-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(table): virtualization #4285
base: canary
Are you sure you want to change the base?
Changes from all commits
bff9f02
aaf9afb
038613a
72b4f88
432e2e8
ed0a7d8
fc78b55
783e260
dfc56c1
edd6f91
3308771
455149b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@nextui-org/table": patch | ||
--- | ||
|
||
Virtualization support added to Table component |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@nextui-org/react"; | ||
|
||
function generateRows(count) { | ||
return Array.from({length: count}, (_, index) => ({ | ||
key: index.toString(), | ||
name: `Item ${index + 1}`, | ||
value: `Value ${index + 1}`, | ||
})); | ||
} | ||
|
||
export default function App() { | ||
const rows = generateRows(500); | ||
const columns = [ | ||
{key: "name", label: "Name"}, | ||
{key: "value", label: "Value"}, | ||
]; | ||
|
||
return ( | ||
<Table | ||
isVirtualized | ||
aria-label="Example of virtualized table with a large dataset" | ||
maxTableHeight={300} | ||
rowHeight={40} | ||
> | ||
<TableHeader columns={columns}> | ||
{(column) => <TableColumn key={column.key}>{column.label}</TableColumn>} | ||
</TableHeader> | ||
<TableBody items={rows}> | ||
{(item) => ( | ||
<TableRow key={item.key}> | ||
{(columnKey) => <TableCell>{item[columnKey]}</TableCell>} | ||
</TableRow> | ||
)} | ||
</TableBody> | ||
</Table> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import App from "./virtualization-custom-max-table-height.raw.jsx?raw"; | ||
|
||
const react = { | ||
"/App.jsx": App, | ||
}; | ||
|
||
export default { | ||
...react, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@nextui-org/react"; | ||
|
||
function generateRows(count) { | ||
return Array.from({length: count}, (_, index) => ({ | ||
key: index.toString(), | ||
name: `Item ${index + 1}`, | ||
value: `Value ${index + 1}`, | ||
})); | ||
} | ||
|
||
export default function App() { | ||
const rows = generateRows(500); | ||
const columns = [ | ||
{key: "name", label: "Name"}, | ||
{key: "value", label: "Value"}, | ||
]; | ||
|
||
return ( | ||
<Table | ||
isVirtualized | ||
aria-label="Example of virtualized table with a large dataset" | ||
maxTableHeight={500} | ||
rowHeight={70} | ||
> | ||
<TableHeader columns={columns}> | ||
{(column) => <TableColumn key={column.key}>{column.label}</TableColumn>} | ||
</TableHeader> | ||
<TableBody items={rows}> | ||
{(item) => ( | ||
<TableRow key={item.key}> | ||
{(columnKey) => <TableCell>{item[columnKey]}</TableCell>} | ||
</TableRow> | ||
)} | ||
</TableBody> | ||
</Table> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import App from "./virtualization-custom-row-height.raw.jsx?raw"; | ||
|
||
const react = { | ||
"/App.jsx": App, | ||
}; | ||
|
||
export default { | ||
...react, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@nextui-org/react"; | ||
|
||
function generateRows(count) { | ||
return Array.from({length: count}, (_, index) => ({ | ||
key: index.toString(), | ||
name: `Item ${index + 1}`, | ||
value: `Value ${index + 1}`, | ||
})); | ||
} | ||
Comment on lines
+3
to
+9
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider memoizing row generation The +import {useMemo} from "react";
function generateRows(count) {
return Array.from({length: count}, (_, index) => ({
key: index.toString(),
name: `Item ${index + 1}`,
value: `Value ${index + 1}`,
}));
}
export default function App() {
- const rows = generateRows(10000);
+ const rows = useMemo(() => generateRows(10000), []);
|
||
|
||
export default function App() { | ||
const rows = generateRows(10000); | ||
const columns = [ | ||
{key: "name", label: "Name"}, | ||
{key: "value", label: "Value"}, | ||
]; | ||
|
||
return ( | ||
<Table | ||
isVirtualized | ||
aria-label="Example of virtualized table with a large dataset" | ||
maxTableHeight={500} | ||
rowHeight={40} | ||
> | ||
<TableHeader columns={columns}> | ||
{(column) => <TableColumn key={column.key}>{column.label}</TableColumn>} | ||
</TableHeader> | ||
<TableBody items={rows}> | ||
{(item) => ( | ||
<TableRow key={item.key}> | ||
{(columnKey) => <TableCell>{item[columnKey]}</TableCell>} | ||
</TableRow> | ||
)} | ||
</TableBody> | ||
</Table> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import App from "./virtualization-ten-thousand.raw.jsx?raw"; | ||
|
||
const react = { | ||
"/App.jsx": App, | ||
}; | ||
|
||
export default { | ||
...react, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import {Table, TableBody, TableCell, TableColumn, TableHeader, TableRow} from "@nextui-org/react"; | ||
|
||
function generateRows(count) { | ||
return Array.from({length: count}, (_, index) => ({ | ||
key: index.toString(), | ||
name: `Item ${index + 1}`, | ||
value: `Value ${index + 1}`, | ||
})); | ||
} | ||
|
||
export default function App() { | ||
const rows = generateRows(500); | ||
const columns = [ | ||
{key: "name", label: "Name"}, | ||
{key: "value", label: "Value"}, | ||
]; | ||
|
||
return ( | ||
<Table | ||
isVirtualized | ||
aria-label="Example of virtualized table with a large dataset" | ||
maxTableHeight={500} | ||
rowHeight={40} | ||
> | ||
Comment on lines
+19
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Enhance error handling and loading states The table implementation could benefit from additional error handling and loading states to improve user experience. <Table
isVirtualized
aria-label="Example of virtualized table with a large dataset"
maxTableHeight={500}
rowHeight={40}
+ loadingState={isLoading ? "loading" : "idle"}
+ loadingContent={<Spinner label="Loading..." />}
+ emptyContent={<div>No rows to display</div>}
>
|
||
<TableHeader columns={columns}> | ||
{(column) => <TableColumn key={column.key}>{column.label}</TableColumn>} | ||
</TableHeader> | ||
<TableBody items={rows}> | ||
{(item) => ( | ||
<TableRow key={item.key}> | ||
{(columnKey) => <TableCell>{item[columnKey]}</TableCell>} | ||
</TableRow> | ||
)} | ||
</TableBody> | ||
Comment on lines
+28
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Add aria-rowindex for better screen reader support When virtualizing table rows, it's important to maintain proper accessibility by indicating the absolute row position to screen readers. <TableBody items={rows}>
{(item) => (
- <TableRow key={item.key}>
+ <TableRow
+ key={item.key}
+ aria-rowindex={parseInt(item.key) + 2} // +2 to account for header row and 1-based indexing
+ >
{(columnKey) => <TableCell>{item[columnKey]}</TableCell>}
</TableRow>
)}
</TableBody> |
||
</Table> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import App from "./virtualization.raw.jsx?raw"; | ||
|
||
const react = { | ||
"/App.jsx": App, | ||
}; | ||
|
||
export default { | ||
...react, | ||
}; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -11,7 +11,7 @@ export interface TableRowGroupProps extends HTMLNextUIProps<"thead"> { | |||||
classNames?: ValuesType["classNames"]; | ||||||
} | ||||||
|
||||||
const TableRowGroup = forwardRef<"thead", TableRowGroupProps>((props, ref) => { | ||||||
const TableRowGroup = forwardRef<any, TableRowGroupProps>((props, ref) => { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Avoid using Changing the ref type from Apply this diff to restore type safety: - const TableRowGroup = forwardRef<any, TableRowGroupProps>((props, ref) => {
+ const TableRowGroup = forwardRef<HTMLTableSectionElement, TableRowGroupProps>((props, ref) => { 📝 Committable suggestion
Suggested change
|
||||||
const {as, className, children, slots, classNames, ...otherProps} = props; | ||||||
|
||||||
const Component = as || "thead"; | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Extract generateRows to a shared utility file
This helper function is duplicated across multiple example files. Consider moving it to a shared utility file to improve maintainability.
Create a new file
apps/docs/content/components/table/utils.js
:Then import it in each example file: