Custom data types and cell renderers
If the built-in column types aren't enough for your use case, you can provide a custom React component for your cells, headers, footers, or filter inputs.
Custom Cell Component
To render custom JSX in a table cell, define a columnCell component in your column configuration. It receives the cellContext (from @tanstack/react-table) and the current cell value.
Result
Loading...
Live Editor
// import { DataTable } from 'koval-ui'; // Example custom cell renderer function CustomBadgeCell({ value }) { return ( <div style={{padding: 6}}> <div style={{ background: value === 'manager' ? '#e3f2fd' : '#f0f4c3', color: value === 'manager' ? '#1565c0' : '#827717', padding: '6px 12px', borderRadius: '4px', fontWeight: 'bold', textTransform: 'uppercase', fontSize: '0.8rem', }}> {value} </div> </div> ); } function CustomCellExample() { const data = React.useMemo(() => generateData(5, 777), []); const columns = React.useMemo<Column[]>(() => [ { id: 'firstName', name: 'First Name', accessorKey: 'firstName' }, { id: 'lastName', name: 'Last Name', accessorKey: 'lastName' }, { id: 'role', name: 'Role', accessorKey: 'role', columnCell: CustomBadgeCell // Providing the custom component } ], []); return ( <DataTable tableData={data} columns={columns} tableHeight={333} /> ); } render( <CustomCellExample /> );
Advanced Cell Overrides
Similarly, you can override how the column header, column footer, and the filter input render.
import type {Column} from 'koval-ui';
import {Select} from 'koval-ui';
const customColumns: Column[] = [
{
id: 'status',
name: 'Status',
accessorKey: 'status',
headerCell: ({title}) => <strong>{title} 🚀</strong>,
filterInput: ({value, onChange}) => (
<Select value={value as string} onChange={e => onChange(e.target.value)}>
<option value="">All</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
</Select>
),
},
];
Localized Country & Flag with Custom Filter
Here is a more comprehensive example that demonstrates how to render a localized country name using the Koval UI NameRegion alongside the Flag component. We also override the column's filter input to render a Select instead of the default text input.
Result
Loading...
Live Editor
// import { DataTable, Flag, Select, NameRegion } from 'koval-ui'; // Custom cell to render a flag and localized country name function CountryCell({value, cellContext}) { // Get table locale from context const locale = cellContext.table.options.meta.locale; return ( <div style={{display: 'flex', alignItems: 'center', gap: '8px', padding: 6}}> <Flag countryCode={value} size={24} /> <span> <NameRegion countryCode={value} locale={locale} /> </span> </div> ); } // Custom filter using a native select for demonstration function CountryFilter({value, onChange}) { return ( <FormField label="Select country:"> <Select value={value} onChange={e => onChange(e.target.value)}> <option value="">All</option> <option value="US">United States</option> <option value="GB">United Kingdom</option> <option value="CA">Canada</option> <option value="FR">France</option> <option value="DE">Germany</option> <option value="JP">Japan</option> </Select> </FormField> ); } const tableData = [ {id: 1, name: 'Alice Smith', country: 'US'}, {id: 2, name: 'Bob Jones', country: 'GB'}, {id: 3, name: 'Charlie Brown', country: 'FR'}, {id: 4, name: 'Diana Prince', country: 'DE'}, {id: 5, name: 'Evan Wright', country: 'JP'}, {id: 6, name: 'Fiona Gallagher', country: 'CA'}, ]; const tableColumns = [ { id: 'name', name: 'Name', accessorKey: 'name', }, { id: 'country', name: 'Country', accessorKey: 'country', columnCell: CountryCell, filterInput: CountryFilter, size: 222, }, ]; function AdvancedCustomCellExample() { const [locale, setLocale] = useState('zgh-Tfng-MA'); return ( <div style={{display: 'flex', flexDirection: 'column', gap: 18}}> <Select value={locale} onChange={e => setLocale(e.target.value)}> <option value="en-US">Enlish/US</option> <option value="de-DE">German</option> <option value="ja-JP">Japan</option> <option value="ka-GE">Georgian</option> <option value="uk-UA">Ukrainian</option> <option value="zgh-Tfng-MA">Tamazight</option> </Select> <DataTable locale={locale} tableData={tableData} columns={tableColumns} tableHeight={366} enableFilters={true} /> </div> ); } render(<AdvancedCustomCellExample />);