Repository files navigation

react-smart-data-table

npm versionContributor CovenantWorkflow Status

A smart data table component for React.js meant to be configuration free, batteries included.

About

This is meant to be a zero configuration data table component for React.js in the spirit of plug and play.

Just feed it an array of equal JSON objects and it will create a template free table that can be customized easily with any framework (or custom CSS).

Features

It supports:

  1. Humanized column names based on object keys
  2. Sortable columns
    • Accepts a custom sort compareFn function
  3. Rows filtering / searchable
  4. Search term highlight in the results
  5. Column visibility toggles
  6. Automatic pagination
  7. Server-side/remote data
  8. Control over row clicks
  9. Smart data rendering
    • URLs and E-Mail addresses rendered as the href in an anchor tag <a />
    • boolean value parsing to yes/no word
    • Image URLs rendered as the src for an image tag <img />
  10. Custom override if the default behavior is unwanted for some columns
  11. Custom components
    • Paginator
  12. Control the order of the columns
    • Using the above, it's also possible to select which columns to display

Installation

npm install react-smart-data-table
# or
pnpm add react-smart-data-table

There is some very basic styling you can use to get started. You can also copy the file and use it as the basis for your own theme.

// Import basic stylingimport'react-smart-data-table/dist/react-smart-data-table.css'

Context

You can access the SmartDataTable's internal context in your own component by using the useSmartDataTableContext hook.

Note: You must be within the context of SmartDataTable, e.g. passing a custom component to emptyTable, loading, or paginator.

import{useSmartDataTableContext}from'react-smart-data-table'constMyComponent=()=>{const{ columns, data }=useSmartDataTableContext()return(<div><h3>My Component</h3><p>Columns: {columns.length}</p><p>Rows: {data.length}</p></div>)}

Props

NameDefaultTypeDescription
data[]{array|string}An array of plain objects (can be nested) or a URL
dataKey'data'{string}The object key where the async data is available
dataKeyResolvernull{function}Supply a function to extract the data from the async response
dataRequestOptions{}{object}Fetch API options passed directly into the async request call
dataSampling0{number}Percentage of the data to sample before computing the headers
dynamicfalse{boolean}Use this if your column structure changes dynamically
emptyTablenull{element}Pass a renderable object to render when there is no data
filterValue''{string}Filters all columns by its value
headers{}{object}The object that overrides default column behavior
hideUnorderedfalse{boolean}Hides all the columns not passed to orderedHeaders
loadernull{element}Element to be rendered while fetching async data
name'reactsmartdatatable'{string}The name for the table
onRowClickundefined{function}If present, it will execute on every row click
orderedHeaders[]{array}An ordered array of the column keys
paginatorelements{element}Pass a renderable object to handle the table pagination
parseBoolfalse{boolean|object}When true, boolean values will be converted to Yes/No
parseImgfalse{boolean|object}When true, image URLs will be rendered as an img tag
perPage0{number}Paginates the results with the value as rows per page
rowClassNameundefined{function}If present, returns a className string for each row
sortablefalse{boolean}Enables the columns of the table to be sortable
withFooterfalse{boolean}Copy the header to the footer
withHeadertrue{boolean}Can be used to disable the rendering of column headers
withLinksfalse{boolean}Converts e-mails and url addresses to links
withTogglesfalse{boolean|object}Enables the column visibility toggles

Performance tip: Function props (onRowClick, rowClassName, dataKeyResolver) are called on every render cycle. Wrap them with useCallback to keep row memoization effective and avoid unnecessary re-renders.

emptyTable

// Any renderable object can be passedconstemptyTable=<div>There is no data available at the time.</div>

headers

/* Use the following structure to overwrite the default behavior for columns Undefined column keys will present the default behavior text: Humanized text based on the column key name invisible: Columns are visible by default sortable: Columns are sortable by default filterable: Columns are filterable by default isImg: Will force the render as an image, e.g. for dynamic URLs transform: Allows the custom rendering of the cells content Should be a function and these are the arguments passed: (value, index, row) The index is the position of the row as being rendered and not the index of the row in the original data Nested structures can be defined by a string-dot representation 'key1.key2.key3.[...].key99'*/constheaders={columnKey: {text: 'Column 1',invisible: false,sortable: true,filterable: true,},'nested.columnKey': {text: 'Nested Column',invisible: false,sortable: (a,b)=>b['nested.columnKey']-a['nested.columnKey'],filterable: true,},// If a dummy column is inserted into the data, it can be used to customize// the table by allowing actions per row to be implemented, for exampletableActions: {text: 'Actions',invisible: false,sortable: false,filterable: false,transform: (value,index,row)=>{// The following results should be identicalconsole.log(value,row.tableActions)// Example of table actions: Delete row from data by row indexreturn<buttononClick={()=>deleteRow(row)}>Delete Row</button>},},}

onRowClick()

constonRowClick=(event,{ rowData, rowIndex, tableData })=>{// The following results should be identicalconsole.log(rowData,tableData[rowIndex])}

rowClassName()

// Return a className string for each row's <tr> elementconstrowClassName=(rowData,rowIndex)=>{// rowIndex is zero-based, so the 1st row (index 0) is oddreturnrowIndex%2===0 ? 'odd-row' : 'even-row'}

paginator

The CustomComponent passed down as a prop will be rendered with the following props which can be used to perform all the necessary calculations and makes it fully compatible with Semantic UI's Pagination component.

constCustomComponent=({
activePage, totalPages, onPageChange,})=>(/* ... */)<SmartDataTable// ...paginator={CustomComponent}/>// To change the page, call the onPageChange function with the next activePage<MyCustomElement// ...onClick={(e)=>onPageChange(e,{activePage: nextActivePage})}/>

parseBool

// DefaultconstparseBool={yesWord: 'Yes',noWord: 'No',}

parseImg

// You can pass a regular style object that will be passed down to <img />// Or a Class NameconstparseImg={style: {border: '1px solid #ddd',borderRadius: '4px',padding: '5px',width: '150px',},className: 'my-custom-image-style',}

orderedHeaders / hideUnordered

If you want to control the order of the columns, simply pass an array containing the keys in the desired order. All the omitted headers will be appended afterwards unpredictably. Additionally, you can pass the hideUnordered in order to render only the headers in orderedHeaders and hide the remaining.

consthideUnordered=trueconstorderedHeaders=['key1','key2.subkey3',
...
]

withToggles

You can control the Toggles by passing an object with the following structure:

// Default toggles enabledconstwithToggles=true// Default toggles enabled with default select allconstwithToggles={selectAll: true,}// Toggles with a custom localeconstwithToggles={// The options to be passed as props to the `SelectAll` componentselectAll: {// The text to be displayed in the Select All inputlocale: {// The default label for the `unchecked` stateselectAllWord: 'Select All',// The default label for the `checked` stateunSelectAllWord: 'Unselect All',},// You should not need to use this, but it is here for completenesshandleToggleAll: (isChecked: boolean): void=>{// ...},},}

Examples

Async data loading (fetch)

By passing a string to the data prop, the component will interpret it as an URL and try to load the data from that location using fetch. If a successful request is returned, the data will be extracted from the response object. By default, it will grab the data key from the response. If it's in a different key, you can specify it with the dataKey prop. Just in case it's not a first-level attribute, you can supply a custom function to locate the data using the dataKeyResolver prop.

response from /api/v1/user

{
"status": "success",
"message": "",
"users": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}

response from /api/v1/post

{
"status": "success",
"message": "",
"results": {
"posts": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}
}

component

// Using `dataKey`<SmartDataTabledata="/api/v1/user"dataKey="users"name="test-table"/>// Using `dataKeyResolver`<SmartDataTabledata="/api/v1/post"dataKeyResolver={(response)=>response.results.posts}name="test-table"/>

Simple sortable table

import{faker}from'@faker-js/faker'import{createRoot}from'react-dom/client'importSmartDataTablefrom'react-smart-data-table'consttestData=[]constnumResults=100for(leti=0;i<numResults;i++){testData.push({_id: i,fullName: faker.person.fullName(),'email.address': faker.internet.email(),phone_number: faker.phone.number(),address: {city: faker.location.city(),state: faker.location.state(),country: faker.location.country(),},})}createRoot(document.getElementById('app')).render(<SmartDataTabledata={testData}name="test-table"className="ui compact selectable table"sortable/>,)

Demos

You can try react-smart-data-table with different UI libraries in the demo pages below. You can experiment with different features as well.

Take a look at the full featured example's source code.

Also, see it in full integration with a simple user/group management dashboard application. Feel free to play around with it, it's built with hot reloading.

If you want to play around, check out this codepen.

FAQ

If you're having trouble with react-smart-data-table, please check out the answers below. Otherwise, feel free to open a new issue!

  • Check this answer to see how to hide the pagination for an empty table
  • Check this answer if you're integrating with Server Side Rendering (SSR)
  • Check this answer if you want to implement a double click event on a row
  • Check this answer if you want to control the active page manually (e.g., based on a URL parameter)
  • Check this answer if you want to style individual columns differently

Forking / Contributing

If you want to fork or contribute, it's easy to test your changes. Just run the following development commands. The start instruction will start a development HTTP server in your computer accessible from your browser at the address http://localhost:3000/.

pnpm start

About

A smart data table component for React meant to be configuration free

Topics

Resources

Code of conduct

Contributing

Stars

87 stars

Watchers

8 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

react-smart-data-table

npm versionContributor CovenantWorkflow Status

A smart data table component for React.js meant to be configuration free, batteries included.

About

This is meant to be a zero configuration data table component for React.js in the spirit of plug and play.

Just feed it an array of equal JSON objects and it will create a template free table that can be customized easily with any framework (or custom CSS).

Features

It supports:

  1. Humanized column names based on object keys
  2. Sortable columns
    • Accepts a custom sort compareFn function
  3. Rows filtering / searchable
  4. Search term highlight in the results
  5. Column visibility toggles
  6. Automatic pagination
  7. Server-side/remote data
  8. Control over row clicks
  9. Smart data rendering
    • URLs and E-Mail addresses rendered as the href in an anchor tag <a />
    • boolean value parsing to yes/no word
    • Image URLs rendered as the src for an image tag <img />
  10. Custom override if the default behavior is unwanted for some columns
  11. Custom components
    • Paginator
  12. Control the order of the columns
    • Using the above, it's also possible to select which columns to display

Installation

npm install react-smart-data-table
# or
pnpm add react-smart-data-table

There is some very basic styling you can use to get started. You can also copy the file and use it as the basis for your own theme.

// Import basic stylingimport'react-smart-data-table/dist/react-smart-data-table.css'

Context

You can access the SmartDataTable's internal context in your own component by using the useSmartDataTableContext hook.

Note: You must be within the context of SmartDataTable, e.g. passing a custom component to emptyTable, loading, or paginator.

import{useSmartDataTableContext}from'react-smart-data-table'constMyComponent=()=>{const{ columns, data }=useSmartDataTableContext()return(<div><h3>My Component</h3><p>Columns: {columns.length}</p><p>Rows: {data.length}</p></div>)}

Props

NameDefaultTypeDescription
data[]{array|string}An array of plain objects (can be nested) or a URL
dataKey'data'{string}The object key where the async data is available
dataKeyResolvernull{function}Supply a function to extract the data from the async response
dataRequestOptions{}{object}Fetch API options passed directly into the async request call
dataSampling0{number}Percentage of the data to sample before computing the headers
dynamicfalse{boolean}Use this if your column structure changes dynamically
emptyTablenull{element}Pass a renderable object to render when there is no data
filterValue''{string}Filters all columns by its value
headers{}{object}The object that overrides default column behavior
hideUnorderedfalse{boolean}Hides all the columns not passed to orderedHeaders
loadernull{element}Element to be rendered while fetching async data
name'reactsmartdatatable'{string}The name for the table
onRowClickundefined{function}If present, it will execute on every row click
orderedHeaders[]{array}An ordered array of the column keys
paginatorelements{element}Pass a renderable object to handle the table pagination
parseBoolfalse{boolean|object}When true, boolean values will be converted to Yes/No
parseImgfalse{boolean|object}When true, image URLs will be rendered as an img tag
perPage0{number}Paginates the results with the value as rows per page
rowClassNameundefined{function}If present, returns a className string for each row
sortablefalse{boolean}Enables the columns of the table to be sortable
withFooterfalse{boolean}Copy the header to the footer
withHeadertrue{boolean}Can be used to disable the rendering of column headers
withLinksfalse{boolean}Converts e-mails and url addresses to links
withTogglesfalse{boolean|object}Enables the column visibility toggles

Performance tip: Function props (onRowClick, rowClassName, dataKeyResolver) are called on every render cycle. Wrap them with useCallback to keep row memoization effective and avoid unnecessary re-renders.

emptyTable

// Any renderable object can be passedconstemptyTable=<div>There is no data available at the time.</div>

headers

/* Use the following structure to overwrite the default behavior for columns Undefined column keys will present the default behavior text: Humanized text based on the column key name invisible: Columns are visible by default sortable: Columns are sortable by default filterable: Columns are filterable by default isImg: Will force the render as an image, e.g. for dynamic URLs transform: Allows the custom rendering of the cells content Should be a function and these are the arguments passed: (value, index, row) The index is the position of the row as being rendered and not the index of the row in the original data Nested structures can be defined by a string-dot representation 'key1.key2.key3.[...].key99'*/constheaders={columnKey: {text: 'Column 1',invisible: false,sortable: true,filterable: true,},'nested.columnKey': {text: 'Nested Column',invisible: false,sortable: (a,b)=>b['nested.columnKey']-a['nested.columnKey'],filterable: true,},// If a dummy column is inserted into the data, it can be used to customize// the table by allowing actions per row to be implemented, for exampletableActions: {text: 'Actions',invisible: false,sortable: false,filterable: false,transform: (value,index,row)=>{// The following results should be identicalconsole.log(value,row.tableActions)// Example of table actions: Delete row from data by row indexreturn<buttononClick={()=>deleteRow(row)}>Delete Row</button>},},}

onRowClick()

constonRowClick=(event,{ rowData, rowIndex, tableData })=>{// The following results should be identicalconsole.log(rowData,tableData[rowIndex])}

rowClassName()

// Return a className string for each row's <tr> elementconstrowClassName=(rowData,rowIndex)=>{// rowIndex is zero-based, so the 1st row (index 0) is oddreturnrowIndex%2===0 ? 'odd-row' : 'even-row'}

paginator

The CustomComponent passed down as a prop will be rendered with the following props which can be used to perform all the necessary calculations and makes it fully compatible with Semantic UI's Pagination component.

constCustomComponent=({
activePage, totalPages, onPageChange,})=>(/* ... */)<SmartDataTable// ...paginator={CustomComponent}/>// To change the page, call the onPageChange function with the next activePage<MyCustomElement// ...onClick={(e)=>onPageChange(e,{activePage: nextActivePage})}/>

parseBool

// DefaultconstparseBool={yesWord: 'Yes',noWord: 'No',}

parseImg

// You can pass a regular style object that will be passed down to <img />// Or a Class NameconstparseImg={style: {border: '1px solid #ddd',borderRadius: '4px',padding: '5px',width: '150px',},className: 'my-custom-image-style',}

orderedHeaders / hideUnordered

If you want to control the order of the columns, simply pass an array containing the keys in the desired order. All the omitted headers will be appended afterwards unpredictably. Additionally, you can pass the hideUnordered in order to render only the headers in orderedHeaders and hide the remaining.

consthideUnordered=trueconstorderedHeaders=['key1','key2.subkey3',
...
]

withToggles

You can control the Toggles by passing an object with the following structure:

// Default toggles enabledconstwithToggles=true// Default toggles enabled with default select allconstwithToggles={selectAll: true,}// Toggles with a custom localeconstwithToggles={// The options to be passed as props to the `SelectAll` componentselectAll: {// The text to be displayed in the Select All inputlocale: {// The default label for the `unchecked` stateselectAllWord: 'Select All',// The default label for the `checked` stateunSelectAllWord: 'Unselect All',},// You should not need to use this, but it is here for completenesshandleToggleAll: (isChecked: boolean): void=>{// ...},},}

Examples

Async data loading (fetch)

By passing a string to the data prop, the component will interpret it as an URL and try to load the data from that location using fetch. If a successful request is returned, the data will be extracted from the response object. By default, it will grab the data key from the response. If it's in a different key, you can specify it with the dataKey prop. Just in case it's not a first-level attribute, you can supply a custom function to locate the data using the dataKeyResolver prop.

response from /api/v1/user

{
"status": "success",
"message": "",
"users": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}

response from /api/v1/post

{
"status": "success",
"message": "",
"results": {
"posts": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}
}

component

// Using `dataKey`<SmartDataTabledata="/api/v1/user"dataKey="users"name="test-table"/>// Using `dataKeyResolver`<SmartDataTabledata="/api/v1/post"dataKeyResolver={(response)=>response.results.posts}name="test-table"/>

Simple sortable table

import{faker}from'@faker-js/faker'import{createRoot}from'react-dom/client'importSmartDataTablefrom'react-smart-data-table'consttestData=[]constnumResults=100for(leti=0;i<numResults;i++){testData.push({_id: i,fullName: faker.person.fullName(),'email.address': faker.internet.email(),phone_number: faker.phone.number(),address: {city: faker.location.city(),state: faker.location.state(),country: faker.location.country(),},})}createRoot(document.getElementById('app')).render(<SmartDataTabledata={testData}name="test-table"className="ui compact selectable table"sortable/>,)

Demos

You can try react-smart-data-table with different UI libraries in the demo pages below. You can experiment with different features as well.

Take a look at the full featured example's source code.

Also, see it in full integration with a simple user/group management dashboard application. Feel free to play around with it, it's built with hot reloading.

If you want to play around, check out this codepen.

FAQ

If you're having trouble with react-smart-data-table, please check out the answers below. Otherwise, feel free to open a new issue!

  • Check this answer to see how to hide the pagination for an empty table
  • Check this answer if you're integrating with Server Side Rendering (SSR)
  • Check this answer if you want to implement a double click event on a row
  • Check this answer if you want to control the active page manually (e.g., based on a URL parameter)
  • Check this answer if you want to style individual columns differently

Forking / Contributing

If you want to fork or contribute, it's easy to test your changes. Just run the following development commands. The start instruction will start a development HTTP server in your computer accessible from your browser at the address http://localhost:3000/.

pnpm start

About

A smart data table component for React meant to be configuration free

Topics

Resources

Code of conduct

Contributing

Stars

87 stars

Watchers

8 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

react-smart-data-table

npm versionContributor CovenantWorkflow Status

A smart data table component for React.js meant to be configuration free, batteries included.

About

This is meant to be a zero configuration data table component for React.js in the spirit of plug and play.

Just feed it an array of equal JSON objects and it will create a template free table that can be customized easily with any framework (or custom CSS).

Features

It supports:

  1. Humanized column names based on object keys
  2. Sortable columns
    • Accepts a custom sort compareFn function
  3. Rows filtering / searchable
  4. Search term highlight in the results
  5. Column visibility toggles
  6. Automatic pagination
  7. Server-side/remote data
  8. Control over row clicks
  9. Smart data rendering
    • URLs and E-Mail addresses rendered as the href in an anchor tag <a />
    • boolean value parsing to yes/no word
    • Image URLs rendered as the src for an image tag <img />
  10. Custom override if the default behavior is unwanted for some columns
  11. Custom components
    • Paginator
  12. Control the order of the columns
    • Using the above, it's also possible to select which columns to display

Installation

npm install react-smart-data-table
# or
pnpm add react-smart-data-table

There is some very basic styling you can use to get started. You can also copy the file and use it as the basis for your own theme.

// Import basic stylingimport'react-smart-data-table/dist/react-smart-data-table.css'

Context

You can access the SmartDataTable's internal context in your own component by using the useSmartDataTableContext hook.

Note: You must be within the context of SmartDataTable, e.g. passing a custom component to emptyTable, loading, or paginator.

import{useSmartDataTableContext}from'react-smart-data-table'constMyComponent=()=>{const{ columns, data }=useSmartDataTableContext()return(<div><h3>My Component</h3><p>Columns: {columns.length}</p><p>Rows: {data.length}</p></div>)}

Props

NameDefaultTypeDescription
data[]{array|string}An array of plain objects (can be nested) or a URL
dataKey'data'{string}The object key where the async data is available
dataKeyResolvernull{function}Supply a function to extract the data from the async response
dataRequestOptions{}{object}Fetch API options passed directly into the async request call
dataSampling0{number}Percentage of the data to sample before computing the headers
dynamicfalse{boolean}Use this if your column structure changes dynamically
emptyTablenull{element}Pass a renderable object to render when there is no data
filterValue''{string}Filters all columns by its value
headers{}{object}The object that overrides default column behavior
hideUnorderedfalse{boolean}Hides all the columns not passed to orderedHeaders
loadernull{element}Element to be rendered while fetching async data
name'reactsmartdatatable'{string}The name for the table
onRowClickundefined{function}If present, it will execute on every row click
orderedHeaders[]{array}An ordered array of the column keys
paginatorelements{element}Pass a renderable object to handle the table pagination
parseBoolfalse{boolean|object}When true, boolean values will be converted to Yes/No
parseImgfalse{boolean|object}When true, image URLs will be rendered as an img tag
perPage0{number}Paginates the results with the value as rows per page
rowClassNameundefined{function}If present, returns a className string for each row
sortablefalse{boolean}Enables the columns of the table to be sortable
withFooterfalse{boolean}Copy the header to the footer
withHeadertrue{boolean}Can be used to disable the rendering of column headers
withLinksfalse{boolean}Converts e-mails and url addresses to links
withTogglesfalse{boolean|object}Enables the column visibility toggles

Performance tip: Function props (onRowClick, rowClassName, dataKeyResolver) are called on every render cycle. Wrap them with useCallback to keep row memoization effective and avoid unnecessary re-renders.

emptyTable

// Any renderable object can be passedconstemptyTable=<div>There is no data available at the time.</div>

headers

/* Use the following structure to overwrite the default behavior for columns Undefined column keys will present the default behavior text: Humanized text based on the column key name invisible: Columns are visible by default sortable: Columns are sortable by default filterable: Columns are filterable by default isImg: Will force the render as an image, e.g. for dynamic URLs transform: Allows the custom rendering of the cells content Should be a function and these are the arguments passed: (value, index, row) The index is the position of the row as being rendered and not the index of the row in the original data Nested structures can be defined by a string-dot representation 'key1.key2.key3.[...].key99'*/constheaders={columnKey: {text: 'Column 1',invisible: false,sortable: true,filterable: true,},'nested.columnKey': {text: 'Nested Column',invisible: false,sortable: (a,b)=>b['nested.columnKey']-a['nested.columnKey'],filterable: true,},// If a dummy column is inserted into the data, it can be used to customize// the table by allowing actions per row to be implemented, for exampletableActions: {text: 'Actions',invisible: false,sortable: false,filterable: false,transform: (value,index,row)=>{// The following results should be identicalconsole.log(value,row.tableActions)// Example of table actions: Delete row from data by row indexreturn<buttononClick={()=>deleteRow(row)}>Delete Row</button>},},}

onRowClick()

constonRowClick=(event,{ rowData, rowIndex, tableData })=>{// The following results should be identicalconsole.log(rowData,tableData[rowIndex])}

rowClassName()

// Return a className string for each row's <tr> elementconstrowClassName=(rowData,rowIndex)=>{// rowIndex is zero-based, so the 1st row (index 0) is oddreturnrowIndex%2===0 ? 'odd-row' : 'even-row'}

paginator

The CustomComponent passed down as a prop will be rendered with the following props which can be used to perform all the necessary calculations and makes it fully compatible with Semantic UI's Pagination component.

constCustomComponent=({
activePage, totalPages, onPageChange,})=>(/* ... */)<SmartDataTable// ...paginator={CustomComponent}/>// To change the page, call the onPageChange function with the next activePage<MyCustomElement// ...onClick={(e)=>onPageChange(e,{activePage: nextActivePage})}/>

parseBool

// DefaultconstparseBool={yesWord: 'Yes',noWord: 'No',}

parseImg

// You can pass a regular style object that will be passed down to <img />// Or a Class NameconstparseImg={style: {border: '1px solid #ddd',borderRadius: '4px',padding: '5px',width: '150px',},className: 'my-custom-image-style',}

orderedHeaders / hideUnordered

If you want to control the order of the columns, simply pass an array containing the keys in the desired order. All the omitted headers will be appended afterwards unpredictably. Additionally, you can pass the hideUnordered in order to render only the headers in orderedHeaders and hide the remaining.

consthideUnordered=trueconstorderedHeaders=['key1','key2.subkey3',
...
]

withToggles

You can control the Toggles by passing an object with the following structure:

// Default toggles enabledconstwithToggles=true// Default toggles enabled with default select allconstwithToggles={selectAll: true,}// Toggles with a custom localeconstwithToggles={// The options to be passed as props to the `SelectAll` componentselectAll: {// The text to be displayed in the Select All inputlocale: {// The default label for the `unchecked` stateselectAllWord: 'Select All',// The default label for the `checked` stateunSelectAllWord: 'Unselect All',},// You should not need to use this, but it is here for completenesshandleToggleAll: (isChecked: boolean): void=>{// ...},},}

Examples

Async data loading (fetch)

By passing a string to the data prop, the component will interpret it as an URL and try to load the data from that location using fetch. If a successful request is returned, the data will be extracted from the response object. By default, it will grab the data key from the response. If it's in a different key, you can specify it with the dataKey prop. Just in case it's not a first-level attribute, you can supply a custom function to locate the data using the dataKeyResolver prop.

response from /api/v1/user

{
"status": "success",
"message": "",
"users": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}

response from /api/v1/post

{
"status": "success",
"message": "",
"results": {
"posts": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}
}

component

// Using `dataKey`<SmartDataTabledata="/api/v1/user"dataKey="users"name="test-table"/>// Using `dataKeyResolver`<SmartDataTabledata="/api/v1/post"dataKeyResolver={(response)=>response.results.posts}name="test-table"/>

Simple sortable table

import{faker}from'@faker-js/faker'import{createRoot}from'react-dom/client'importSmartDataTablefrom'react-smart-data-table'consttestData=[]constnumResults=100for(leti=0;i<numResults;i++){testData.push({_id: i,fullName: faker.person.fullName(),'email.address': faker.internet.email(),phone_number: faker.phone.number(),address: {city: faker.location.city(),state: faker.location.state(),country: faker.location.country(),},})}createRoot(document.getElementById('app')).render(<SmartDataTabledata={testData}name="test-table"className="ui compact selectable table"sortable/>,)

Demos

You can try react-smart-data-table with different UI libraries in the demo pages below. You can experiment with different features as well.

Take a look at the full featured example's source code.

Also, see it in full integration with a simple user/group management dashboard application. Feel free to play around with it, it's built with hot reloading.

If you want to play around, check out this codepen.

FAQ

If you're having trouble with react-smart-data-table, please check out the answers below. Otherwise, feel free to open a new issue!

  • Check this answer to see how to hide the pagination for an empty table
  • Check this answer if you're integrating with Server Side Rendering (SSR)
  • Check this answer if you want to implement a double click event on a row
  • Check this answer if you want to control the active page manually (e.g., based on a URL parameter)
  • Check this answer if you want to style individual columns differently

Forking / Contributing

If you want to fork or contribute, it's easy to test your changes. Just run the following development commands. The start instruction will start a development HTTP server in your computer accessible from your browser at the address http://localhost:3000/.

pnpm start

About

A smart data table component for React meant to be configuration free

Topics

Resources

Code of conduct

Contributing

Stars

87 stars

Watchers

8 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

react-smart-data-table

npm versionContributor CovenantWorkflow Status

A smart data table component for React.js meant to be configuration free, batteries included.

About

This is meant to be a zero configuration data table component for React.js in the spirit of plug and play.

Just feed it an array of equal JSON objects and it will create a template free table that can be customized easily with any framework (or custom CSS).

Features

It supports:

  1. Humanized column names based on object keys
  2. Sortable columns
    • Accepts a custom sort compareFn function
  3. Rows filtering / searchable
  4. Search term highlight in the results
  5. Column visibility toggles
  6. Automatic pagination
  7. Server-side/remote data
  8. Control over row clicks
  9. Smart data rendering
    • URLs and E-Mail addresses rendered as the href in an anchor tag <a />
    • boolean value parsing to yes/no word
    • Image URLs rendered as the src for an image tag <img />
  10. Custom override if the default behavior is unwanted for some columns
  11. Custom components
    • Paginator
  12. Control the order of the columns
    • Using the above, it's also possible to select which columns to display

Installation

npm install react-smart-data-table
# or
pnpm add react-smart-data-table

There is some very basic styling you can use to get started. You can also copy the file and use it as the basis for your own theme.

// Import basic stylingimport'react-smart-data-table/dist/react-smart-data-table.css'

Context

You can access the SmartDataTable's internal context in your own component by using the useSmartDataTableContext hook.

Note: You must be within the context of SmartDataTable, e.g. passing a custom component to emptyTable, loading, or paginator.

import{useSmartDataTableContext}from'react-smart-data-table'constMyComponent=()=>{const{ columns, data }=useSmartDataTableContext()return(<div><h3>My Component</h3><p>Columns: {columns.length}</p><p>Rows: {data.length}</p></div>)}

Props

NameDefaultTypeDescription
data[]{array|string}An array of plain objects (can be nested) or a URL
dataKey'data'{string}The object key where the async data is available
dataKeyResolvernull{function}Supply a function to extract the data from the async response
dataRequestOptions{}{object}Fetch API options passed directly into the async request call
dataSampling0{number}Percentage of the data to sample before computing the headers
dynamicfalse{boolean}Use this if your column structure changes dynamically
emptyTablenull{element}Pass a renderable object to render when there is no data
filterValue''{string}Filters all columns by its value
headers{}{object}The object that overrides default column behavior
hideUnorderedfalse{boolean}Hides all the columns not passed to orderedHeaders
loadernull{element}Element to be rendered while fetching async data
name'reactsmartdatatable'{string}The name for the table
onRowClickundefined{function}If present, it will execute on every row click
orderedHeaders[]{array}An ordered array of the column keys
paginatorelements{element}Pass a renderable object to handle the table pagination
parseBoolfalse{boolean|object}When true, boolean values will be converted to Yes/No
parseImgfalse{boolean|object}When true, image URLs will be rendered as an img tag
perPage0{number}Paginates the results with the value as rows per page
rowClassNameundefined{function}If present, returns a className string for each row
sortablefalse{boolean}Enables the columns of the table to be sortable
withFooterfalse{boolean}Copy the header to the footer
withHeadertrue{boolean}Can be used to disable the rendering of column headers
withLinksfalse{boolean}Converts e-mails and url addresses to links
withTogglesfalse{boolean|object}Enables the column visibility toggles

Performance tip: Function props (onRowClick, rowClassName, dataKeyResolver) are called on every render cycle. Wrap them with useCallback to keep row memoization effective and avoid unnecessary re-renders.

emptyTable

// Any renderable object can be passedconstemptyTable=<div>There is no data available at the time.</div>

headers

/* Use the following structure to overwrite the default behavior for columns Undefined column keys will present the default behavior text: Humanized text based on the column key name invisible: Columns are visible by default sortable: Columns are sortable by default filterable: Columns are filterable by default isImg: Will force the render as an image, e.g. for dynamic URLs transform: Allows the custom rendering of the cells content Should be a function and these are the arguments passed: (value, index, row) The index is the position of the row as being rendered and not the index of the row in the original data Nested structures can be defined by a string-dot representation 'key1.key2.key3.[...].key99'*/constheaders={columnKey: {text: 'Column 1',invisible: false,sortable: true,filterable: true,},'nested.columnKey': {text: 'Nested Column',invisible: false,sortable: (a,b)=>b['nested.columnKey']-a['nested.columnKey'],filterable: true,},// If a dummy column is inserted into the data, it can be used to customize// the table by allowing actions per row to be implemented, for exampletableActions: {text: 'Actions',invisible: false,sortable: false,filterable: false,transform: (value,index,row)=>{// The following results should be identicalconsole.log(value,row.tableActions)// Example of table actions: Delete row from data by row indexreturn<buttononClick={()=>deleteRow(row)}>Delete Row</button>},},}

onRowClick()

constonRowClick=(event,{ rowData, rowIndex, tableData })=>{// The following results should be identicalconsole.log(rowData,tableData[rowIndex])}

rowClassName()

// Return a className string for each row's <tr> elementconstrowClassName=(rowData,rowIndex)=>{// rowIndex is zero-based, so the 1st row (index 0) is oddreturnrowIndex%2===0 ? 'odd-row' : 'even-row'}

paginator

The CustomComponent passed down as a prop will be rendered with the following props which can be used to perform all the necessary calculations and makes it fully compatible with Semantic UI's Pagination component.

constCustomComponent=({
activePage, totalPages, onPageChange,})=>(/* ... */)<SmartDataTable// ...paginator={CustomComponent}/>// To change the page, call the onPageChange function with the next activePage<MyCustomElement// ...onClick={(e)=>onPageChange(e,{activePage: nextActivePage})}/>

parseBool

// DefaultconstparseBool={yesWord: 'Yes',noWord: 'No',}

parseImg

// You can pass a regular style object that will be passed down to <img />// Or a Class NameconstparseImg={style: {border: '1px solid #ddd',borderRadius: '4px',padding: '5px',width: '150px',},className: 'my-custom-image-style',}

orderedHeaders / hideUnordered

If you want to control the order of the columns, simply pass an array containing the keys in the desired order. All the omitted headers will be appended afterwards unpredictably. Additionally, you can pass the hideUnordered in order to render only the headers in orderedHeaders and hide the remaining.

consthideUnordered=trueconstorderedHeaders=['key1','key2.subkey3',
...
]

withToggles

You can control the Toggles by passing an object with the following structure:

// Default toggles enabledconstwithToggles=true// Default toggles enabled with default select allconstwithToggles={selectAll: true,}// Toggles with a custom localeconstwithToggles={// The options to be passed as props to the `SelectAll` componentselectAll: {// The text to be displayed in the Select All inputlocale: {// The default label for the `unchecked` stateselectAllWord: 'Select All',// The default label for the `checked` stateunSelectAllWord: 'Unselect All',},// You should not need to use this, but it is here for completenesshandleToggleAll: (isChecked: boolean): void=>{// ...},},}

Examples

Async data loading (fetch)

By passing a string to the data prop, the component will interpret it as an URL and try to load the data from that location using fetch. If a successful request is returned, the data will be extracted from the response object. By default, it will grab the data key from the response. If it's in a different key, you can specify it with the dataKey prop. Just in case it's not a first-level attribute, you can supply a custom function to locate the data using the dataKeyResolver prop.

response from /api/v1/user

{
"status": "success",
"message": "",
"users": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}

response from /api/v1/post

{
"status": "success",
"message": "",
"results": {
"posts": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}
}

component

// Using `dataKey`<SmartDataTabledata="/api/v1/user"dataKey="users"name="test-table"/>// Using `dataKeyResolver`<SmartDataTabledata="/api/v1/post"dataKeyResolver={(response)=>response.results.posts}name="test-table"/>

Simple sortable table

import{faker}from'@faker-js/faker'import{createRoot}from'react-dom/client'importSmartDataTablefrom'react-smart-data-table'consttestData=[]constnumResults=100for(leti=0;i<numResults;i++){testData.push({_id: i,fullName: faker.person.fullName(),'email.address': faker.internet.email(),phone_number: faker.phone.number(),address: {city: faker.location.city(),state: faker.location.state(),country: faker.location.country(),},})}createRoot(document.getElementById('app')).render(<SmartDataTabledata={testData}name="test-table"className="ui compact selectable table"sortable/>,)

Demos

You can try react-smart-data-table with different UI libraries in the demo pages below. You can experiment with different features as well.

Take a look at the full featured example's source code.

Also, see it in full integration with a simple user/group management dashboard application. Feel free to play around with it, it's built with hot reloading.

If you want to play around, check out this codepen.

FAQ

If you're having trouble with react-smart-data-table, please check out the answers below. Otherwise, feel free to open a new issue!

  • Check this answer to see how to hide the pagination for an empty table
  • Check this answer if you're integrating with Server Side Rendering (SSR)
  • Check this answer if you want to implement a double click event on a row
  • Check this answer if you want to control the active page manually (e.g., based on a URL parameter)
  • Check this answer if you want to style individual columns differently

Forking / Contributing

If you want to fork or contribute, it's easy to test your changes. Just run the following development commands. The start instruction will start a development HTTP server in your computer accessible from your browser at the address http://localhost:3000/.

pnpm start

About

A smart data table component for React meant to be configuration free

Topics

Resources

Code of conduct

Contributing

Stars

87 stars

Watchers

8 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

react-smart-data-table

npm versionContributor CovenantWorkflow Status

A smart data table component for React.js meant to be configuration free, batteries included.

About

This is meant to be a zero configuration data table component for React.js in the spirit of plug and play.

Just feed it an array of equal JSON objects and it will create a template free table that can be customized easily with any framework (or custom CSS).

Features

It supports:

  1. Humanized column names based on object keys
  2. Sortable columns
    • Accepts a custom sort compareFn function
  3. Rows filtering / searchable
  4. Search term highlight in the results
  5. Column visibility toggles
  6. Automatic pagination
  7. Server-side/remote data
  8. Control over row clicks
  9. Smart data rendering
    • URLs and E-Mail addresses rendered as the href in an anchor tag <a />
    • boolean value parsing to yes/no word
    • Image URLs rendered as the src for an image tag <img />
  10. Custom override if the default behavior is unwanted for some columns
  11. Custom components
    • Paginator
  12. Control the order of the columns
    • Using the above, it's also possible to select which columns to display

Installation

npm install react-smart-data-table
# or
pnpm add react-smart-data-table

There is some very basic styling you can use to get started. You can also copy the file and use it as the basis for your own theme.

// Import basic stylingimport'react-smart-data-table/dist/react-smart-data-table.css'

Context

You can access the SmartDataTable's internal context in your own component by using the useSmartDataTableContext hook.

Note: You must be within the context of SmartDataTable, e.g. passing a custom component to emptyTable, loading, or paginator.

import{useSmartDataTableContext}from'react-smart-data-table'constMyComponent=()=>{const{ columns, data }=useSmartDataTableContext()return(<div><h3>My Component</h3><p>Columns: {columns.length}</p><p>Rows: {data.length}</p></div>)}

Props

NameDefaultTypeDescription
data[]{array|string}An array of plain objects (can be nested) or a URL
dataKey'data'{string}The object key where the async data is available
dataKeyResolvernull{function}Supply a function to extract the data from the async response
dataRequestOptions{}{object}Fetch API options passed directly into the async request call
dataSampling0{number}Percentage of the data to sample before computing the headers
dynamicfalse{boolean}Use this if your column structure changes dynamically
emptyTablenull{element}Pass a renderable object to render when there is no data
filterValue''{string}Filters all columns by its value
headers{}{object}The object that overrides default column behavior
hideUnorderedfalse{boolean}Hides all the columns not passed to orderedHeaders
loadernull{element}Element to be rendered while fetching async data
name'reactsmartdatatable'{string}The name for the table
onRowClickundefined{function}If present, it will execute on every row click
orderedHeaders[]{array}An ordered array of the column keys
paginatorelements{element}Pass a renderable object to handle the table pagination
parseBoolfalse{boolean|object}When true, boolean values will be converted to Yes/No
parseImgfalse{boolean|object}When true, image URLs will be rendered as an img tag
perPage0{number}Paginates the results with the value as rows per page
rowClassNameundefined{function}If present, returns a className string for each row
sortablefalse{boolean}Enables the columns of the table to be sortable
withFooterfalse{boolean}Copy the header to the footer
withHeadertrue{boolean}Can be used to disable the rendering of column headers
withLinksfalse{boolean}Converts e-mails and url addresses to links
withTogglesfalse{boolean|object}Enables the column visibility toggles

Performance tip: Function props (onRowClick, rowClassName, dataKeyResolver) are called on every render cycle. Wrap them with useCallback to keep row memoization effective and avoid unnecessary re-renders.

emptyTable

// Any renderable object can be passedconstemptyTable=<div>There is no data available at the time.</div>

headers

/* Use the following structure to overwrite the default behavior for columns Undefined column keys will present the default behavior text: Humanized text based on the column key name invisible: Columns are visible by default sortable: Columns are sortable by default filterable: Columns are filterable by default isImg: Will force the render as an image, e.g. for dynamic URLs transform: Allows the custom rendering of the cells content Should be a function and these are the arguments passed: (value, index, row) The index is the position of the row as being rendered and not the index of the row in the original data Nested structures can be defined by a string-dot representation 'key1.key2.key3.[...].key99'*/constheaders={columnKey: {text: 'Column 1',invisible: false,sortable: true,filterable: true,},'nested.columnKey': {text: 'Nested Column',invisible: false,sortable: (a,b)=>b['nested.columnKey']-a['nested.columnKey'],filterable: true,},// If a dummy column is inserted into the data, it can be used to customize// the table by allowing actions per row to be implemented, for exampletableActions: {text: 'Actions',invisible: false,sortable: false,filterable: false,transform: (value,index,row)=>{// The following results should be identicalconsole.log(value,row.tableActions)// Example of table actions: Delete row from data by row indexreturn<buttononClick={()=>deleteRow(row)}>Delete Row</button>},},}

onRowClick()

constonRowClick=(event,{ rowData, rowIndex, tableData })=>{// The following results should be identicalconsole.log(rowData,tableData[rowIndex])}

rowClassName()

// Return a className string for each row's <tr> elementconstrowClassName=(rowData,rowIndex)=>{// rowIndex is zero-based, so the 1st row (index 0) is oddreturnrowIndex%2===0 ? 'odd-row' : 'even-row'}

paginator

The CustomComponent passed down as a prop will be rendered with the following props which can be used to perform all the necessary calculations and makes it fully compatible with Semantic UI's Pagination component.

constCustomComponent=({
activePage, totalPages, onPageChange,})=>(/* ... */)<SmartDataTable// ...paginator={CustomComponent}/>// To change the page, call the onPageChange function with the next activePage<MyCustomElement// ...onClick={(e)=>onPageChange(e,{activePage: nextActivePage})}/>

parseBool

// DefaultconstparseBool={yesWord: 'Yes',noWord: 'No',}

parseImg

// You can pass a regular style object that will be passed down to <img />// Or a Class NameconstparseImg={style: {border: '1px solid #ddd',borderRadius: '4px',padding: '5px',width: '150px',},className: 'my-custom-image-style',}

orderedHeaders / hideUnordered

If you want to control the order of the columns, simply pass an array containing the keys in the desired order. All the omitted headers will be appended afterwards unpredictably. Additionally, you can pass the hideUnordered in order to render only the headers in orderedHeaders and hide the remaining.

consthideUnordered=trueconstorderedHeaders=['key1','key2.subkey3',
...
]

withToggles

You can control the Toggles by passing an object with the following structure:

// Default toggles enabledconstwithToggles=true// Default toggles enabled with default select allconstwithToggles={selectAll: true,}// Toggles with a custom localeconstwithToggles={// The options to be passed as props to the `SelectAll` componentselectAll: {// The text to be displayed in the Select All inputlocale: {// The default label for the `unchecked` stateselectAllWord: 'Select All',// The default label for the `checked` stateunSelectAllWord: 'Unselect All',},// You should not need to use this, but it is here for completenesshandleToggleAll: (isChecked: boolean): void=>{// ...},},}

Examples

Async data loading (fetch)

By passing a string to the data prop, the component will interpret it as an URL and try to load the data from that location using fetch. If a successful request is returned, the data will be extracted from the response object. By default, it will grab the data key from the response. If it's in a different key, you can specify it with the dataKey prop. Just in case it's not a first-level attribute, you can supply a custom function to locate the data using the dataKeyResolver prop.

response from /api/v1/user

{
"status": "success",
"message": "",
"users": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}

response from /api/v1/post

{
"status": "success",
"message": "",
"results": {
"posts": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}
}

component

// Using `dataKey`<SmartDataTabledata="/api/v1/user"dataKey="users"name="test-table"/>// Using `dataKeyResolver`<SmartDataTabledata="/api/v1/post"dataKeyResolver={(response)=>response.results.posts}name="test-table"/>

Simple sortable table

import{faker}from'@faker-js/faker'import{createRoot}from'react-dom/client'importSmartDataTablefrom'react-smart-data-table'consttestData=[]constnumResults=100for(leti=0;i<numResults;i++){testData.push({_id: i,fullName: faker.person.fullName(),'email.address': faker.internet.email(),phone_number: faker.phone.number(),address: {city: faker.location.city(),state: faker.location.state(),country: faker.location.country(),},})}createRoot(document.getElementById('app')).render(<SmartDataTabledata={testData}name="test-table"className="ui compact selectable table"sortable/>,)

Demos

You can try react-smart-data-table with different UI libraries in the demo pages below. You can experiment with different features as well.

Take a look at the full featured example's source code.

Also, see it in full integration with a simple user/group management dashboard application. Feel free to play around with it, it's built with hot reloading.

If you want to play around, check out this codepen.

FAQ

If you're having trouble with react-smart-data-table, please check out the answers below. Otherwise, feel free to open a new issue!

  • Check this answer to see how to hide the pagination for an empty table
  • Check this answer if you're integrating with Server Side Rendering (SSR)
  • Check this answer if you want to implement a double click event on a row
  • Check this answer if you want to control the active page manually (e.g., based on a URL parameter)
  • Check this answer if you want to style individual columns differently

Forking / Contributing

If you want to fork or contribute, it's easy to test your changes. Just run the following development commands. The start instruction will start a development HTTP server in your computer accessible from your browser at the address http://localhost:3000/.

pnpm start

About

A smart data table component for React meant to be configuration free

Topics

Resources

Code of conduct

Contributing

Stars

87 stars

Watchers

8 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

react-smart-data-table

npm versionContributor CovenantWorkflow Status

A smart data table component for React.js meant to be configuration free, batteries included.

About

This is meant to be a zero configuration data table component for React.js in the spirit of plug and play.

Just feed it an array of equal JSON objects and it will create a template free table that can be customized easily with any framework (or custom CSS).

Features

It supports:

  1. Humanized column names based on object keys
  2. Sortable columns
    • Accepts a custom sort compareFn function
  3. Rows filtering / searchable
  4. Search term highlight in the results
  5. Column visibility toggles
  6. Automatic pagination
  7. Server-side/remote data
  8. Control over row clicks
  9. Smart data rendering
    • URLs and E-Mail addresses rendered as the href in an anchor tag <a />
    • boolean value parsing to yes/no word
    • Image URLs rendered as the src for an image tag <img />
  10. Custom override if the default behavior is unwanted for some columns
  11. Custom components
    • Paginator
  12. Control the order of the columns
    • Using the above, it's also possible to select which columns to display

Installation

npm install react-smart-data-table
# or
pnpm add react-smart-data-table

There is some very basic styling you can use to get started. You can also copy the file and use it as the basis for your own theme.

// Import basic stylingimport'react-smart-data-table/dist/react-smart-data-table.css'

Context

You can access the SmartDataTable's internal context in your own component by using the useSmartDataTableContext hook.

Note: You must be within the context of SmartDataTable, e.g. passing a custom component to emptyTable, loading, or paginator.

import{useSmartDataTableContext}from'react-smart-data-table'constMyComponent=()=>{const{ columns, data }=useSmartDataTableContext()return(<div><h3>My Component</h3><p>Columns: {columns.length}</p><p>Rows: {data.length}</p></div>)}

Props

NameDefaultTypeDescription
data[]{array|string}An array of plain objects (can be nested) or a URL
dataKey'data'{string}The object key where the async data is available
dataKeyResolvernull{function}Supply a function to extract the data from the async response
dataRequestOptions{}{object}Fetch API options passed directly into the async request call
dataSampling0{number}Percentage of the data to sample before computing the headers
dynamicfalse{boolean}Use this if your column structure changes dynamically
emptyTablenull{element}Pass a renderable object to render when there is no data
filterValue''{string}Filters all columns by its value
headers{}{object}The object that overrides default column behavior
hideUnorderedfalse{boolean}Hides all the columns not passed to orderedHeaders
loadernull{element}Element to be rendered while fetching async data
name'reactsmartdatatable'{string}The name for the table
onRowClickundefined{function}If present, it will execute on every row click
orderedHeaders[]{array}An ordered array of the column keys
paginatorelements{element}Pass a renderable object to handle the table pagination
parseBoolfalse{boolean|object}When true, boolean values will be converted to Yes/No
parseImgfalse{boolean|object}When true, image URLs will be rendered as an img tag
perPage0{number}Paginates the results with the value as rows per page
rowClassNameundefined{function}If present, returns a className string for each row
sortablefalse{boolean}Enables the columns of the table to be sortable
withFooterfalse{boolean}Copy the header to the footer
withHeadertrue{boolean}Can be used to disable the rendering of column headers
withLinksfalse{boolean}Converts e-mails and url addresses to links
withTogglesfalse{boolean|object}Enables the column visibility toggles

Performance tip: Function props (onRowClick, rowClassName, dataKeyResolver) are called on every render cycle. Wrap them with useCallback to keep row memoization effective and avoid unnecessary re-renders.

emptyTable

// Any renderable object can be passedconstemptyTable=<div>There is no data available at the time.</div>

headers

/* Use the following structure to overwrite the default behavior for columns Undefined column keys will present the default behavior text: Humanized text based on the column key name invisible: Columns are visible by default sortable: Columns are sortable by default filterable: Columns are filterable by default isImg: Will force the render as an image, e.g. for dynamic URLs transform: Allows the custom rendering of the cells content Should be a function and these are the arguments passed: (value, index, row) The index is the position of the row as being rendered and not the index of the row in the original data Nested structures can be defined by a string-dot representation 'key1.key2.key3.[...].key99'*/constheaders={columnKey: {text: 'Column 1',invisible: false,sortable: true,filterable: true,},'nested.columnKey': {text: 'Nested Column',invisible: false,sortable: (a,b)=>b['nested.columnKey']-a['nested.columnKey'],filterable: true,},// If a dummy column is inserted into the data, it can be used to customize// the table by allowing actions per row to be implemented, for exampletableActions: {text: 'Actions',invisible: false,sortable: false,filterable: false,transform: (value,index,row)=>{// The following results should be identicalconsole.log(value,row.tableActions)// Example of table actions: Delete row from data by row indexreturn<buttononClick={()=>deleteRow(row)}>Delete Row</button>},},}

onRowClick()

constonRowClick=(event,{ rowData, rowIndex, tableData })=>{// The following results should be identicalconsole.log(rowData,tableData[rowIndex])}

rowClassName()

// Return a className string for each row's <tr> elementconstrowClassName=(rowData,rowIndex)=>{// rowIndex is zero-based, so the 1st row (index 0) is oddreturnrowIndex%2===0 ? 'odd-row' : 'even-row'}

paginator

The CustomComponent passed down as a prop will be rendered with the following props which can be used to perform all the necessary calculations and makes it fully compatible with Semantic UI's Pagination component.

constCustomComponent=({
activePage, totalPages, onPageChange,})=>(/* ... */)<SmartDataTable// ...paginator={CustomComponent}/>// To change the page, call the onPageChange function with the next activePage<MyCustomElement// ...onClick={(e)=>onPageChange(e,{activePage: nextActivePage})}/>

parseBool

// DefaultconstparseBool={yesWord: 'Yes',noWord: 'No',}

parseImg

// You can pass a regular style object that will be passed down to <img />// Or a Class NameconstparseImg={style: {border: '1px solid #ddd',borderRadius: '4px',padding: '5px',width: '150px',},className: 'my-custom-image-style',}

orderedHeaders / hideUnordered

If you want to control the order of the columns, simply pass an array containing the keys in the desired order. All the omitted headers will be appended afterwards unpredictably. Additionally, you can pass the hideUnordered in order to render only the headers in orderedHeaders and hide the remaining.

consthideUnordered=trueconstorderedHeaders=['key1','key2.subkey3',
...
]

withToggles

You can control the Toggles by passing an object with the following structure:

// Default toggles enabledconstwithToggles=true// Default toggles enabled with default select allconstwithToggles={selectAll: true,}// Toggles with a custom localeconstwithToggles={// The options to be passed as props to the `SelectAll` componentselectAll: {// The text to be displayed in the Select All inputlocale: {// The default label for the `unchecked` stateselectAllWord: 'Select All',// The default label for the `checked` stateunSelectAllWord: 'Unselect All',},// You should not need to use this, but it is here for completenesshandleToggleAll: (isChecked: boolean): void=>{// ...},},}

Examples

Async data loading (fetch)

By passing a string to the data prop, the component will interpret it as an URL and try to load the data from that location using fetch. If a successful request is returned, the data will be extracted from the response object. By default, it will grab the data key from the response. If it's in a different key, you can specify it with the dataKey prop. Just in case it's not a first-level attribute, you can supply a custom function to locate the data using the dataKeyResolver prop.

response from /api/v1/user

{
"status": "success",
"message": "",
"users": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}

response from /api/v1/post

{
"status": "success",
"message": "",
"results": {
"posts": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}
}

component

// Using `dataKey`<SmartDataTabledata="/api/v1/user"dataKey="users"name="test-table"/>// Using `dataKeyResolver`<SmartDataTabledata="/api/v1/post"dataKeyResolver={(response)=>response.results.posts}name="test-table"/>

Simple sortable table

import{faker}from'@faker-js/faker'import{createRoot}from'react-dom/client'importSmartDataTablefrom'react-smart-data-table'consttestData=[]constnumResults=100for(leti=0;i<numResults;i++){testData.push({_id: i,fullName: faker.person.fullName(),'email.address': faker.internet.email(),phone_number: faker.phone.number(),address: {city: faker.location.city(),state: faker.location.state(),country: faker.location.country(),},})}createRoot(document.getElementById('app')).render(<SmartDataTabledata={testData}name="test-table"className="ui compact selectable table"sortable/>,)

Demos

You can try react-smart-data-table with different UI libraries in the demo pages below. You can experiment with different features as well.

Take a look at the full featured example's source code.

Also, see it in full integration with a simple user/group management dashboard application. Feel free to play around with it, it's built with hot reloading.

If you want to play around, check out this codepen.

FAQ

If you're having trouble with react-smart-data-table, please check out the answers below. Otherwise, feel free to open a new issue!

  • Check this answer to see how to hide the pagination for an empty table
  • Check this answer if you're integrating with Server Side Rendering (SSR)
  • Check this answer if you want to implement a double click event on a row
  • Check this answer if you want to control the active page manually (e.g., based on a URL parameter)
  • Check this answer if you want to style individual columns differently

Forking / Contributing

If you want to fork or contribute, it's easy to test your changes. Just run the following development commands. The start instruction will start a development HTTP server in your computer accessible from your browser at the address http://localhost:3000/.

pnpm start

About

A smart data table component for React meant to be configuration free

Topics

Resources

Code of conduct

Contributing

Stars

87 stars

Watchers

8 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

react-smart-data-table

npm versionContributor CovenantWorkflow Status

A smart data table component for React.js meant to be configuration free, batteries included.

About

This is meant to be a zero configuration data table component for React.js in the spirit of plug and play.

Just feed it an array of equal JSON objects and it will create a template free table that can be customized easily with any framework (or custom CSS).

Features

It supports:

  1. Humanized column names based on object keys
  2. Sortable columns
    • Accepts a custom sort compareFn function
  3. Rows filtering / searchable
  4. Search term highlight in the results
  5. Column visibility toggles
  6. Automatic pagination
  7. Server-side/remote data
  8. Control over row clicks
  9. Smart data rendering
    • URLs and E-Mail addresses rendered as the href in an anchor tag <a />
    • boolean value parsing to yes/no word
    • Image URLs rendered as the src for an image tag <img />
  10. Custom override if the default behavior is unwanted for some columns
  11. Custom components
    • Paginator
  12. Control the order of the columns
    • Using the above, it's also possible to select which columns to display

Installation

npm install react-smart-data-table
# or
pnpm add react-smart-data-table

There is some very basic styling you can use to get started. You can also copy the file and use it as the basis for your own theme.

// Import basic stylingimport'react-smart-data-table/dist/react-smart-data-table.css'

Context

You can access the SmartDataTable's internal context in your own component by using the useSmartDataTableContext hook.

Note: You must be within the context of SmartDataTable, e.g. passing a custom component to emptyTable, loading, or paginator.

import{useSmartDataTableContext}from'react-smart-data-table'constMyComponent=()=>{const{ columns, data }=useSmartDataTableContext()return(<div><h3>My Component</h3><p>Columns: {columns.length}</p><p>Rows: {data.length}</p></div>)}

Props

NameDefaultTypeDescription
data[]{array|string}An array of plain objects (can be nested) or a URL
dataKey'data'{string}The object key where the async data is available
dataKeyResolvernull{function}Supply a function to extract the data from the async response
dataRequestOptions{}{object}Fetch API options passed directly into the async request call
dataSampling0{number}Percentage of the data to sample before computing the headers
dynamicfalse{boolean}Use this if your column structure changes dynamically
emptyTablenull{element}Pass a renderable object to render when there is no data
filterValue''{string}Filters all columns by its value
headers{}{object}The object that overrides default column behavior
hideUnorderedfalse{boolean}Hides all the columns not passed to orderedHeaders
loadernull{element}Element to be rendered while fetching async data
name'reactsmartdatatable'{string}The name for the table
onRowClickundefined{function}If present, it will execute on every row click
orderedHeaders[]{array}An ordered array of the column keys
paginatorelements{element}Pass a renderable object to handle the table pagination
parseBoolfalse{boolean|object}When true, boolean values will be converted to Yes/No
parseImgfalse{boolean|object}When true, image URLs will be rendered as an img tag
perPage0{number}Paginates the results with the value as rows per page
rowClassNameundefined{function}If present, returns a className string for each row
sortablefalse{boolean}Enables the columns of the table to be sortable
withFooterfalse{boolean}Copy the header to the footer
withHeadertrue{boolean}Can be used to disable the rendering of column headers
withLinksfalse{boolean}Converts e-mails and url addresses to links
withTogglesfalse{boolean|object}Enables the column visibility toggles

Performance tip: Function props (onRowClick, rowClassName, dataKeyResolver) are called on every render cycle. Wrap them with useCallback to keep row memoization effective and avoid unnecessary re-renders.

emptyTable

// Any renderable object can be passedconstemptyTable=<div>There is no data available at the time.</div>

headers

/* Use the following structure to overwrite the default behavior for columns Undefined column keys will present the default behavior text: Humanized text based on the column key name invisible: Columns are visible by default sortable: Columns are sortable by default filterable: Columns are filterable by default isImg: Will force the render as an image, e.g. for dynamic URLs transform: Allows the custom rendering of the cells content Should be a function and these are the arguments passed: (value, index, row) The index is the position of the row as being rendered and not the index of the row in the original data Nested structures can be defined by a string-dot representation 'key1.key2.key3.[...].key99'*/constheaders={columnKey: {text: 'Column 1',invisible: false,sortable: true,filterable: true,},'nested.columnKey': {text: 'Nested Column',invisible: false,sortable: (a,b)=>b['nested.columnKey']-a['nested.columnKey'],filterable: true,},// If a dummy column is inserted into the data, it can be used to customize// the table by allowing actions per row to be implemented, for exampletableActions: {text: 'Actions',invisible: false,sortable: false,filterable: false,transform: (value,index,row)=>{// The following results should be identicalconsole.log(value,row.tableActions)// Example of table actions: Delete row from data by row indexreturn<buttononClick={()=>deleteRow(row)}>Delete Row</button>},},}

onRowClick()

constonRowClick=(event,{ rowData, rowIndex, tableData })=>{// The following results should be identicalconsole.log(rowData,tableData[rowIndex])}

rowClassName()

// Return a className string for each row's <tr> elementconstrowClassName=(rowData,rowIndex)=>{// rowIndex is zero-based, so the 1st row (index 0) is oddreturnrowIndex%2===0 ? 'odd-row' : 'even-row'}

paginator

The CustomComponent passed down as a prop will be rendered with the following props which can be used to perform all the necessary calculations and makes it fully compatible with Semantic UI's Pagination component.

constCustomComponent=({
activePage, totalPages, onPageChange,})=>(/* ... */)<SmartDataTable// ...paginator={CustomComponent}/>// To change the page, call the onPageChange function with the next activePage<MyCustomElement// ...onClick={(e)=>onPageChange(e,{activePage: nextActivePage})}/>

parseBool

// DefaultconstparseBool={yesWord: 'Yes',noWord: 'No',}

parseImg

// You can pass a regular style object that will be passed down to <img />// Or a Class NameconstparseImg={style: {border: '1px solid #ddd',borderRadius: '4px',padding: '5px',width: '150px',},className: 'my-custom-image-style',}

orderedHeaders / hideUnordered

If you want to control the order of the columns, simply pass an array containing the keys in the desired order. All the omitted headers will be appended afterwards unpredictably. Additionally, you can pass the hideUnordered in order to render only the headers in orderedHeaders and hide the remaining.

consthideUnordered=trueconstorderedHeaders=['key1','key2.subkey3',
...
]

withToggles

You can control the Toggles by passing an object with the following structure:

// Default toggles enabledconstwithToggles=true// Default toggles enabled with default select allconstwithToggles={selectAll: true,}// Toggles with a custom localeconstwithToggles={// The options to be passed as props to the `SelectAll` componentselectAll: {// The text to be displayed in the Select All inputlocale: {// The default label for the `unchecked` stateselectAllWord: 'Select All',// The default label for the `checked` stateunSelectAllWord: 'Unselect All',},// You should not need to use this, but it is here for completenesshandleToggleAll: (isChecked: boolean): void=>{// ...},},}

Examples

Async data loading (fetch)

By passing a string to the data prop, the component will interpret it as an URL and try to load the data from that location using fetch. If a successful request is returned, the data will be extracted from the response object. By default, it will grab the data key from the response. If it's in a different key, you can specify it with the dataKey prop. Just in case it's not a first-level attribute, you can supply a custom function to locate the data using the dataKeyResolver prop.

response from /api/v1/user

{
"status": "success",
"message": "",
"users": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}

response from /api/v1/post

{
"status": "success",
"message": "",
"results": {
"posts": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}
}

component

// Using `dataKey`<SmartDataTabledata="/api/v1/user"dataKey="users"name="test-table"/>// Using `dataKeyResolver`<SmartDataTabledata="/api/v1/post"dataKeyResolver={(response)=>response.results.posts}name="test-table"/>

Simple sortable table

import{faker}from'@faker-js/faker'import{createRoot}from'react-dom/client'importSmartDataTablefrom'react-smart-data-table'consttestData=[]constnumResults=100for(leti=0;i<numResults;i++){testData.push({_id: i,fullName: faker.person.fullName(),'email.address': faker.internet.email(),phone_number: faker.phone.number(),address: {city: faker.location.city(),state: faker.location.state(),country: faker.location.country(),},})}createRoot(document.getElementById('app')).render(<SmartDataTabledata={testData}name="test-table"className="ui compact selectable table"sortable/>,)

Demos

You can try react-smart-data-table with different UI libraries in the demo pages below. You can experiment with different features as well.

Take a look at the full featured example's source code.

Also, see it in full integration with a simple user/group management dashboard application. Feel free to play around with it, it's built with hot reloading.

If you want to play around, check out this codepen.

FAQ

If you're having trouble with react-smart-data-table, please check out the answers below. Otherwise, feel free to open a new issue!

  • Check this answer to see how to hide the pagination for an empty table
  • Check this answer if you're integrating with Server Side Rendering (SSR)
  • Check this answer if you want to implement a double click event on a row
  • Check this answer if you want to control the active page manually (e.g., based on a URL parameter)
  • Check this answer if you want to style individual columns differently

Forking / Contributing

If you want to fork or contribute, it's easy to test your changes. Just run the following development commands. The start instruction will start a development HTTP server in your computer accessible from your browser at the address http://localhost:3000/.

pnpm start

About

A smart data table component for React meant to be configuration free

Topics

Resources

Code of conduct

Contributing

Stars

87 stars

Watchers

8 watching

Forks

Releases

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

react-smart-data-table

npm versionContributor CovenantWorkflow Status

A smart data table component for React.js meant to be configuration free, batteries included.

About

This is meant to be a zero configuration data table component for React.js in the spirit of plug and play.

Just feed it an array of equal JSON objects and it will create a template free table that can be customized easily with any framework (or custom CSS).

Features

It supports:

  1. Humanized column names based on object keys
  2. Sortable columns
    • Accepts a custom sort compareFn function
  3. Rows filtering / searchable
  4. Search term highlight in the results
  5. Column visibility toggles
  6. Automatic pagination
  7. Server-side/remote data
  8. Control over row clicks
  9. Smart data rendering
    • URLs and E-Mail addresses rendered as the href in an anchor tag <a />
    • boolean value parsing to yes/no word
    • Image URLs rendered as the src for an image tag <img />
  10. Custom override if the default behavior is unwanted for some columns
  11. Custom components
    • Paginator
  12. Control the order of the columns
    • Using the above, it's also possible to select which columns to display

Installation

npm install react-smart-data-table
# or
pnpm add react-smart-data-table

There is some very basic styling you can use to get started. You can also copy the file and use it as the basis for your own theme.

// Import basic stylingimport'react-smart-data-table/dist/react-smart-data-table.css'

Context

You can access the SmartDataTable's internal context in your own component by using the useSmartDataTableContext hook.

Note: You must be within the context of SmartDataTable, e.g. passing a custom component to emptyTable, loading, or paginator.

import{useSmartDataTableContext}from'react-smart-data-table'constMyComponent=()=>{const{ columns, data }=useSmartDataTableContext()return(<div><h3>My Component</h3><p>Columns: {columns.length}</p><p>Rows: {data.length}</p></div>)}

Props

NameDefaultTypeDescription
data[]{array|string}An array of plain objects (can be nested) or a URL
dataKey'data'{string}The object key where the async data is available
dataKeyResolvernull{function}Supply a function to extract the data from the async response
dataRequestOptions{}{object}Fetch API options passed directly into the async request call
dataSampling0{number}Percentage of the data to sample before computing the headers
dynamicfalse{boolean}Use this if your column structure changes dynamically
emptyTablenull{element}Pass a renderable object to render when there is no data
filterValue''{string}Filters all columns by its value
headers{}{object}The object that overrides default column behavior
hideUnorderedfalse{boolean}Hides all the columns not passed to orderedHeaders
loadernull{element}Element to be rendered while fetching async data
name'reactsmartdatatable'{string}The name for the table
onRowClickundefined{function}If present, it will execute on every row click
orderedHeaders[]{array}An ordered array of the column keys
paginatorelements{element}Pass a renderable object to handle the table pagination
parseBoolfalse{boolean|object}When true, boolean values will be converted to Yes/No
parseImgfalse{boolean|object}When true, image URLs will be rendered as an img tag
perPage0{number}Paginates the results with the value as rows per page
rowClassNameundefined{function}If present, returns a className string for each row
sortablefalse{boolean}Enables the columns of the table to be sortable
withFooterfalse{boolean}Copy the header to the footer
withHeadertrue{boolean}Can be used to disable the rendering of column headers
withLinksfalse{boolean}Converts e-mails and url addresses to links
withTogglesfalse{boolean|object}Enables the column visibility toggles

Performance tip: Function props (onRowClick, rowClassName, dataKeyResolver) are called on every render cycle. Wrap them with useCallback to keep row memoization effective and avoid unnecessary re-renders.

emptyTable

// Any renderable object can be passedconstemptyTable=<div>There is no data available at the time.</div>

headers

/* Use the following structure to overwrite the default behavior for columns Undefined column keys will present the default behavior text: Humanized text based on the column key name invisible: Columns are visible by default sortable: Columns are sortable by default filterable: Columns are filterable by default isImg: Will force the render as an image, e.g. for dynamic URLs transform: Allows the custom rendering of the cells content Should be a function and these are the arguments passed: (value, index, row) The index is the position of the row as being rendered and not the index of the row in the original data Nested structures can be defined by a string-dot representation 'key1.key2.key3.[...].key99'*/constheaders={columnKey: {text: 'Column 1',invisible: false,sortable: true,filterable: true,},'nested.columnKey': {text: 'Nested Column',invisible: false,sortable: (a,b)=>b['nested.columnKey']-a['nested.columnKey'],filterable: true,},// If a dummy column is inserted into the data, it can be used to customize// the table by allowing actions per row to be implemented, for exampletableActions: {text: 'Actions',invisible: false,sortable: false,filterable: false,transform: (value,index,row)=>{// The following results should be identicalconsole.log(value,row.tableActions)// Example of table actions: Delete row from data by row indexreturn<buttononClick={()=>deleteRow(row)}>Delete Row</button>},},}

onRowClick()

constonRowClick=(event,{ rowData, rowIndex, tableData })=>{// The following results should be identicalconsole.log(rowData,tableData[rowIndex])}

rowClassName()

// Return a className string for each row's <tr> elementconstrowClassName=(rowData,rowIndex)=>{// rowIndex is zero-based, so the 1st row (index 0) is oddreturnrowIndex%2===0 ? 'odd-row' : 'even-row'}

paginator

The CustomComponent passed down as a prop will be rendered with the following props which can be used to perform all the necessary calculations and makes it fully compatible with Semantic UI's Pagination component.

constCustomComponent=({
activePage, totalPages, onPageChange,})=>(/* ... */)<SmartDataTable// ...paginator={CustomComponent}/>// To change the page, call the onPageChange function with the next activePage<MyCustomElement// ...onClick={(e)=>onPageChange(e,{activePage: nextActivePage})}/>

parseBool

// DefaultconstparseBool={yesWord: 'Yes',noWord: 'No',}

parseImg

// You can pass a regular style object that will be passed down to <img />// Or a Class NameconstparseImg={style: {border: '1px solid #ddd',borderRadius: '4px',padding: '5px',width: '150px',},className: 'my-custom-image-style',}

orderedHeaders / hideUnordered

If you want to control the order of the columns, simply pass an array containing the keys in the desired order. All the omitted headers will be appended afterwards unpredictably. Additionally, you can pass the hideUnordered in order to render only the headers in orderedHeaders and hide the remaining.

consthideUnordered=trueconstorderedHeaders=['key1','key2.subkey3',
...
]

withToggles

You can control the Toggles by passing an object with the following structure:

// Default toggles enabledconstwithToggles=true// Default toggles enabled with default select allconstwithToggles={selectAll: true,}// Toggles with a custom localeconstwithToggles={// The options to be passed as props to the `SelectAll` componentselectAll: {// The text to be displayed in the Select All inputlocale: {// The default label for the `unchecked` stateselectAllWord: 'Select All',// The default label for the `checked` stateunSelectAllWord: 'Unselect All',},// You should not need to use this, but it is here for completenesshandleToggleAll: (isChecked: boolean): void=>{// ...},},}

Examples

Async data loading (fetch)

By passing a string to the data prop, the component will interpret it as an URL and try to load the data from that location using fetch. If a successful request is returned, the data will be extracted from the response object. By default, it will grab the data key from the response. If it's in a different key, you can specify it with the dataKey prop. Just in case it's not a first-level attribute, you can supply a custom function to locate the data using the dataKeyResolver prop.

response from /api/v1/user

{
"status": "success",
"message": "",
"users": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}

response from /api/v1/post

{
"status": "success",
"message": "",
"results": {
"posts": [{ "id": 0, "other": "..." }, { "id": 1, "other": "..." }, "..."]
}
}

component

// Using `dataKey`<SmartDataTabledata="/api/v1/user"dataKey="users"name="test-table"/>// Using `dataKeyResolver`<SmartDataTabledata="/api/v1/post"dataKeyResolver={(response)=>response.results.posts}name="test-table"/>

Simple sortable table

import{faker}from'@faker-js/faker'import{createRoot}from'react-dom/client'importSmartDataTablefrom'react-smart-data-table'consttestData=[]constnumResults=100for(leti=0;i<numResults;i++){testData.push({_id: i,fullName: faker.person.fullName(),'email.address': faker.internet.email(),phone_number: faker.phone.number(),address: {city: faker.location.city(),state: faker.location.state(),country: faker.location.country(),},})}createRoot(document.getElementById('app')).render(<SmartDataTabledata={testData}name="test-table"className="ui compact selectable table"sortable/>,)

Demos

You can try react-smart-data-table with different UI libraries in the demo pages below. You can experiment with different features as well.

Take a look at the full featured example's source code.

Also, see it in full integration with a simple user/group management dashboard application. Feel free to play around with it, it's built with hot reloading.

If you want to play around, check out this codepen.

FAQ

If you're having trouble with react-smart-data-table, please check out the answers below. Otherwise, feel free to open a new issue!

  • Check this answer to see how to hide the pagination for an empty table
  • Check this answer if you're integrating with Server Side Rendering (SSR)
  • Check this answer if you want to implement a double click event on a row
  • Check this answer if you want to control the active page manually (e.g., based on a URL parameter)
  • Check this answer if you want to style individual columns differently

Forking / Contributing

If you want to fork or contribute, it's easy to test your changes. Just run the following development commands. The start instruction will start a development HTTP server in your computer accessible from your browser at the address http://localhost:3000/.

pnpm start

About

A smart data table component for React meant to be configuration free

Topics

Resources

Code of conduct

Contributing

Stars

87 stars

Watchers

8 watching

Forks

Releases

Used by

Contributors

Languages