Themes & Color Mode
react-data-table-component ships with a set of built-in structural themes and a flexible theming system built
on CSS custom properties. Pick a named theme with the theme prop, brand any
theme with createTheme(), and let colorMode handle light/dark
automatically.
Built-in themes
Select a theme and color mode. Structural themes define density, spacing, and shape. colorMode controls light/dark.
import DataTable from 'react-data-table-component';
<DataTable columns={columns} data={data} />
<DataTable columns={columns} data={data} theme="material" />
<DataTable columns={columns} data={data} theme="crisp" colorMode="dark" />
<DataTable columns={columns} data={data} theme="catppuccin" colorMode="system" /> Structural themes
Structural themes define density, spacing, typography, and shape. They ship
with a neutral palette that adapts to light and dark mode via colorMode. Brand
them with createTheme() to add your own accent color:
// Apply Material Design layout with your own brand color
createTheme('material-violet', { primary: '#6200EE' }, 'material');
<DataTable columns={columns} data={data} theme="material-violet" /> | Name | Density | Shape | Separator defaults |
|---|---|---|---|
default | 48 px rows, 16 px padding | 4 px radius | Header separator on, no column separators |
material | 52 px rows, 16 px padding | 4 px radius | No header or column separators (Material uses row dividers only) |
rounded | 48 px rows, 18 px padding | 8 px radius, circular checkboxes | Subtle header separator |
catppuccin | 48 px rows, 16 px padding | 6 px radius | Subtle header separator, Catppuccin Latte (light) / Mocha (dark) |
crisp | 42 px rows, 16 px padding | 4 px radius | Subtle header separator (AG Grid Quartz) |
All themes include a darkMode block and respond correctly to
colorMode="system" or colorMode="dark".
colorMode
The colorMode prop controls whether DataTable applies the active theme's
darkMode overrides.
| Value | Behavior |
|---|---|
"light" | Always render in light mode regardless of OS preference or page class. |
"dark" | Always render in dark mode, applying the theme's darkMode overrides. |
"system" (default) |
Follow the page automatically. DataTable checks, in order:
MutationObserver and a
storage event listener, so DataTable updates when the user toggles the
page theme without needing a re-render from outside.
|
// Always dark — ignores OS preference
<DataTable columns={columns} data={data} theme="material" colorMode="dark" />
// Follow OS / page toggle (default, explicit)
<DataTable columns={columns} data={data} theme="crisp" colorMode="system" />
// Force light even when the page is in dark mode
<DataTable columns={columns} data={data} theme="rounded" colorMode="light" /> createTheme()
createTheme() accepts two call signatures:
import { createTheme } from 'react-data-table-component';
// 1. Named — register globally, reference by string in the theme prop
createTheme('my-brand', { primary: '#6200EE' }, 'material');
// 2. Inline — compose and pass the object directly to the theme prop
const inlineTheme = createTheme({ primary: '#e91e63' }, 'crisp');
<DataTable theme={inlineTheme} columns={columns} data={data} /> Theme shape
All keys are optional. Unspecified fields inherit from the base theme. For
darkMode, supply only the fields that differ from light mode; they are merged on
top of the light values at render time.
import { createTheme } from 'react-data-table-component';
createTheme('violet', {
primary: '#6200EE',
text: {
primary: '#1a1a2e',
secondary: '#4a4a6a',
disabled: '#9e9e9e',
},
background: {
default: '#f5f0ff',
header: '#ede7f6', // distinct header background
},
divider: { default: '#d1c4e9' },
selected: { default: '#ede7f6', text: '#1a1a2e' },
highlightOnHover: { default: '#ede7f6', text: '#1a1a2e' },
striped: { default: '#f3eeff', text: '#1a1a2e' },
button: {
default: '#6200EE',
focus: 'rgba(98,0,238,0.12)',
hover: 'rgba(98,0,238,0.08)',
disabled: '#d1c4e9',
},
context: { background: '#6200EE', text: '#ffffff' },
// Dark-mode overrides — only what changes
darkMode: {
primary: '#BB86FC',
text: { primary: '#e0e0e0', secondary: '#b0b0b0' },
background: { default: '#1a0533', header: '#240844' },
divider: { default: '#3d1f6e' },
selected: { default: '#2d1060', text: '#e0e0e0' },
highlightOnHover: { default: '#2d1060', text: '#e0e0e0' },
striped: { default: '#1e0a40', text: '#e0e0e0' },
},
// Structural
spacing: { rowHeight: '48px', headerHeight: '56px', cellPaddingX: '16px' },
typography: { fontSize: '14px', fontSizeHeader: '12px' },
shape: { borderRadius: '8px' },
}); Icons
Sort chevron, row expander, and pagination arrows can all be replaced. There are two ways: bake them into a theme so every table using it gets them automatically, or pass them as per-table props for a one-off override. Props win when both are set.
Override via props
Pass icons directly on a single table. Only the icons you supply are replaced. The rest fall back to the theme or built-in defaults.
import { ChevronUp, ChevronDown, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from 'lucide-react';
// Sort icon — replaces the chevron shown in sortable column headers
<DataTable
sortIcon={<ChevronUp size={14} />}
columns={columns}
data={data}
/>
// Expander icons — collapsed / expanded state
<DataTable
expandableRows
expandableIcon={{
collapsed: <ChevronDown size={16} />,
expanded: <ChevronUp size={16} />,
}}
columns={columns}
data={data}
/>
// Pagination icons — any subset; omitted keys fall back to defaults
<DataTable
pagination
paginationIcons={{
previous: <ChevronLeft size={16} />,
next: <ChevronRight size={16} />,
first: <ChevronsLeft size={16} />,
last: <ChevronsRight size={16} />,
}}
columns={columns}
data={data}
/> Override via theme
Declare icons inside a theme so every table using it shares the same iconography without repeating props. Per-table props override the theme when explicitly passed.
import { createTheme } from 'react-data-table-component';
import { ChevronUp, ChevronDown, ChevronLeft, ChevronRight } from 'lucide-react';
createTheme('icon-theme', {
icons: {
sort: <ChevronUp size={14} />,
expandable: {
collapsed: <ChevronDown size={16} />,
// expanded: omitted — falls back to the built-in default
},
pagination: {
next: <ChevronRight size={16} />,
previous: <ChevronLeft size={16} />,
// first/last: omitted — fall back to defaults
},
},
});
<DataTable columns={columns} data={data} theme="icon-theme" /> Custom checkbox component
Replace the built-in checkbox with your own component via selectableRowsComponent.
Extra props can be forwarded through selectableRowsComponentProps.
The component receives standard HTMLInputElement props and a ref.
DataTable sets el.indeterminate directly on the ref to handle the partial-selection state.
import Checkbox from '@mui/material/Checkbox';
<DataTable
selectableRows
selectableRowsComponent={Checkbox}
selectableRowsComponentProps={{ color: 'primary' }}
/>
If you build your own checkbox, use React.forwardRef and forward the ref to the
underlying <input> element so DataTable can set indeterminate
natively:
import React from 'react';
const MyCheckbox = React.forwardRef<
HTMLInputElement,
React.InputHTMLAttributes<HTMLInputElement>
>((props, ref) => (
<input
{...props}
ref={ref}
style={{ accentColor: 'teal', width: 18, height: 18 }}
/>
));
MyCheckbox.displayName = 'MyCheckbox';
<DataTable
selectableRows
selectableRowsComponent={MyCheckbox}
/> Header & column separators in themes
The headerSeparator and columnSeparator props can be baked into a
theme so every table using it shares the same separator style. The per-table prop always
takes precedence when explicitly passed.
createTheme('grid', {
primary: '#1976d2',
headerSeparator: 'full', // bold line below header row
columnSeparator: 'full', // full-height lines between columns
}, 'default');
// Override for one specific table
<DataTable theme="grid" columnSeparator={false} /> Column separators
Toggle between no separators, subtle inset lines, and full-height lines.
// No body separators (default)
<DataTable columns={columns} data={data} />
// Subtle body separators (60%-height inset)
<DataTable columns={columns} data={data} columnSeparator />
// Full-height body separators
<DataTable columns={columns} data={data} columnSeparator="full" />
// Remove the default header separator
<DataTable columns={columns} data={data} headerSeparator={false} /> CSS variable override
Every theme compiles to CSS custom properties scoped to DataTable's wrapper element.
Override any variable with a wrapper class. No createTheme() needed for
small tweaks.
.my-table {
--rdt-color-text-primary: #1a1a2e;
--rdt-color-bg: #f0f4ff;
--rdt-color-header-bg: #e8edff; /* separate header background */
--rdt-color-divider: #c7d2fe;
--rdt-color-highlight: #e0e7ff;
--rdt-color-selected: #ede9fe;
--rdt-border-radius: 8px;
--rdt-font-size: 13px;
} CSS variable reference
| Variable | Default | What it controls |
|---|---|---|
--rdt-color-scheme | light | CSS color-scheme: affects native checkbox, select, and scrollbar rendering |
--rdt-color-primary | #1976d2 | Checkbox accent, active sort icon, selection ring |
--rdt-color-text-primary | rgba(0,0,0,.87) | Primary text in rows and header cells |
--rdt-color-text-secondary | rgba(0,0,0,.54) | Muted text: group labels, pagination count |
--rdt-color-text-disabled | rgba(0,0,0,.38) | Disabled row text |
--rdt-color-bg | #fff | Table and row background |
--rdt-color-header-bg | falls back to --rdt-color-bg | Header row background: set only when the theme or CSS provides it |
--rdt-color-divider | rgba(0,0,0,.12) | Row borders and separator lines |
--rdt-color-context-bg | #e3f2fd | Selected-rows context bar background |
--rdt-color-context-text | rgba(0,0,0,.87) | Selected-rows context bar text |
--rdt-color-selected | #e3f2fd | Selected row background |
--rdt-color-selected-text | rgba(0,0,0,.87) | Selected row text |
--rdt-color-highlight | #eee | Hover highlight background |
--rdt-color-highlight-text | rgba(0,0,0,.87) | Hover highlight text |
--rdt-color-striped | #fafafa | Striped (even) row background |
--rdt-color-striped-text | rgba(0,0,0,.87) | Striped row text |
--rdt-color-btn | rgba(0,0,0,.54) | Sort icon, expander chevron, pagination button icons |
--rdt-color-btn-hover | rgba(0,0,0,.08) | Pagination button hover background |
--rdt-color-btn-focus | rgba(0,0,0,.12) | Pagination button focus ring |
--rdt-color-btn-disabled | rgba(0,0,0,.18) | Disabled pagination button icon |
--rdt-row-height | 52px | Body row min-height |
--rdt-header-height | 56px | Header row min-height |
--rdt-cell-padding-x | 16px | Horizontal padding inside every cell |
--rdt-font-size | 13px | Body cell font size |
--rdt-font-size-header | 12px | Header cell font size |
--rdt-font-family | inherits | Font family for all table text |
--rdt-border-radius | 4px | Pill radius on selection badges and other rounded elements |
Prop reference
| Prop | Type | Default | Description |
|---|---|---|---|
theme | string | Theme | Record<string, string> | "default" |
Named built-in theme, a Theme object from createTheme(overrides, inherit),
or a raw CSS variable map ({ '--rdt-color-bg': '#000', ... }).
|
colorMode | "light" | "dark" | "system" | "system" |
Controls when the theme's darkMode overrides are applied.
"system" follows localStorage, the html.dark class, then prefers-color-scheme.
|
selectableRowsComponent | React.ComponentType<InputHTMLAttributes> | "input" | "input" |
Custom checkbox component. Must accept standard input props and forward its ref to an
<input> element so DataTable can set indeterminate.
|
selectableRowsComponentProps | Record<string, unknown> | - | Extra props forwarded to every instance of the custom checkbox component. |
headerSeparator | boolean | "full" | theme default or true |
Line below the header row. true = subtle inset line.
"full" = full-height divider. false = none.
Overrides the theme's headerSeparator setting.
|
columnSeparator | boolean | "full" | theme default or false |
Vertical lines between body row cells. true = subtle inset.
"full" = full-height. false = none.
Overrides the theme's columnSeparator setting.
|
customStyles | TableStyles | - | Fine-grained style overrides per slot (rows, cells, header, pagination, etc.). Applied on top of the active theme. See the Custom Styles page. |