# Table Displays data in rows and columns. ## Import ```tsx import { Table } from '@coinbase/cds-web/tables/Table' ``` ## Examples CDS Data Tables allow product teams to place their content in an organized display of rows and columns enabling them to group their data by different classifications so their product users can make comparisons, glean insights and make informed decisions. Display of content in rows and columns allows data to be organized for further analysis, allowing large amounts of raw data to be sorted and reorganized in a neat format, and allows the inclusion of only the most important or relevant data. ### Principles A defining element of CDS Data Tables is the ability to "manipulate" the data view. This defining attribute is represented in the table header row; the first row of a table. The table header row not only labels the columns with a descriptive title but it also provides functionality to re-organize or re-configure what is being displayed in the corresponding cols. A Data Table requires a header row. However it is not required that a header row have actions (sorting, filtering, etc.) ### When to use Use Data Tables when you want to: - Organize data that is too detailed or complicated to be described adequately in the text - Show many numerical values and other specific data in a small space - Compare and contrast data values with several shared characteristics or variables - Organize the order of content Data Tables can contain: - Static/Read-only content (text/strings, labels, etc) - Interactive elements (input fields, buttons, etc) - Actions to query and/or manipulate data (sorting, filtering, etc) ### Cross-Platform Data Tables are intended for and built for desktop screens. When displaying complex data sets on mobile devices we recommend using CDS Lists View. ### Complicated tables Sometimes you need to use a more complicated layout to fit your data. That's okay, but please be aware more complex tables come with... [more complexity](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table#complicated_tables) 🤯 ### Accessibility :::tip Accessibility tip Tables should have an accessible label for people using assistive technologies. The preferred and most semantic method is to add a TableCaption as the first child of your Table component (see code examples below). However, if you need more flexibility or your design does not include a caption or title, you can set a label using the `accessibilityLabelledBy` or `accessibilityLabel` props. ::: ### Table Variants The Table component supports three variants: `default`, `graph`, and `ruled`. ```tsx live Default variant - Simple and clean
Graph variant - With grid lines
Ruled variant - With horizontal lines
``` ### Basic usage with Layout Control ```tsx live function Example() { const totalResults = accounts.length; const PAGE_SIZE = 7; const [page, setPage] = useState(1); const [isFixed, setIsFixed] = useState(false); const startIdx = (page - 1) * PAGE_SIZE; const endIdx = Math.min(startIdx + PAGE_SIZE, totalResults); const slicedAccounts = accounts.slice(startIdx, endIdx); return ( setIsFixed((isFixed) => !isFixed)} checked={isFixed}> Fixed Layout Example {slicedAccounts.map((account) => { return ( } title={account.name} subtitle={account.currency.name} /> ); })} {[1, 2, 3, 4, 5].map((pg) => ( ))}
); } ``` ### Cell Spacing and Compact Mode ```tsx live function TableCellCompactExample() { const MOCK_DATA = Object.entries(assets).slice(0, 20); const mediaTypes = ['Text', 'Asset', 'Image', 'Avatar']; const [isCompact, setIsCompact] = useState(true); return ( setIsCompact((isCompact) => !isCompact)} checked={isCompact}> Compact Compact Example {mediaTypes.map((label) => ( ))} {MOCK_DATA.map((row) => ( {mediaTypes.map((mediaType) => ( ) } /> ))} ))}
); } ``` ### Height-Constrained Table with Sticky Header ```tsx live Sticky Header Example {Array.from({ length: 6 }).map((_, i) => ( ))}
``` ### Complex Table Structure with Row/Column Spans ```tsx live Complex Table Example
``` ### Sortable Table ```tsx live function SortingExample() { const [{ sortBy, sortDirection }, setSort] = useState({ sortBy: 'name', sortDirection: 'ascending', }); const onChange = (key) => { const isAscending = key === sortBy && sortDirection === 'ascending'; const ascendingOrDescending = isAscending ? 'descending' : 'ascending'; setSort({ sortBy: key, sortDirection: ascendingOrDescending }); }; const data = useSort({ data: accounts, sortDirection, sortBy }); const getSortableProps = useSortableCell({ sortBy, sortDirection, onChange }); return ( Sorting Example {data.map((account) => { return ( } title={account.name} subtitle={account.currency.name} /> ); })}
); } ``` ## Props | Prop | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `bordered` | `boolean` | No | `-` | When set, a border will be applied around the entire table | | `cellSpacing` | `TableCellSpacing` | No | `-` | Provide custom cell spacing for all child TableCells | | `compact` | `boolean` | No | `-` | Use compact cell spacing. If set, cellSpacing will override these defaults | | `height` | `string \| number` | No | `-` | Set a fixed height. | | `key` | `Key \| null` | No | `-` | - | | `maxHeight` | `string \| number` | No | `-` | Set a maximum height. | | `onChange` | `FormEventHandler` | No | `-` | - | | `ref` | `((instance: HTMLTableElement \| null) => void) \| RefObject \| null` | No | `-` | - | | `tableLayout` | `fixed \| auto` | No | `'auto'` | Use tableLayout=fixed if you need full control over cell width | | `testID` | `string` | No | `-` | Used to locate this element in unit and end-to-end tests. Under the hood, testID translates to data-testid on Web. On Mobile, testID stays the same - testID | | `variant` | `default \| graph \| ruled` | No | `undefined` | The variant prop allows clients to use a CDS approved style for their Table. |