Tables
The Table component is an all inclusive and accessible table based on correct HTML semantics.
Please use the properties instead of overwriting the styles. And if you miss a feature, get in touch with us.
NB: If you have more than three (3) columns, please consider to use border
property in order to enhance accessibility.
Accessibility
Tables do both serve as a way of navigation for screen readers and other assertive technologies. But they also help to give data an ordered structure.
Use the documentation from MDN – The Table element for more information on making semantic correct tables, including scope
, align
, colSpan
and rowSpan
.
Here is a list of things you may follow along in order to ensure your coded tables still are accessible:
- Keep a semantic correct structure.
- Let tables align the column width, when possible.
- Do not use CSS
display
property on any table element. - Do not overwrite styles in general, but rather get in touch with DNB UX.
- Never put a table inside a table.
- Text inside tables do not need to be wrapped inside a paragraph as well. They give screen readers no additional useful information.
Table header components
<Th.SortButton />
to be used for additional sorting functionality.<Th.HelpButton />
to be used for help related content.
Alignment
Use e.g. align="right"
on a <Th>
, <Td>
or <Tr>
to align a table header or a table data element.
Fixed layout
You may consider using table-layout: fixed;
. You can use the modifier property fixed
for doing so and combine it with CSS e.g. width: 40%
on specific table headers.
Scrollable
Depending on your situation, you may want to wrap your Table within Table.ScrollView
:
import { Table } from '@dnb/eufemia'render(<Table.ScrollView><Table /></Table.ScrollView>,)
Sticky header
You have two options (both have their downsides):
-
use
sticky={true}
. It works even when using aTable.ScrollView
or aoverflow: hidden;
is used on any parent elements. And it works inside a Drawer as well. The downside is, that it uses JavaScript and the browser may drop some frames, which results in a potential flickering during scrolling. -
use
sticky="css-position"
for using the CSSposition: sticky;
method. It is super smooth. But then you can not use aoverflow: hidden;
oroverflow: auto;
on any parent elements. This is a know issue happening on every modern browser.
Method no. 2 should be used when a max-height
is set to the wrapping Table.ScrollView
e.g.:
<Table.ScrollView style={{ maxHeight: '20rem' }}><Table sticky="css-position" /></Table.ScrollView>
Have a look at this example.
Sortable table
Optionally, make use of the following React Hook to handle the Th.SortButton
directions.
It can be used as a "controller" for your own sorting logic of your data.
By default, it will cycle trough three stages ['asc', 'desc', 'off']
.
Show how to use the useHandleSortState React Hook.
import useHandleSortState from '@dnb/eufemia/components/table/useHandleSortState'// You can also provide a default that will be used as the fallback e.g.const defaultOptions = { direction: 'asc', modes: ['asc', 'desc', 'off'] }export const YourComponent = () => {const { sortState, sortHandler, activeSortName } = useHandleSortState({// Define your column names with options (optional)column1: { active: true }, //column2: { direction: 'desc', modes: ['asc', 'desc'] }, // overwrite the defaultOptionscolumn3: { modes: ['asc', 'off'] }, // will only allow one directioncolumn4: {}, // etc.},defaultOptions,)// Use these properties for your custom sorting logicconsole.log(sortState.column1.direction) // returns either "asc", "desc" or "off"console.log(activeSortName) // returns the current active one: "column1" (returns null when nothing is active)// Handle your logicuseEffect(() => {switch (sortState.column1.direction) {default:case 'asc':setYourLocalState(mockData.sort(compareFunctionAsc))breakcase 'desc':setYourLocalState(mockData.sort(compareFunctionsDesc))breakcase 'off':setYourLocalState(mockData)break}}, [sortState.column1.direction])return (<Table><thead><Tr><Thsortableactive={sortState.column1.active}reversed={sortState.column1.reversed}><Th.SortButtontext="Column 1"title="Sort this column"on_click={sortHandler.column1}/></Th></Tr></thead></Table>)}
Demos
Basic table
NB: In this example, the sort buttons do react on your input. But will not change the table data.
Column | Help Button | ||
---|---|---|---|
Row 1 | Row 1 | Row 1 | Row 1 |
Row 2 | Row 2 | Row 2 | Row 2 |
Row 3 with paragraph | Row 3 with code | Row 3 with medium paragraph | Row 3 with medium text |
const BasicTable = () => { const { sortState, sortHandler } = useHandleSortState({ column1: { direction: 'asc', active: true, }, column2: { direction: 'desc', modes: ['asc', 'desc'], }, }) // Handle your "column1" logic React.useEffect(() => { switch (sortState.column1.direction) { case 'asc': break case 'desc': break default: case 'off': break } }, [sortState.column1.direction]) return ( <Table.ScrollView> <Table> <caption className="dnb-sr-only">A Table Caption</caption> <thead> <Tr> <Th>Column</Th> <Th> <Th.Horizontal> Help Button <Th.HelpButton>Help Content</Th.HelpButton> </Th.Horizontal> </Th> <Th sortable active={sortState.column1.active} reversed={sortState.column1.reversed} > <Th.SortButton text="Sortable Active" title="Sort table column" on_click={sortHandler.column1} /> </Th> <Th sortable active={sortState.column2.active} reversed={sortState.column2.reversed} align="right" > <Th.SortButton text="Sortable" title="Sort table column" on_click={sortHandler.column2} /> </Th> </Tr> </thead> <tbody> <Tr> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> <Td align="right">Row 1</Td> </Tr> <Tr> <Td>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> <Td align="right">Row 2</Td> </Tr> <Tr> <Td> <P>Row 3 with paragraph</P> </Td> <Td> Row 3 with <Code>code</Code> </Td> <Td> <P> Row 3 with <b>medium paragraph</b> </P> </Td> <Td align="right"> Row 3 with <b>medium text</b> </Td> </Tr> </tbody> </Table> </Table.ScrollView> ) } render(<BasicTable />)
Complex table
You can force a row to overwrite the automated odd/even counting by providing e.g. variant="even"
to a <Tr />
. You can use this in combination with rowSpan
.
NB: The table header in the first column needs to have scope="row"
!
Column 2 newline | Column 3 that spans | ||
---|---|---|---|
Row 1+2 Header | Row 1 that spans | Row 1 | Row 1 |
Row 2 | Row 2 | ||
Row 3 Header newline | Row 3 | noSpacing + align="right" | |
Row 4 Header | Row 4 | Row 4 |
<Table.ScrollView> <Table border outline> <caption>A Table Caption</caption> <thead> <Tr noWrap> <Th /> <Th> Column 2<br /> newline </Th> <Th colSpan={2}>Column 3 that spans</Th> </Tr> </thead> <tbody> <Tr variant="even"> <Th scope="rowgroup" rowSpan={2}> Row 1+2 Header </Th> <Td rowSpan={2}>Row 1 that spans</Td> <Td>Row 1</Td> <Td>Row 1</Td> </Tr> <Tr variant="even"> <Td>Row 2</Td> <Td>Row 2</Td> </Tr> <Tr> <Th scope="row"> Row 3 Header <br /> newline </Th> <Td>Row 3</Td> <Td spacing="horizontal"> <Button variant="secondary">Button</Button> </Td> <Td noSpacing align="right"> <Code>noSpacing + align="right"</Code> </Td> </Tr> <Tr> <Th scope="row">Row 4 Header</Th> <Td>Row 4</Td> <Td colSpan={2}>Row 4</Td> </Tr> </tbody> </Table> </Table.ScrollView>
Row scope headers only
This table has only scope="row"
and scope="rowgroup"
headers – without the default scope="col"
.
Header A | Row 1 | Row 1 |
---|---|---|
Header B | Row 2 | Row 2 |
<Table.ScrollView> <Table outline border> <caption>A Table Caption</caption> <tbody> <Tr> <Th scope="row">Header A</Th> <Td>Row 1</Td> <Td>Row 1</Td> </Tr> <Tr> <Th>Header B</Th> <Td>Row 2</Td> <Td>Row 2</Td> </Tr> </tbody> </Table> </Table.ScrollView>
Fixed table
Column 1 | Column 2 | Column 3 | Column 4 | Column 5 | Column 6 | Column 7 | Column 8 |
---|---|---|---|---|---|---|---|
Row 1 | Row 1 | Row 1 | Row 1 | Row 1 | Row 1 | Row 1 | Row 1 |
Row 2 | Row 2 | Row 2 | Row 2 | Row 2 | Row 2 | Row 2 | Row 2 |
Row 3 | Row 3 | Row 3 | Row 3 | Row 3 | Row 3 | Row 3 | Row 3 |
Row 4 | Row 4 | Row 4 | Row 4 | Row 4 | Row 4 | Row 4 | Row 4 |
const FixedTable = styled(Table)` min-width: 70rem; /* Define the width of the THs so they are aligned across tables */ thead { th:nth-of-type(1) { width: 30%; } th:nth-of-type(2) { width: 20%; } th:nth-of-type(3) { width: 10%; } th:nth-of-type(4) { width: 10%; } th:nth-of-type(5) { width: 5%; } th:nth-of-type(6) { width: 5%; } th:nth-of-type(7) { width: 5%; } th:nth-of-type(8) { width: 5%; } } ` render( <Table.ScrollView> <FixedTable fixed> <caption className="dnb-sr-only">A Table Caption</caption> <thead> <Tr noWrap> <Th>Column 1</Th> <Th>Column 2</Th> <Th>Column 3</Th> <Th>Column 4</Th> <Th>Column 5</Th> <Th>Column 6</Th> <Th>Column 7</Th> <Th align="right">Column 8</Th> </Tr> </thead> <tbody> <Tr> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> <Td align="right">Row 1</Td> </Tr> <Tr> <Td>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> <Td align="right">Row 2</Td> </Tr> <Tr> <Td>Row 3</Td> <Td>Row 3</Td> <Td>Row 3</Td> <Td>Row 3</Td> <Td>Row 3</Td> <Td>Row 3</Td> <Td>Row 3</Td> <Td align="right">Row 3</Td> </Tr> <Tr> <Td>Row 4</Td> <Td>Row 4</Td> <Td>Row 4</Td> <Td>Row 4</Td> <Td>Row 4</Td> <Td>Row 4</Td> <Td>Row 4</Td> <Td align="right">Row 4</Td> </Tr> </tbody> </FixedTable> </Table.ScrollView>, )
Medium and small sized
Column | Column | |
---|---|---|
Row 1 | Row 1 | Row 1 |
Row 2 with paragraph | Row 2 with medium paragraph | Row 2 with medium text |
<Table.ScrollView> <Table size="medium"> <caption className="dnb-sr-only">A Table Caption</caption> <thead> <Tr> <Th>Column</Th> <Th sortable> <Th.SortButton text="Sortable" title="Sort table column" /> </Th> <Th align="right">Column</Th> </Tr> </thead> <tbody> <Tr> <Td>Row 1</Td> <Td>Row 1</Td> <Td align="right">Row 1</Td> </Tr> <Tr> <Td> <P>Row 2 with paragraph</P> </Td> <Td> <P> Row 2 with <b>medium paragraph</b> </P> </Td> <Td align="right"> Row 2 with <b>medium text</b> </Td> </Tr> </tbody> </Table> </Table.ScrollView>
A small
sized table is only for special circumstances, where a lot of data needs to be shown on the screen at the same time.
Column | Column | |
---|---|---|
Row 1 | Row 1 | Row 1 |
Row 2 with paragraph | Row 2 with medium paragraph | Row 2 with medium text |
<Table.ScrollView> <Table size="small"> <caption className="dnb-sr-only">A Table Caption</caption> <thead> <Tr> <Th>Column</Th> <Th sortable> <Th.SortButton text="Sortable" title="Sort table column" /> </Th> <Th align="right">Column</Th> </Tr> </thead> <tbody> <Tr> <Td>Row 1</Td> <Td>Row 1</Td> <Td align="right">Row 1</Td> </Tr> <Tr> <Td> <P>Row 2 with paragraph</P> </Td> <Td> <P> Row 2 with <b>medium paragraph</b> </P> </Td> <Td align="right"> Row 2 with <b>medium text</b> </Td> </Tr> </tbody> </Table> </Table.ScrollView>
Table with accordion rows
This example is not yet fully supported using the Sbanken theme.
The second example uses both a border
and an outline
.
Column A | Column B | Column C | Column D | |
---|---|---|---|---|
Row 1 | Row 1 | |||
Row 2 | Row 2 | |||
Row 3 | Row 3 |
Column A | Column B | Column C | Column D | |
---|---|---|---|---|
Row 1 | Row 1 | Row 1 | ||
Row 2 | Row 2 | Row 2 | ||
Row 3 | Row 3 | Row 3 |
const AccordionTable = ({ id, showCheckbox = false, ...props }) => { const TdCheckbox = () => { return <Checkbox label="Select row" label_sr_only /> } const TdInput = () => { return <Input label="Label" label_sr_only size={4} /> } const Content = ({ shareId }) => { const ref = React.useRef() const { copy } = useCopyWithNotice() const shareHandler = () => { const url = new URL(location.href) url.hash = '#' + shareId copy(url.toString(), ref.current) } return ( <> <Button top icon="bell" variant="secondary"> Ring the bell </Button> <Section top spacing> <Dl> <Dt>Favorittfarge</Dt> <Dd>Grønn</Dd> <Dt>Favorittmat</Dt> <Dd>Taco</Dd> </Dl> </Section> <Button top variant="tertiary" icon={copyIcon} icon_position="left" on_click={shareHandler} inner_ref={ref} > Copy link to this row </Button> </> ) } const Row = ({ nr }) => { const shareId = id + '-' + nr return ( <Tr id={shareId}> <Td>{showCheckbox ? <TdCheckbox /> : 'Row ' + nr}</Td> <Td>Row {nr}</Td> <Td spacing="horizontal"> <TdInput /> </Td> <Td align="right">Row {nr}</Td> <Td.AccordionContent> <Content shareId={shareId} /> </Td.AccordionContent> </Tr> ) } return ( <Table accordion id={id} {...props}> <caption className="dnb-sr-only">A Table Caption</caption> <thead> <Tr> <Th>Column A</Th> <Th>Column B</Th> <Th>Column C</Th> <Th align="right">Column D</Th> </Tr> </thead> <tbody> <Row nr="1" /> <Row nr="2" /> <Row nr="3" /> </tbody> </Table> ) } render( <> <Table.ScrollView> <AccordionTable id="table-1" showCheckbox accordionChevronPlacement="end" /> </Table.ScrollView> <Table.ScrollView top> <AccordionTable id="table-2" border outline size="medium" /> </Table.ScrollView> </>, )
Table with sticky header
Header | |||
---|---|---|---|
Row 1 with p | Row 1 with code | Row 1 with span | Row 1 |
Column which spans over two columns | Row 2 | Row 2 | |
Row 3 | Row 3 | Row 3 | Row 3 |
Footer | Sum |
<Table.ScrollView> <Table sticky={isVisibleWhenVisualTest ? 'css-position' : true} stickyOffset={isFullscreen ? 0 : '3.5rem'} > <caption className="dnb-sr-only">A Table Caption</caption> <thead> <Tr> <Th colSpan={2}>Header</Th> <Th sortable reversed> <Th.SortButton text="Sortable" title="Sort table column" /> </Th> <Th sortable active> <Th.SortButton text="Active" title="Sort table column" /> </Th> </Tr> </thead> <tbody> <Tr> <Td> <P> Row 1 <b>with p</b> </P> </Td> <Td> <Code>Row 1 with code</Code> </Td> <Td> <span>Row 1 with span</span> </Td> <Td>Row 1</Td> </Tr> <Tr> <Td colSpan={2}>Column which spans over two columns</Td> <Td>Row 2</Td> <Td>Row 2</Td> </Tr> <Tr> <Td>Row 3</Td> <Td>Row 3</Td> <Td>Row 3</Td> <Td>Row 3</Td> </Tr> </tbody> <tfoot> <Tr> <Td colSpan={3}>Footer</Td> <Td>Sum</Td> </Tr> </tfoot> </Table> </Table.ScrollView>
Table with a max height
A sticky table header with sticky="css-position"
and max-height
on the Table.ScrollView
.
Column 1 | Column 2 | Column 3 | Column 4 |
---|---|---|---|
Row 1 | Row 1 | Row 1 | Row 1 |
Row 2 | Row 2 | Row 2 | Row 2 |
Row 3 | Row 3 | Row 3 | Row 3 |
Row 4 | Row 4 | Row 4 | Row 4 |
Row 5 | Row 5 | Row 5 | Row 5 |
Row 6 | Row 6 | Row 6 | Row 6 |
Row 7 | Row 7 | Row 7 | Row 7 |
Row 8 | Row 8 | Row 8 | Row 8 |
Row 9 | Row 9 | Row 9 | Row 9 |
Row 10 | Row 10 | Row 10 | Row 10 |
Row 11 | Row 11 | Row 11 | Row 11 |
Row 12 | Row 12 | Row 12 | Row 12 |
<Table.ScrollView style={{ maxHeight: '18rem', }} > <Table sticky="css-position"> <thead> <Tr> <Th>Column 1</Th> <Th>Column 2</Th> <Th>Column 3</Th> <Th>Column 4</Th> </Tr> </thead> <tbody> <Tr> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> </Tr> <Tr> <Td>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> </Tr> <Tr> <Td>Row 3</Td> <Td>Row 3</Td> <Td>Row 3</Td> <Td>Row 3</Td> </Tr> <Tr> <Td>Row 4</Td> <Td>Row 4</Td> <Td>Row 4</Td> <Td>Row 4</Td> </Tr> <Tr> <Td>Row 5</Td> <Td>Row 5</Td> <Td>Row 5</Td> <Td>Row 5</Td> </Tr> <Tr> <Td>Row 6</Td> <Td>Row 6</Td> <Td>Row 6</Td> <Td>Row 6</Td> </Tr> <Tr> <Td>Row 7</Td> <Td>Row 7</Td> <Td>Row 7</Td> <Td>Row 7</Td> </Tr> <Tr> <Td>Row 8</Td> <Td>Row 8</Td> <Td>Row 8</Td> <Td>Row 8</Td> </Tr> <Tr> <Td>Row 9</Td> <Td>Row 9</Td> <Td>Row 9</Td> <Td>Row 9</Td> </Tr> <Tr> <Td>Row 10</Td> <Td>Row 10</Td> <Td>Row 10</Td> <Td>Row 10</Td> </Tr> <Tr> <Td>Row 11</Td> <Td>Row 11</Td> <Td>Row 11</Td> <Td>Row 11</Td> </Tr> <Tr> <Td>Row 12</Td> <Td>Row 12</Td> <Td>Row 12</Td> <Td>Row 12</Td> </Tr> </tbody> </Table> </Table.ScrollView>
Several tables in one container
Show how the import and syntax is structured.
<TableContainer> <TableContainer.Head> <H2>Heading</H2> </TableContainer.Head> <TableContainer.Body> <Table>{'hei'}</Table> <Table>{'hei'}</Table> </TableContainer.Body> <TableContainer.Foot> <P>Footer</P> </TableContainer.Foot> </TableContainer>
Header
Text
I have a superscript 1 | Column 2 | Column 3 | Column 4 |
---|---|---|---|
Row 1 | Row 1 | Row 1 | Row 1 |
Row 2 | Row 2 | Row 2 | Row 2 |
Column 1 | Column 2 | Column 3 | Column 4 |
---|---|---|---|
Row 1 | Row 1 | Row 1 | Row 1 |
Row 2 | Row 2 | Row 2 | |
Row 3 | Row 3 | Row 3 |
Row Header Group | Row 1 | Row 1 |
---|---|---|
Row 2 | Row 2 |
Footer
const StyledContainer = styled(TableContainer)` /* Define the width of the THs so they are aligned across tables. A "fixed" table width is needed in order to align all tables to act with the same column widths. */ &, .dnb-table__scroll-view { max-width: 70rem; } .dnb-table__container__body { min-width: 800px; } table { th:nth-of-type(1), td:nth-of-type(1) { width: 30%; } th:nth-of-type(2) { width: 30%; } th:nth-of-type(3) { width: 20%; } th:nth-of-type(4) { width: 20%; } } ` render( <StyledContainer aria-label="I contain two tables" bottom="large"> <TableContainer.Head> <H2>Header</H2> <P top>Text</P> </TableContainer.Head> <TableContainer.Body> <Table fixed border sticky stickyOffset={isFullscreen ? 0 : '3.5rem'} > <caption className="dnb-sr-only">Table One</caption> <thead> <Tr noWrap> <Th> I have a superscript{' '} <sup> <Anchor href="#unique-ref-id">1</Anchor> </sup> </Th> <Th>Column 2</Th> <Th>Column 3</Th> <Th>Column 4</Th> </Tr> </thead> <tbody> <Tr> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> </Tr> <Tr> <Td>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> </Tr> </tbody> </Table> <Table fixed border sticky stickyOffset={isFullscreen ? 0 : '3.5rem'} > <caption className="dnb-sr-only">Table Two</caption> <thead> <Tr noWrap> <Th>Column 1</Th> <Th>Column 2</Th> <Th>Column 3</Th> <Th>Column 4</Th> </Tr> </thead> <tbody> <Tr> <Td rowSpan={2}>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> </Tr> <Tr> <Td rowSpan={2}>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> </Tr> <Tr> <Td>Row 3</Td> <Td>Row 3</Td> <Td>Row 3</Td> </Tr> </tbody> </Table> <Table fixed border> <tbody> <Tr> <Th scope="rowgroup" rowSpan={2}> Row Header Group </Th> <Td>Row 1</Td> <Td>Row 1</Td> </Tr> <Tr> <Td>Row 2</Td> <Td>Row 2</Td> </Tr> </tbody> </Table> </TableContainer.Body> <TableContainer.Foot> <P id="unique-ref-id">Footer</P> </TableContainer.Foot> </StyledContainer>, )
With no (empty) head
and foot
content.
Column 1 | Column 2 | Column 3 | Column 4 |
---|---|---|---|
Row 1 | Row 1 | Row 1 | Row 1 |
Row 2 | Row 2 | Row 2 | Row 2 |
render( <TableContainer bottom="large"> <TableContainer.Body> <Table border> <thead> <Tr> <Th>Column 1</Th> <Th>Column 2</Th> <Th>Column 3</Th> <Th>Column 4</Th> </Tr> </thead> <tbody> <Tr> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> <Td>Row 1</Td> </Tr> <Tr> <Td>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> <Td>Row 2</Td> </Tr> </tbody> </Table> </TableContainer.Body> </TableContainer>, )
Table with long header text (wrapping)
Static long header senectus ornare convallis ut at erat imperdiet commodo | |||
---|---|---|---|
col span of 4 |
<Table.ScrollView> <Table> <caption className="dnb-sr-only">A Table Caption</caption> <thead> <Tr> <Th colSpan={2}> Static long header senectus ornare convallis ut at erat imperdiet commodo </Th> <Th sortable reversed> <Th.SortButton text="Sortable long header ridiculus laoreet turpis netus at vitae" title="Sort table column" /> </Th> <Th align="right" sortable active> <Th.SortButton text="Active and right aligned long header ridiculus laoreet turpis netus at vitae" title="Sort table column" /> </Th> </Tr> </thead> <tbody> <Tr> <Td colSpan={4}> <P>col span of 4</P> </Td> </Tr> </tbody> </Table> </Table.ScrollView>
Table with pagination
This example is not yet fully supported using the Sbanken theme.
const TablePagination = () => { const amountPerPage = 5 const [currentPage, setCurrentPage] = React.useState(1) const [data] = React.useState(() => getDataFromAPI(0, 100)) return ( <Pagination page_count={data.length / amountPerPage} current_page={currentPage} on_change={({ pageNumber }) => { setCurrentPage(pageNumber) }} > <MakeTable currentPage={currentPage} amountPerPage={amountPerPage} data={data} /> </Pagination> ) function getDataFromAPI(offset, max) { const list = [] for (let i = offset + 1, l = offset + max; i <= l; i++) { list.push({ name: 'Row ' + i, }) } return list } function MakeTable({ currentPage, amountPerPage, data }) { const offset = currentPage * amountPerPage - amountPerPage const tableBody = data .slice(offset, offset + amountPerPage) .map(({ name }, i) => { return ( <Tr key={i}> <Td>{name}</Td> </Tr> ) }) return ( <Table.ScrollView> <Table> <thead> <Tr> <Th>Column</Th> </Tr> </thead> <tbody>{tableBody}</tbody> </Table> </Table.ScrollView> ) } } render(<TablePagination />)
Example usage without and with classes
Header | ||
---|---|---|
Row 1 | Row 1 | Row 1 |
Row 2 | Row 2 | Row 2 |
Row 3 | Row 3 | Row 3 |
<Table.ScrollView> <table className="dnb-table"> <thead> <tr> <th>Header</th> <th className="dnb-table--sortable dnb-table--reversed"> <Th.SortButton text="Sortable" /> </th> <th className="dnb-table--sortable dnb-table--active"> <Th.SortButton text="Active" /> </th> </tr> </thead> <tbody> <tr> <td>Row 1</td> <td>Row 1</td> <td>Row 1</td> </tr> <tr> <td>Row 2</td> <td>Row 2</td> <td>Row 2</td> </tr> <tr> <td>Row 3</td> <td>Row 3</td> <td>Row 3</td> </tr> </tbody> </table> </Table.ScrollView>
.dnb-table__th | ||
---|---|---|
.dnb-table__tr--even > .dnb-table__td | ||
.dnb-table__tr--odd > .dnb-table__td |
<Table.ScrollView> <table className="dnb-table"> <thead> <tr className="dnb-table__tr"> <th className="dnb-table__th">.dnb-table__th</th> <th className="dnb-table__th dnb-table--sortable dnb-table--reversed"> <Th.SortButton text="dnb-table--reversed" title="dnb-table__th dnb-table--sortable dnb-table--reversed" /> </th> <th className="dnb-table__th dnb-table--sortable dnb-table--active"> <Th.SortButton text="dnb-table--active" title="dnb-table__th dnb-table--sortable dnb-table--active" /> </th> </tr> </thead> <tbody> <tr className="dnb-table__tr dnb-table__tr--even"> <td colSpan={3} className="dnb-table__td"> .dnb-table__tr--even{' > '}.dnb-table__td </td> </tr> <tr className="dnb-table__tr dnb-table__tr--odd"> <td colSpan={3} className="dnb-table__td"> .dnb-table__tr--odd{' > '}.dnb-table__td </td> </tr> </tbody> </table> </Table.ScrollView>