DataTable
The DataTable component simplifies the creation of tabular data. It uses CSS flex for layout and does not rely on native tables.
Simple usage example
To create a table, provide columns with titles using <DataTable.Column name={name}/>
and data with data={data}
.
TIP
<DataTable.Column/>
must be a child component of <DataTable.Head/>
import React from 'react';
import DataTable from 'intergalactic/data-table';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Scroll in table
<DataTable/>
, <DataTable.Head/>
, and <DataTable.Body/>
are inherited from the Box component and accept all its parameters. <DataTable/>
serves as a container for <DataTable.Head/>
and <DataTable.Body/>
where scrolling is implemented.
TIP
If horizontal scrolling is not visible, try reducing the window size
By default, scrolling is displayed at the bottom of the table, but it can also be added to the table header. Scroll in the table header is useful for very long tables with fixed columns, allowing users to scroll more conveniently without reaching the end. For examples, refer to the Fixed header section.
import React from 'react';
import DataTable from 'intergalactic/data-table';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head wMin={1000}>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body hMax={200} />
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Customizing header
You can insert tooltips, selectors, and other components into the table header using the children
property.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import Tooltip from 'intergalactic/tooltip';
import { Text } from 'intergalactic/typography';
import DropdownMenu from 'intergalactic/dropdown-menu';
import { LinkTrigger } from 'intergalactic/base-trigger';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column
name='keyword'
tag={Tooltip}
title="Jesus Christ, Joe, fucking forget about it. I'm Mr. Pink. Let's move on."
tabIndex={0}
>
<Text noWrap>
Keyword <Text color='text-secondary'>(1 - 100)</Text>
</Text>
</DataTable.Column>
<DataTable.Column name='kd'>
<DropdownMenu>
<DropdownMenu.Trigger>
<LinkTrigger color='text-primary' style={{ fontSize: '12px' }}>
KD,%
</LinkTrigger>
</DropdownMenu.Trigger>
<DropdownMenu.Menu>
<DropdownMenu.Item>Options 1</DropdownMenu.Item>
<DropdownMenu.Item>Options 2</DropdownMenu.Item>
</DropdownMenu.Menu>
</DropdownMenu>
</DataTable.Column>
<DataTable.Column
name='cpc'
tag={Tooltip}
title="Jesus Christ, Joe, fucking forget about it. I'm Mr. Pink. Let's move on."
tabIndex={0}
>
CPC
</DataTable.Column>
<DataTable.Column
name='vol'
tag={Tooltip}
title="Jesus Christ, Joe, fucking forget about it. I'm Mr. Pink. Let's move on."
tabIndex={0}
>
Vol.
</DataTable.Column>
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Column sizes
Columns are inherited from the Flex
component and accept its parameters, such as flex
, wMin
, and wMax
, to adjust the column width.
import React from 'react';
import DataTable from 'intergalactic/data-table';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' wMin={100} flex='1 0 auto' />
<DataTable.Column name='kd' children='KD,%' flex='0' wMin={100} />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Column alignment
Columns and cells inherit properties from the Flex
component, so you can use justifyContent
and alignItems
to align columns and cells. Table cells automatically inherit the same properties as the column.
import React from 'react';
import DataTable from 'intergalactic/data-table';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' justifyContent='flex-end' />
<DataTable.Column name='cpc' children='CPC' justifyContent='flex-end' />
<DataTable.Column name='vol' children='Vol.' justifyContent='flex-end' />
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Sorting
To enable column sorting:
- Set the
sortable
property on the column. - Subscribe to the
onSortChange
event. - Pass the
sort
property to the table. - Sort the data provided in the
data
property.
import React from 'react';
import DataTable, { DataTableSort } from 'intergalactic/data-table';
type SortableColumn = Exclude<keyof typeof data[0], 'keyword'>;
const Demo = () => {
const [sort, setSort] = React.useState<DataTableSort<keyof typeof data[0]>>(['kd', 'desc']);
const sortedData = React.useMemo(
() =>
[...data].sort((aRow, bRow) => {
const [prop, sortDirection] = sort;
const a = aRow[prop as SortableColumn];
const b = bRow[prop as SortableColumn];
if (a === b) return 0;
if (sortDirection === 'asc') return a - b;
else return b - a;
}),
[sort],
);
const numberFormat = React.useMemo(() => new Intl.NumberFormat('en-US'), []);
const currencyFormat = React.useMemo(
() => new Intl.NumberFormat('en-US', { currency: 'USD', style: 'currency' }),
[],
);
return (
<DataTable data={sortedData} sort={sort} onSortChange={setSort}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' justifyContent='left' sortable />
<DataTable.Column name='kd' children='KD,%' justifyContent='right' wMax={68} sortable />
<DataTable.Column name='cpc' children='CPC' wMax={60} sortable />
<DataTable.Column name='vol' children='Vol.' wMax={120} justifyContent='left' sortable />
</DataTable.Head>
<DataTable.Body>
<DataTable.Cell data={data} name='kd'>
{(_, row) => ({
children: row.kd === -1 ? 'n/a' : numberFormat.format(row.kd),
})}
</DataTable.Cell>
<DataTable.Cell data={data} name='cpc'>
{(_, row) => ({
children: row.cpc === -1 ? 'n/a' : currencyFormat.format(row.cpc),
})}
</DataTable.Cell>
<DataTable.Cell data={data} name='vol'>
{(_, row) => ({
children: row.vol === -1 ? 'n/a' : numberFormat.format(row.vol),
})}
</DataTable.Cell>
</DataTable.Body>
</DataTable>
);
};
export default Demo;
const data = [
{
keyword: 'ebay buy',
kd: 77.8,
cpc: 1.25,
vol: 32500000,
},
{
keyword: 'www.ebay.com',
kd: 11.2,
cpc: 3.4,
vol: 65457920,
},
{
keyword: 'www.ebay.com',
kd: 10,
cpc: 0.65,
vol: 47354640,
},
{
keyword: 'ebay buy',
kd: -1,
cpc: 0,
vol: -1,
},
{
keyword: 'ebay buy',
kd: 75.89,
cpc: 0,
vol: 21644290,
},
];
Change width for sorting column
If some column has changeSortSize={true}
, by default, it will be increased by the largest column if the computed width less than content width
+ sorting icon width
.
import React from 'react';
import DataTable, { DataTableSort } from 'intergalactic/data-table';
type SortableColumn = Exclude<keyof typeof data[0], 'keyword'>;
const Demo = () => {
const [sort, setSort] = React.useState<DataTableSort<keyof typeof data[0]>>(['kd', 'desc']);
const sortedData = React.useMemo(
() =>
[...data].sort((aRow, bRow) => {
const [prop, sortDirection] = sort;
const a = aRow[prop as SortableColumn];
const b = bRow[prop as SortableColumn];
if (a === b) return 0;
if (sortDirection === 'asc') return a - b;
else return b - a;
}),
[sort],
);
const numberFormat = React.useMemo(() => new Intl.NumberFormat('en-US'), []);
const currencyFormat = React.useMemo(
() => new Intl.NumberFormat('en-US', { currency: 'USD', style: 'currency' }),
[],
);
return (
<DataTable data={sortedData} sort={sort} onSortChange={setSort}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' justifyContent='left' sortable />
<DataTable.Column name='kd' children='KD,%' justifyContent='right' wMax={68} sortable />
<DataTable.Column name='cpc' children='CPC' wMax={60} sortable changeSortSize />
<DataTable.Column name='vol' children='Vol.' wMax={120} justifyContent='left' sortable />
</DataTable.Head>
<DataTable.Body>
<DataTable.Cell data={data} name='kd'>
{(_, row) => ({
children: row.kd === -1 ? 'n/a' : numberFormat.format(row.kd),
})}
</DataTable.Cell>
<DataTable.Cell data={data} name='cpc'>
{(_, row) => ({
children: row.cpc === -1 ? 'n/a' : currencyFormat.format(row.cpc),
})}
</DataTable.Cell>
<DataTable.Cell data={data} name='vol'>
{(_, row) => ({
children: row.vol === -1 ? 'n/a' : numberFormat.format(row.vol),
})}
</DataTable.Cell>
</DataTable.Body>
</DataTable>
);
};
export default Demo;
const data = [
{
keyword: 'ebay buy',
kd: 77.8,
cpc: 1.25,
vol: 32500000,
},
{
keyword: 'www.ebay.com',
kd: 11.2,
cpc: 3.4,
vol: 65457920,
},
{
keyword: 'www.ebay.com',
kd: 10,
cpc: 0.65,
vol: 47354640,
},
{
keyword: 'ebay buy',
kd: -1,
cpc: 0,
vol: -1,
},
{
keyword: 'ebay buy',
kd: 75.89,
cpc: 0,
vol: 21644290,
},
];
Change width for sorting column by specific columns
You could set sortSizeRecalculation={true}
for using this column as column to recalculation width (after increase to sorting column). The needed width will be divided equally between all such columns.
import React from 'react';
import DataTable, { DataTableSort } from 'intergalactic/data-table';
type SortableColumn = Exclude<keyof typeof data[0], 'keyword'>;
const Demo = () => {
const [sort, setSort] = React.useState<DataTableSort<keyof typeof data[0]>>(['kd', 'desc']);
const sortedData = React.useMemo(
() =>
[...data].sort((aRow, bRow) => {
const [prop, sortDirection] = sort;
const a = aRow[prop as SortableColumn];
const b = bRow[prop as SortableColumn];
if (a === b) return 0;
if (sortDirection === 'asc') return a - b;
else return b - a;
}),
[sort],
);
const numberFormat = React.useMemo(() => new Intl.NumberFormat('en-US'), []);
const currencyFormat = React.useMemo(
() => new Intl.NumberFormat('en-US', { currency: 'USD', style: 'currency' }),
[],
);
return (
<DataTable data={sortedData} sort={sort} onSortChange={setSort}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' justifyContent='left' sortable />
<DataTable.Column name='kd' children='KD,%' justifyContent='right' wMax={68} sortable />
<DataTable.Column name='cpc' children='CPC' wMax={60} sortable changeSortSize />
<DataTable.Column
name='vol'
children='Vol.'
justifyContent='left'
sortable
wMax={120}
sortSizeRecalculation
/>
</DataTable.Head>
<DataTable.Body>
<DataTable.Cell data={data} name='kd'>
{(_, row) => ({
children: row.kd === -1 ? 'n/a' : numberFormat.format(row.kd),
})}
</DataTable.Cell>
<DataTable.Cell data={data} name='cpc'>
{(_, row) => ({
children: row.cpc === -1 ? 'n/a' : currencyFormat.format(row.cpc),
})}
</DataTable.Cell>
<DataTable.Cell data={data} name='vol'>
{(_, row) => ({
children: row.vol === -1 ? 'n/a' : numberFormat.format(row.vol),
})}
</DataTable.Cell>
</DataTable.Body>
</DataTable>
);
};
export default Demo;
const data = [
{
keyword: 'ebay buy',
kd: 77.8,
cpc: 1.25,
vol: 32500000,
},
{
keyword: 'www.ebay.com',
kd: 11.2,
cpc: 3.4,
vol: 65457920,
},
{
keyword: 'www.ebay.com',
kd: 10,
cpc: 0.65,
vol: 47354640,
},
{
keyword: 'ebay buy',
kd: -1,
cpc: 0,
vol: -1,
},
{
keyword: 'ebay buy',
kd: 75.89,
cpc: 0,
vol: 21644290,
},
];
Fixed header
Use the <Box position="sticky" top={top} />
to fix the table header.
TIP
Set zIndex=2
for correct display.
Scroll in the table header is useful for very long tables with fixed columns, allowing users to scroll more conveniently without reaching the end. In such cases, scroll can be added to the header and the bottom of the table.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import { Box } from 'intergalactic/flex-box';
const Demo = () => {
const top = 0; // Here should be height of Header in your application
return (
<>
<DataTable data={data}>
<Box position='sticky' top={top} zIndex={2}>
<DataTable.Head wMin={1000}>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
</Box>
<DataTable.Body />
</DataTable>
<h3>with Scroll.Bar in Header</h3>
<DataTable data={data}>
<Box position='sticky' top={top} zIndex={2}>
<DataTable.Head wMin={1000} withScrollBar>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
</Box>
<DataTable.Body />
</DataTable>
</>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Fixed header with table loading state
For correct components overlapping, use the SpinContainer
component with SpinContainer.Overlay
but without SpinContainer.Content
.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import SpinContainer from 'intergalactic/spin-container';
import { Box } from 'intergalactic/flex-box';
const Demo = () => {
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
const timer = setInterval(() => {
setLoading(!loading);
}, 1500);
return () => {
clearInterval(timer);
};
}, [loading]);
return (
<DataTable data={data}>
<Box position='sticky' top={0} zIndex={2}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
</Box>
<SpinContainer loading={loading} style={{ overflow: 'initial' }}>
<DataTable.Body />
<SpinContainer.Overlay />
</SpinContainer>
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Fixed columns
To fix table columns, use the fixed
property with <DataTable.Column/>
.
TIP
If fixed columns are not visible in the example below, try reducing the window size.
import React from 'react';
import DataTable from 'intergalactic/data-table';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head wMin={1000}>
<DataTable.Column name='keyword' children='Keyword' fixed='left' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' fixed='right' />
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Multi-level header
Create a multi-level header by nesting columns within each other.
TIP
name
property is not applicable for group columns.
import React from 'react';
import DataTable from 'intergalactic/data-table';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column vBorders wMax={'40%'}>
Organic Sessions
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Column>
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Additional elements in header
Components added to <DataTable.Head/>
will be inserted at the end of the header.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import ProgressBar from 'intergalactic/progress-bar';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
<ProgressBar value={40} size='s' style={{ borderRadius: 0 }}>
<ProgressBar.Value style={{ borderRadius: 0 }} />
</ProgressBar>
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Header separation
Move the table header outside of the table using a portal. All functionality will work, and the table body will adjust to the header's size.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import Divider from 'intergalactic/divider';
import Portal, { PortalProvider } from 'intergalactic/portal';
const Demo = () => {
const portalRef = React.useRef(null);
return (
<>
<div style={{ border: '1px solid' }} ref={portalRef} />
<Divider my={5} />
<DataTable style={{ border: '1px solid' }} data={data}>
<PortalProvider value={portalRef}>
<Portal>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
</Portal>
</PortalProvider>
<DataTable.Body />
</DataTable>
</>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Access to rows
To apply properties to a table row, use <DataTable.Row/>
. You can use multiple <DataTable.Row/>
to separate the business logic.
TIP
<DataTable.Row/>
must be a direct child component of <DataTable.Body/>
. Do not wrap it in higher-order components, and using styled components (for example, styled(DataTable. Row)
...
) is not allowed.
You can provide data
property for <DataTable.Row/>
. It is not used in the component runtime but improves strict typings.
import React from 'react';
import DataTable from 'intergalactic/data-table';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body>
<DataTable.Row data={data}>
{(props, row) => {
return {
theme: row['kd'] === '-' ? 'warning' : props.theme,
};
}}
</DataTable.Row>
<DataTable.Row data={data}>
{(props, row, index) => {
return {
style: {
cursor: 'pointer',
},
onClick: () => {
alert(`Click row
props: ${JSON.stringify(Object.keys(props), null, ' ')};
row: ${JSON.stringify(row, null, ' ')};
index: ${index};`);
},
onKeyDown: (event) => {
if (event.key === ' ' || event.key === 'Enter')
alert(`Click row
props: ${JSON.stringify(Object.keys(props), null, ' ')};
row: ${JSON.stringify(row, null, ' ')};
index: ${index};`);
},
};
}}
</DataTable.Row>
</DataTable.Body>
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Access to cells
Define <DataTable.Cell/>
with the appropriate name={name}
to apply properties to a table cell. You can use multiple <DataTable.Cell/>
for different business logic.
<DataTable.Cell/>
must be a direct child component of <DataTable.Body/>
. Do not wrap it in higher-order components, and using styled components ((for example, styled(DataTable. Cell)
...
)) is not allowed.
You can provide data
property for <DataTable.Cell/>
. It is not used in the component runtime but improves strict typings.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import Link from 'intergalactic/link';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body>
<DataTable.Cell data={data} name='keyword'>
{(props, row) => {
return {
children: <Link>{row[props.name]}</Link>,
};
}}
</DataTable.Cell>
<DataTable.Cell data={data} name='keyword'>
{(props, row, index) => {
return {
style: {
cursor: 'pointer',
},
onClick: () => {
alert(`Click row
props: ${JSON.stringify(Object.keys(props), null, ' ')};
row: ${JSON.stringify(row, null, ' ')};
index: ${index};`);
},
onKeyDown: (event) => {
if (event.key === ' ' || event.key === 'Enter')
alert(`Click row
props: ${JSON.stringify(Object.keys(props), null, ' ')};
row: ${JSON.stringify(row, null, ' ')};
index: ${index};`);
},
};
}}
</DataTable.Cell>
</DataTable.Body>
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Access to set of cells
To apply properties to multiple table cells, define <DataTable.Cell />
with their names listed using /
.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import Spin from 'intergalactic/spin';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body>
<DataTable.Cell data={data} name='keyword/kd/cpc/vol'>
{(props, row) => {
return {
children: ['-', '$0', 'n/a'].includes(row[props.name]) ? <Spin /> : props.children,
};
}}
</DataTable.Cell>
</DataTable.Body>
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Adding additional elements to table body
Components added to <DataTable.Body/>
will be inserted at the end of the table body. Use z-index=1
to block fixed columns or z-index=2
to block scrolling if needed.
import React from 'react';
import DataTable from 'intergalactic/data-table';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body>
<div
style={{
position: 'absolute',
width: '100%',
height: 'calc(45px * 2)',
left: 0,
bottom: 0,
background:
'linear-gradient(45deg, rgba(255, 187, 51, 0.3) 25%, rgba(85, 136, 170, 0.3) 0px, rgba(85, 136,' +
' 170, 0.3)' +
' 50%,' +
' rgba(255, 187, 51, 0.3) 0px, rgba(255, 187, 51, 0.3) 75%, rgba(85, 136, 170, 0.3) 0px) 0% 0% / 42px 42px',
zIndex: 2,
}}
/>
</DataTable.Body>
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Custom footer cells
To reuse column sizes, use CSS variables like var(--<%column-name%>_width)
.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import { Box, Flex } from 'intergalactic/flex-box';
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body>
<Flex>
<Box p={3} style={{ width: 'var(--keyword_width)' }}>
Summary
</Box>
<Box p={3} style={{ width: 'var(--kd_width)' }} />
<Box p={3} style={{ width: 'var(--cpc_width)' }}>
{data.reduce((sum, row) => sum + row.cpc, 0)}
</Box>
<Box p={3} style={{ width: 'var(--vol_width)' }}>
{data.reduce((sum, row) => sum + row.vol, 0)}
</Box>
</Flex>
</DataTable.Body>
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: 77.8,
cpc: 125,
vol: 32500000,
},
{
keyword: 'www.ebay.com',
kd: 11.2,
cpc: 3.4,
vol: 65457920,
},
{
keyword: 'www.ebay.com',
kd: 10,
cpc: 0.65,
vol: 47354640,
},
{
keyword: 'ebay buy',
kd: 0,
cpc: 0,
vol: 0,
},
{
keyword: 'ebay buy',
kd: 75.89,
cpc: 0,
vol: 21644290,
},
];
export default Demo;
Accordion inside table
Extend table functionality using the intergalactic/accordion
component. This allows you to add accordions to table rows.
- Wrap the table in the
Accordion
component. - Replace the tag in
DataTable.Row
with our extended tag usingAccordion.Item
. - Define a value for
Accordion.Item
. - Calculate the active line to highlight.
- Render the children as accordion content.
- Add the arrow (
ChevronRight
icon) if needed.
import React from 'react';
import { scaleLinear } from 'd3-scale';
import DataTable from 'intergalactic/data-table';
import Accordion from 'intergalactic/accordion';
import { Flex } from 'intergalactic/flex-box';
import { Plot, Line, XAxis, YAxis, ResponsiveContainer, minMax } from 'intergalactic/d3-chart';
const RowAccordion = React.forwardRef(function (
{ value, collapse = {}, ...props }: any,
ref: React.Ref<HTMLDivElement>,
) {
return (
<Accordion.Item value={value} ref={ref}>
<Accordion.Item.Toggle {...props} />
<Accordion.Item.Collapse {...collapse} />
</Accordion.Item>
);
});
const Demo = () => {
const [exapnded, setExapnded] = React.useState<number[]>([]);
return (
/* [1] Wrapping the table in the Accordion control component; */
<Accordion value={exapnded} onChange={setExapnded}>
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body>
{/* [2] Replacing the tag in DataTable.Row with our extended tag with Accordion.Item */}
<DataTable.Row tag={RowAccordion}>
{(_props, _row, index) => {
return {
/* [3] Setting the value for Accordion.Item; */
value: index,
/* [4] Calculating the active line to highlight it */
active: exapnded.includes(index),
collapse: {
/* [5] Render the children to accordion content; */
children: <ChartExample />,
},
};
}}
</DataTable.Row>
<DataTable.Cell data={data} name='keyword'>
{(props) => {
return {
children: (
<Flex alignItems='center'>
{/* [6] Set the arrow (Chevron icon), if necessary. */}
<Accordion.Item.Chevron color='icon-secondary-neutral' mr={2} />
{props.children}
</Flex>
),
};
}}
</DataTable.Cell>
</DataTable.Body>
</DataTable>
</Accordion>
);
};
const ChartExample = () => {
const [[width, height], setSize] = React.useState([0, 0]);
const MARGIN = 40;
const dataChart = Array(20)
.fill({})
.map((d, i) => ({
x: i,
y: Math.random() * 10,
}));
const xScale = scaleLinear()
.range([MARGIN, width - MARGIN])
.domain(minMax(dataChart, 'x'));
const yScale = scaleLinear()
.range([height - MARGIN, MARGIN])
.domain([0, 10]);
return (
<ResponsiveContainer h={300} onResize={setSize}>
<Plot data={dataChart} scale={[xScale, yScale]} width={width} height={height}>
<YAxis>
<YAxis.Ticks />
<YAxis.Grid />
</YAxis>
<XAxis>
<XAxis.Ticks />
</XAxis>
<Line x='x' y='y'>
<Line.Dots display />
</Line>
</Plot>
</ResponsiveContainer>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Table in table
We use the example with the accordion above.
- Hide the table header.
- Set "inherit" to use the size from the top table for each column.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import Accordion from 'intergalactic/accordion';
import { Flex } from 'intergalactic/flex-box';
const RowAccordion = React.forwardRef(
({ value, collapse = {}, ...props }: any, ref: React.Ref<HTMLDivElement>) => {
return (
<Accordion.Item value={value} ref={ref}>
<Accordion.Item.Toggle {...props} />
<Accordion.Item.Collapse {...collapse} />
</Accordion.Item>
);
},
);
const Demo = () => {
const [value, setValue] = React.useState<number[]>([]);
return (
<Accordion value={value} onChange={setValue}>
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body>
<DataTable.Row tag={RowAccordion}>
{(_props, _row, index) => {
return {
value: index,
active: value.includes(index),
collapse: {
children: (
<DataTable data={data}>
{/* [1] Hide the table header */}
<DataTable.Head hidden>
{/* [2] Set "inherit" to use the size from the top table for each column. */}
<DataTable.Column name='keyword' flex='inherit' />
<DataTable.Column name='kd' flex='inherit' />
<DataTable.Column name='cpc' flex='inherit' />
<DataTable.Column name='vol' flex='inherit' />
</DataTable.Head>
<DataTable.Body />
</DataTable>
),
},
};
}}
</DataTable.Row>
<DataTable.Cell data={data} name='keyword'>
{(props) => {
return {
children: (
<Flex alignItems='center'>
<Accordion.Item.Chevron color='icon-secondary-neutral' mr={2} />
{props.children}
</Flex>
),
};
}}
</DataTable.Cell>
</DataTable.Body>
</DataTable>
</Accordion>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Table in table with fixed column
We use the example with the table above.
- Set the desired
z-index
. - Set the variable to block the scroll.
- Set the variable to remove overflow.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import Accordion from 'intergalactic/accordion';
import { Flex } from 'intergalactic/flex-box';
const RowAccordion = React.forwardRef(
({ value, collapse = {}, ...props }: any, ref: React.Ref<HTMLDivElement>) => {
return (
<Accordion.Item value={value} ref={ref}>
<Accordion.Item.Toggle {...props} />
<Accordion.Item.Collapse {...collapse} />
</Accordion.Item>
);
},
);
const Demo = () => {
const [value, setValue] = React.useState([]);
return (
<Accordion value={value} onChange={setValue}>
<DataTable data={data}>
<DataTable.Head wMin={1000}>
<DataTable.Column name='keyword' children='Keyword' fixed='left' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body>
<DataTable.Row tag={RowAccordion}>
{(_props, _row, index) => {
return {
value: index,
active: value.includes(index),
collapse: {
children: (
<DataTable data={data}>
{/* [1] Set the desired z-index */}
<DataTable.Head hidden z-index={1}>
<DataTable.Column name='keyword' flex='inherit' fixed='left' />
<DataTable.Column name='kd' flex='inherit' />
<DataTable.Column name='cpc' flex='inherit' />
<DataTable.Column name='vol' flex='inherit' />
</DataTable.Head>
{/* [2] Set a variable to block the scroll */}
<DataTable.Body disabledScroll />
</DataTable>
),
},
};
}}
</DataTable.Row>
<DataTable.Cell data={data} name='keyword'>
{(props) => {
return {
children: (
<Flex alignItems='center'>
<Accordion.Item.Chevron color='icon-secondary-neutral' mr={2} />
{props.children}
</Flex>
),
};
}}
</DataTable.Cell>
</DataTable.Body>
</DataTable>
</Accordion>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Virtual scroll in table
Enable scroll virtualization using the virtualScroll
property. Note that built-in virtualization support tables with fixed-height rows only.
import React from 'react';
import DataTable, { ROW_GROUP } from 'intergalactic/data-table';
const keyword = ['ebay buy', 'www.ebay.com', 'ebay buy'];
const kd = ['77.8', '10', '11.2', '-', '75.89'];
const cpc = ['$3.4', '$0.65', '$1.25', '$0', '$0'];
const vol = ['32,500,000', '65,457,920', '47,354,640', 'n/a', '21,644,290'];
const data = Array(10000)
.fill(0)
.map((_, index) => ({
id: `#${index + 1}`,
keyword: keyword[Math.floor(keyword.length * Math.random())],
[ROW_GROUP]: [
{
kd: kd[Math.floor(kd.length * Math.random())],
cpc: cpc[Math.floor(cpc.length * Math.random())],
vol: vol[Math.floor(vol.length * Math.random())],
},
],
}));
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='id' children='ID' />
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column>
Organic Sessions
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Column>
</DataTable.Head>
<DataTable.Body h={400} virtualScroll />
</DataTable>
);
};
export default Demo;
Custom rows rendering
If built-in virtualization does not meet your requirements, you can implement your own virtualization using renderRows
prop.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import { AutoSizer, List, CellMeasurer, CellMeasurerCache } from 'react-virtualized';
const cache = new CellMeasurerCache({
fixedWidth: true,
defaultHeight: 100,
});
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='tags' children='Tags' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body
renderRows={({ rows, renderRow }) => {
const rowRenderer = ({
key,
index,
style,
parent,
}: { key: string; index: number; style: any; parent: any }) => (
<CellMeasurer key={key} cache={cache} parent={parent} columnIndex={0} rowIndex={index}>
{({ measure }: { measure: (event: any) => void }) => (
<div key={key} style={style} onLoad={measure}>
{renderRow(rows[index], { dataIndex: index })}
</div>
)}
</CellMeasurer>
);
return (
<AutoSizer disableHeight>
{({ width }: { width: number }) => (
<List
height={600}
rowCount={rows.length}
deferredMeasurementCache={cache}
rowHeight={cache.rowHeight}
rowRenderer={rowRenderer}
width={width}
overscanRowCount={3}
/>
)}
</AutoSizer>
);
}}
>
<DataTable.Cell name='tags' direction='column' />
</DataTable.Body>
</DataTable>
);
};
const data = Array(100)
.fill(0)
.map((_, i) => ({
keyword: `keyword ${i}`,
tags: Array(Math.floor(Math.random() * 4))
.fill(0)
.map((_, i) => <div key={i}>tag {i + 1}</div>),
cpc: Math.round(Math.random() * 10),
vol: Math.round(Math.random() * 1000000),
}));
export default Demo;
Download status
Replace the tag
property with <DataTable.Body/>
on the SpinContainer
to cover the table with a Spin.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import SpinContainer from 'intergalactic/spin-container';
const Demo = () => {
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
const timer = setInterval(() => {
setLoading(!loading);
}, 1500);
return () => {
clearInterval(timer);
};
}, [loading]);
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<SpinContainer loading={loading} style={{ overflow: 'initial' }}>
<DataTable.Body />
<SpinContainer.Overlay />
</SpinContainer>
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Skeleton in table
Add a skeleton to the table by directly substituting it in the data
or replacing rows
with <DataTable.Body/>
.
import React from 'react';
import DataTable from 'intergalactic/data-table';
import Skeleton from 'intergalactic/skeleton';
function getSkeleton() {
return ['keyword', 'kd', 'cpc', 'vol'].map((c) => ({
cssVar: `--${c}_width`,
name: c,
data: (
<Skeleton height={17}>
<Skeleton.Text y='5' width='60%' />
</Skeleton>
),
}));
}
const Demo = () => {
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
const timer = setInterval(() => {
setLoading(!loading);
}, 2000);
return () => {
clearInterval(timer);
};
}, [loading]);
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body
{...(loading ? { rows: [getSkeleton(), getSkeleton(), getSkeleton()] } : {})}
/>
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
];
export default Demo;
Columns merging
Merge two or more columns by changing the table data and using /
to combine column keys.
import React from 'react';
import DataTable from 'intergalactic/data-table';
const data = [
{
keyword: 'ebay buy',
'kd/cpc/vol': 'This is columns group. This is columns group. This is columns group.',
},
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
export default Demo;
Rows merging
Merge two or more rows by adding a special grouping key to the table data.
import React from 'react';
import DataTable, { ROW_GROUP } from 'intergalactic/data-table';
const data = [
{
keyword: 'ebay buy',
[ROW_GROUP]: [
{
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
],
},
{
keyword: 'www.ebay.com',
[ROW_GROUP]: [
{
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
],
},
];
const Demo = () => {
return (
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
export default Demo;
Secondary table
Use the secondary table for compactly displaying a small amount of data.
import React from 'react';
import DataTable from 'intergalactic/data-table';
const Demo = () => {
return (
<DataTable data={data} use='secondary' sort={['kd', 'desc']}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' sortable />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Export in image
Export the table to an image.
import React from 'react';
import { Flex } from 'intergalactic/flex-box';
import DropdownMenu from 'intergalactic/dropdown-menu';
import Button from 'intergalactic/button';
import FileExportM from 'intergalactic/icon/FileExport/m';
import DataTable from 'intergalactic/data-table';
const extensions = ['png', 'jpeg', 'webp'];
const Demo = () => {
const svgRef = React.useRef<SVGSVGElement>(null);
const width = 500;
const height = 300;
const downloadImage = React.useCallback(
(extention: string) => async () => {
const svgElement = svgRef.current;
let svgText = svgElementToSvgText(svgElement);
svgText = svgText.replace(/(\w+)?:?xlink=/g, 'xmlns:xlink='); // Fix root xlink without namespace
svgText = svgText.replace(/NS\d+:href/g, 'xlink:href'); // Safari NS namespace fix
const downloadUrl = await svgText2DownloadUrl(svgText, 2 * width, 2 * height, extention);
const link = document.createElement('a');
link.href = downloadUrl;
link.download = `image.${extention}`;
link.dispatchEvent(
new MouseEvent('click', {
bubbles: true,
cancelable: true,
view: window,
}),
);
setTimeout(() => {
link.remove();
}, 100);
},
[],
);
return (
<Flex>
<svg ref={svgRef} xmlns='http://www.w3.org/2000/svg' width={width} height={height}>
<foreignObject width='100%' height='100%'>
<DataTable data={data}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body />
</DataTable>
</foreignObject>
</svg>
<DropdownMenu>
<DropdownMenu.Trigger tag={Button} ml={4}>
<Button.Addon>
<FileExportM />
</Button.Addon>
<Button.Text>Export</Button.Text>
</DropdownMenu.Trigger>
<DropdownMenu.Popper wMax='257px'>
<DropdownMenu.List>
{extensions.map((name) => (
<DropdownMenu.Item key={name} onClick={downloadImage(name)}>
{name}
</DropdownMenu.Item>
))}
</DropdownMenu.List>
</DropdownMenu.Popper>
</DropdownMenu>
</Flex>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
const getCSSStyles = (parentElement: Element) => {
const selectorTextArr: string[] = [];
for (let c = 0; c < parentElement.classList.length; c++) {
if (!selectorTextArr.includes(`.${parentElement.classList[c]}`))
selectorTextArr.push(`.${parentElement.classList[c]}`);
}
// Add Children element Ids and Classes to the list
const nodes = parentElement.getElementsByTagName('*');
for (let i = 0; i < nodes.length; i++) {
const id = nodes[i].id;
if (!selectorTextArr.includes(`#${id}`)) selectorTextArr.push(`#${id}`);
const classes = nodes[i].classList;
for (let c = 0; c < classes.length; c++)
if (!selectorTextArr.includes(`.${classes[c]}`)) selectorTextArr.push(`.${classes[c]}`);
}
// Extract CSS Rules
let extractedCSSText = '';
for (let i = 0; i < document.styleSheets.length; i++) {
const s = document.styleSheets[i];
try {
if (!s.cssRules) continue;
} catch (e) {
if (e.name !== 'SecurityError') throw e; // for Firefox
continue;
}
const cssRules: any = s.cssRules;
for (let r = 0; r < cssRules.length; r++) {
if (
cssRules[r].selectorText &&
selectorTextArr.some((s) => cssRules[r].selectorText.includes(s))
)
extractedCSSText += cssRules[r].cssText;
}
}
return extractedCSSText;
};
const appendCSS = (cssText: string, element: Element) => {
const styleElement = document.createElement('style');
styleElement.setAttribute('type', 'text/css');
styleElement.innerHTML = cssText;
const refNode = element.hasChildNodes() ? element.children[0] : null;
element.insertBefore(styleElement, refNode);
};
const svgElementToSvgText = (svgNode: Element) => {
svgNode.setAttribute('xlink', 'http://www.w3.org/1999/xlink');
const cssStyleText = getCSSStyles(svgNode);
appendCSS(cssStyleText, svgNode);
const serializer = new XMLSerializer();
const svgString = serializer.serializeToString(svgNode);
return svgString;
};
const svgText2DownloadUrl = async (svg: string, width: number, height: number, format: string) =>
new Promise<string>((resolve, reject) => {
const imgsrc = `data:image/svg+xml;base64,${btoa(unescape(encodeURIComponent(svg)))}`;
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
const image = new Image();
image.onload = function () {
context.clearRect(0, 0, width, height);
context.drawImage(image, 0, 0, width, height);
const img = canvas.toDataURL(`image/${format}`);
resolve(img);
};
image.onerror = reject;
image.src = imgsrc;
});
export default Demo;
Compact
Reduce table cel paddings by adding the compact
property.
import React from 'react';
import DataTable from 'intergalactic/data-table';
const Demo = () => {
return (
<DataTable data={data} compact>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' />
<DataTable.Column name='kd' children='KD,%' />
<DataTable.Column name='cpc' children='CPC' />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
},
];
export default Demo;
Borders
Add borders to columns by passing the vBorders
property to specific columns.
import React from 'react';
import DataTable, { DataTableSort } from 'intergalactic/data-table';
const Demo = () => {
const [sort, setSort] = React.useState<DataTableSort<keyof typeof data[0]>>(['cpc', 'desc']);
return (
<DataTable data={data} sort={sort} onSortChange={setSort}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' sortable />
<DataTable.Column vBorders>
Organic Sessions
<DataTable.Column name='kd' children='KD' sortable />
<DataTable.Column name='cpc' children='CPC' sortable />
<DataTable.Column name='vol' children='Vol.' />
</DataTable.Column>
<DataTable.Column name='other' children='Other' />
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
other: 'ebay buy',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
other: 'ebay buy',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
other: 'ebay buy',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
other: 'ebay buy',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
other: 'ebay buy',
},
];
export default Demo;
Column expand
The active column will expand if there isn't enough space. Fixed-width columns will not change size.
TIP
Be cautious with columns with a wMax
property, as the sort icon may overlap the header text on hover, hiding part of the text.
import React from 'react';
import DataTable, { DataTableSort } from 'intergalactic/data-table';
const Demo = () => {
const [sort, setSort] = React.useState<DataTableSort<keyof typeof data[0]>>(['cpc', 'desc']);
return (
<DataTable data={data} sort={sort} onSortChange={setSort}>
<DataTable.Head>
<DataTable.Column name='keyword' children='Keyword' wMax={'300px'} />
<DataTable.Column name='kd' children='Difficulty Difficulty' sortable wMax={'85px'} />
<DataTable.Column name='cpc' children='CPC' sortable />
<DataTable.Column name='vol' children='Vol.' sortable wMax={'300px'} />
<DataTable.Column name='md' children='Marketing SEO' sortable wMax={'90px'} />
</DataTable.Head>
<DataTable.Body />
</DataTable>
);
};
const data = [
{
keyword: 'ebay buy',
kd: '77.8',
cpc: '$1.25',
vol: '32,500,000',
md: '221',
},
{
keyword: 'www.ebay.com',
kd: '11.2',
cpc: '$3.4',
vol: '65,457,920',
md: '221',
},
{
keyword: 'www.ebay.com',
kd: '10',
cpc: '$0.65',
vol: '47,354,640',
md: 'n/a',
},
{
keyword: 'ebay buy',
kd: '-',
cpc: '$0',
vol: 'n/a',
md: '221',
},
{
keyword: 'ebay buy',
kd: '75.89',
cpc: '$0',
vol: '21,644,290',
md: '221',
},
];
export default Demo;