diff --git a/README.md b/README.md index c978c9765e..c9bda57e4e 100644 --- a/README.md +++ b/README.md @@ -120,9 +120,120 @@ function App() { } ``` -## Theming +## Styling and Customization -Set `--rdg-color-scheme: light/dark` at the `:root` to control the color theme. The light or dark themes can be enforced using the `rdg-light` or `rdg-dark` classes. +The DataGrid provides multiple ways to customize its appearance and behavior. + +### Light/Dark Themes + +The DataGrid supports both light and dark color schemes out of the box using CSS's `light-dark()` function. The theme automatically adapts based on the user's system preference when `color-scheme: light dark;` is set. + +To enforce a specific theme, we recommend setting the standard `color-scheme` CSS property on the `:root`: + +```css +:root { + color-scheme: light; /* or 'dark', or 'light dark' for auto */ +} +``` + +Alternatively, you can add the `rdg-light` or `rdg-dark` class to individual grids: + +```tsx +// Force light theme + + +// Force dark theme + +``` + +### CSS Variables + +The DataGrid supports the following CSS variables for customization: + +```css +.rdg { + /* Selection */ + --rdg-selection-width: 2px; + --rdg-selection-color: hsl(207, 75%, 66%); + + /* Typography */ + --rdg-font-size: 14px; + + /* Colors (using light-dark() for automatic theme switching) */ + --rdg-color: light-dark(#000, #ddd); + --rdg-background-color: light-dark(hsl(0deg 0% 100%), hsl(0deg 0% 13%)); + + /* Header */ + --rdg-header-background-color: light-dark(hsl(0deg 0% 97.5%), hsl(0deg 0% 10.5%)); + --rdg-header-draggable-background-color: light-dark(hsl(0deg 0% 90.5%), hsl(0deg 0% 17.5%)); + + /* Rows */ + --rdg-row-hover-background-color: light-dark(hsl(0deg 0% 96%), hsl(0deg 0% 9%)); + --rdg-row-selected-background-color: light-dark(hsl(207deg 76% 92%), hsl(207deg 76% 42%)); + --rdg-row-selected-hover-background-color: light-dark(hsl(207deg 76% 88%), hsl(207deg 76% 38%)); + + /* Borders */ + --rdg-border-width: 1px; + --rdg-border-color: light-dark(#ddd, #444); + --rdg-summary-border-width: calc(var(--rdg-border-width) * 2); + --rdg-summary-border-color: light-dark(#aaa, #555); + + /* Frozen columns */ + --rdg-cell-frozen-box-shadow: 2px 0 5px -2px rgba(136, 136, 136, 0.3); + + /* Checkboxes */ + --rdg-checkbox-focus-color: hsl(207deg 100% 69%); +} +``` + +Example of customizing colors: + +```css +.my-custom-grid { + --rdg-background-color: #f0f0f0; + --rdg-selection-color: #ff6b6b; + --rdg-font-size: 16px; +} +``` + +```tsx + +``` + +### Standard Props + +The DataGrid accepts standard [`className`](#classname-string--undefined) and [`style`](#style-cssproperties--undefined) props: + +```tsx + +``` + +### Row and Cell Styling + +#### Row Heights + +Control row heights using the [`rowHeight`](#rowheight-maybenumber--row-r--number), [`headerRowHeight`](#headerrowheight-maybenumber), and [`summaryRowHeight`](#summaryrowheight-maybenumber) props. The `rowHeight` prop supports both fixed heights and dynamic heights per row. + +#### Row Classes + +Apply custom CSS classes to rows using the [`rowClass`](#rowclass-mayberow-r-rowidx-number--maybestring) prop, and to header rows using the [`headerRowClass`](#headerrowclass-maybestring) prop. + +#### Cell Classes + +Apply custom CSS classes to cells using the [`cellClass`](#cellclass-maybestring--row-trow--maybestring) property in column definitions. You can also use [`headerCellClass`](#headercellclass-maybestring) and [`summaryCellClass`](#summarycellclass-maybestring--row-tsummaryrow--maybestring) for header and summary cells respectively. + +#### Column Widths + +Control column widths using the [`width`](#width-maybenumber--string), [`minWidth`](#minwidth-maybenumber), and [`maxWidth`](#maxwidth-maybenumber) properties in column definitions. Enable column resizing using the [`resizable`](#resizable-maybeboolean) property, or use [`defaultColumnOptions`](#defaultcolumnoptions-maybedefaultcolumnoptionsr-sr) to apply it to all columns. + +### Custom Renderers + +Replace default components with custom implementations using the [`renderers`](#renderers-mayberenderersr-sr) prop. Columns can also have custom renderers using the [`renderCell`](#rendercell-maybeprops-rendercellpropstrow-tsummaryrow--reactnode), [`renderHeaderCell`](#renderheadercell-maybeprops-renderheadercellpropstrow-tsummaryrow--reactnode), [`renderSummaryCell`](#rendersummarycell-maybeprops-rendersummarycellpropstsummaryrow-trow--reactnode), [`renderGroupCell`](#rendergroupcell-maybeprops-rendergroupcellpropstrow-tsummaryrow--reactnode), and [`renderEditCell`](#rendereditcell-maybeprops-rendereditcellpropstrow-tsummaryrow--reactnode) properties. ## API Reference @@ -214,6 +325,18 @@ function MyGrid() { Height of each row in pixels. A function can be used to set different row heights. +```tsx +// Fixed height for all rows + + +// Dynamic height per row + row.isExpanded ? 100 : 35} +/> +``` + :warning: **Performance:** When using a function, the height of all rows is calculated upfront on every render. For large datasets (1000+ rows), this can cause performance issues. Consider using a fixed height when possible, or memoize the `rowHeight` function. ###### `headerRowHeight?: Maybe` @@ -228,6 +351,17 @@ Height of the header row in pixels. Height of each summary row in pixels. +```tsx + +``` + ###### `columnWidths?: Maybe` A map of column widths containing both measured and resized widths. If not provided then an internal state is used. @@ -508,7 +642,40 @@ interface Renderers { } ``` -For example, the default `` component can be wrapped via the `renderRow` prop to add contexts or tweak props +Example of replacing default components: + +```tsx +import { DataGrid, type Renderers } from 'react-data-grid'; + +const customRenderers: Renderers = { + // Custom row render function + renderRow(key, props) { + return ; + }, + + // Custom cell render function + renderCell(key, props) { + return ; + }, + + // Custom checkbox render function + renderCheckbox(props) { + return ; + }, + + // Custom sort status indicator + renderSortStatus(props) { + return ; + }, + + // Custom empty state + noRowsFallback:
No data available
+}; + +; +``` + +The default `` component can be wrapped via the `renderRow` prop to add contexts or tweak props: ```tsx import { DataGrid, RenderRowProps, Row } from 'react-data-grid'; @@ -533,13 +700,13 @@ Function to apply custom class names to rows. ```tsx import { DataGrid } from 'react-data-grid'; -function MyGrid() { - return ; -} - function rowClass(row: Row, rowIdx: number) { return rowIdx % 2 === 0 ? 'even' : 'odd'; } + +function MyGrid() { + return ; +} ``` :warning: **Performance:** Define this function outside your component or memoize it with `useCallback` to avoid re-rendering all rows on every render. @@ -548,6 +715,10 @@ function rowClass(row: Row, rowIdx: number) { Custom class name for the header row. +```tsx + +``` + ###### `direction?: Maybe<'ltr' | 'rtl'>` This property sets the text direction of the grid, it defaults to `'ltr'` (left-to-right). Setting `direction` to `'rtl'` has the following effects: @@ -1036,6 +1207,31 @@ A unique key to distinguish each column Width can be any valid css grid column value. If not specified, it will be determined automatically based on grid width and specified widths of other columns. +```tsx +const columns: Column[] = [ + { + key: 'id', + name: 'ID', + width: 80, // Fixed width in pixels + resizable: false + }, + { + key: 'name', + name: 'Name', + width: '30%', // Percentage width + minWidth: 100, + maxWidth: 400 + }, + { + key: 'description', + name: 'Description' + // No width specified - automatically sized + } +]; +``` + +Other examples: + ```tsx width: 80, // pixels width: '25%', @@ -1059,6 +1255,36 @@ Maximum column width in pixels. Class name(s) for cells. Can be a string or a function that returns a class name based on the row. +```tsx +const columns: Column[] = [ + { + key: 'status', + name: 'Status', + cellClass: (row) => `status-${row.status}` + }, + { + key: 'price', + name: 'Price', + cellClass: 'text-right' // Static class + } +]; +``` + +```css +.status-active { + color: green; + font-weight: bold; +} + +.status-inactive { + color: grey; +} + +.text-right { + text-align: right; +} +``` + ##### `headerCellClass?: Maybe` Class name(s) for the header cell. diff --git a/package.json b/package.json index 897d4dee87..001802952d 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "typecheck": "tsc --build" }, "devDependencies": { - "@biomejs/biome": "2.3.8", + "@biomejs/biome": "2.3.10", "@eslint-react/eslint-plugin": "^2.3.12", "@eslint/markdown": "^7.5.1", "@faker-js/faker": "^10.0.0", @@ -82,7 +82,7 @@ "react": "^19.2.1", "react-dom": "^19.2.1", "rolldown": "^1.0.0-beta.51", - "rolldown-plugin-dts": "^0.18.0", + "rolldown-plugin-dts": "^0.19.1", "typescript": "~5.9.2", "vite": "npm:rolldown-vite@^7.2.5", "vitest": "^4.0.15", diff --git a/src/style/core.ts b/src/style/core.ts index 142d4b1a4e..a2bbf2022b 100644 --- a/src/style/core.ts +++ b/src/style/core.ts @@ -31,15 +31,13 @@ const root = css` --rdg-checkbox-focus-color: hsl(207deg 100% 69%); &.rdg-dark { - --rdg-color-scheme: dark; + color-scheme: dark; } &.rdg-light { - --rdg-color-scheme: light; + color-scheme: light; } - color-scheme: var(--rdg-color-scheme, light dark); - &:dir(rtl) { --rdg-cell-frozen-box-shadow: -2px 0 5px -2px rgba(136, 136, 136, 0.3); } diff --git a/website/root.css b/website/root.css index 5e21fcd71d..8b0e42b892 100644 --- a/website/root.css +++ b/website/root.css @@ -6,17 +6,18 @@ body { } :root { + color-scheme: light dark; + &:has([value='light']:checked) { - --rdg-color-scheme: light; + color-scheme: light; } &:has([value='dark']:checked) { - --rdg-color-scheme: dark; + color-scheme: dark; } } body { - color-scheme: var(--rdg-color-scheme, light dark); background-color: light-dark(#fff, hsl(0deg 0% 10%)); color: light-dark(#111, #fff); }