diff --git a/apps/docs/content/components/table/async-pagination.raw.jsx b/apps/docs/content/components/table/async-pagination.raw.jsx
new file mode 100644
index 0000000000..266a97e842
--- /dev/null
+++ b/apps/docs/content/components/table/async-pagination.raw.jsx
@@ -0,0 +1,69 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ Pagination,
+ Spinner,
+ getKeyValue,
+} from "@nextui-org/react";
+import useSWR from "swr";
+
+const fetcher = (...args) => fetch(...args).then((res) => res.json());
+
+export default function App() {
+ const [page, setPage] = React.useState(1);
+
+ const {data, isLoading} = useSWR(`https://swapi.py4e.com/api/people?page=${page}`, fetcher, {
+ keepPreviousData: true,
+ });
+
+ const rowsPerPage = 10;
+
+ const pages = React.useMemo(() => {
+ return data?.count ? Math.ceil(data.count / rowsPerPage) : 0;
+ }, [data?.count, rowsPerPage]);
+
+ const loadingState = isLoading || data?.results.length === 0 ? "loading" : "idle";
+
+ return (
+
0 ? (
+
+ ) : null
+ }
+ >
+
+ Name
+ Height
+ Mass
+ Birth year
+
+ }
+ loadingState={loadingState}
+ >
+ {(item) => (
+
+ {(columnKey) => {getKeyValue(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/async-pagination.ts b/apps/docs/content/components/table/async-pagination.ts
index f5c51a3c4f..f59ac27a4c 100644
--- a/apps/docs/content/components/table/async-pagination.ts
+++ b/apps/docs/content/components/table/async-pagination.ts
@@ -1,62 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Pagination, Spinner, getKeyValue} from "@nextui-org/react";
-import useSWR from "swr";
-
-const fetcher = (...args) => fetch(...args).then((res) => res.json());
-
-export default function App() {
- const [page, setPage] = React.useState(1);
-
- const {data, isLoading} = useSWR(\`https://swapi.py4e.com/api/people?page=\$\{page\}\`, fetcher, {
- keepPreviousData: true,
- });
-
- const rowsPerPage = 10;
-
- const pages = React.useMemo(() => {
- return data?.count ? Math.ceil(data.count / rowsPerPage) : 0;
- }, [data?.count, rowsPerPage]);
-
- const loadingState = isLoading || data?.results.length === 0 ? "loading" : "idle";
-
- return (
- 0 ? (
-
- ) : null
- }
- >
-
- Name
- Height
- Mass
- Birth year
-
- }
- loadingState={loadingState}
- >
- {(item) => (
-
- {(columnKey) => {getKeyValue(item, columnKey)}}
-
- )}
-
-
- );
-}`;
+import App from "./async-pagination.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/controlled-selection.raw.jsx b/apps/docs/content/components/table/controlled-selection.raw.jsx
new file mode 100644
index 0000000000..3ee296f7b1
--- /dev/null
+++ b/apps/docs/content/components/table/controlled-selection.raw.jsx
@@ -0,0 +1,75 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ getKeyValue,
+} from "@nextui-org/react";
+
+const rows = [
+ {
+ key: "1",
+ name: "Tony Reichert",
+ role: "CEO",
+ status: "Active",
+ },
+ {
+ key: "2",
+ name: "Zoey Lang",
+ role: "Technical Lead",
+ status: "Paused",
+ },
+ {
+ key: "3",
+ name: "Jane Fisher",
+ role: "Senior Developer",
+ status: "Active",
+ },
+ {
+ key: "4",
+ name: "William Howard",
+ role: "Community Manager",
+ status: "Vacation",
+ },
+];
+
+const columns = [
+ {
+ key: "name",
+ label: "NAME",
+ },
+ {
+ key: "role",
+ label: "ROLE",
+ },
+ {
+ key: "status",
+ label: "STATUS",
+ },
+];
+
+export default function App() {
+ const [selectedKeys, setSelectedKeys] = React.useState(new Set(["2"]));
+
+ return (
+
+
+ {(column) => {column.label}}
+
+
+ {(item) => (
+
+ {(columnKey) => {getKeyValue(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/controlled-selection.ts b/apps/docs/content/components/table/controlled-selection.ts
index 0a54c2bd26..b141b81895 100644
--- a/apps/docs/content/components/table/controlled-selection.ts
+++ b/apps/docs/content/components/table/controlled-selection.ts
@@ -1,70 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue} from "@nextui-org/react";
-
-const rows = [
- {
- key: "1",
- name: "Tony Reichert",
- role: "CEO",
- status: "Active",
- },
- {
- key: "2",
- name: "Zoey Lang",
- role: "Technical Lead",
- status: "Paused",
- },
- {
- key: "3",
- name: "Jane Fisher",
- role: "Senior Developer",
- status: "Active",
- },
- {
- key: "4",
- name: "William Howard",
- role: "Community Manager",
- status: "Vacation",
- },
-];
-
-const columns = [
- {
- key: "name",
- label: "NAME",
- },
- {
- key: "role",
- label: "ROLE",
- },
- {
- key: "status",
- label: "STATUS",
- },
-];
-
-export default function App() {
- const [selectedKeys, setSelectedKeys] = React.useState(new Set(["2"]));
-
- return (
-
-
- {(column) => {column.label}}
-
-
- {(item) => (
-
- {(columnKey) => {getKeyValue(item, columnKey)}}
-
- )}
-
-
- );
-}`;
+import App from "./controlled-selection.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/custom-cells.raw.jsx b/apps/docs/content/components/table/custom-cells.raw.jsx
new file mode 100644
index 0000000000..e29158daeb
--- /dev/null
+++ b/apps/docs/content/components/table/custom-cells.raw.jsx
@@ -0,0 +1,271 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ User,
+ Chip,
+ Tooltip,
+} from "@nextui-org/react";
+
+export const columns = [
+ {name: "NAME", uid: "name"},
+ {name: "ROLE", uid: "role"},
+ {name: "STATUS", uid: "status"},
+ {name: "ACTIONS", uid: "actions"},
+];
+
+export const users = [
+ {
+ id: 1,
+ name: "Tony Reichert",
+ role: "CEO",
+ team: "Management",
+ status: "active",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
+ email: "tony.reichert@example.com",
+ },
+ {
+ id: 2,
+ name: "Zoey Lang",
+ role: "Technical Lead",
+ team: "Development",
+ status: "paused",
+ age: "25",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
+ email: "zoey.lang@example.com",
+ },
+ {
+ id: 3,
+ name: "Jane Fisher",
+ role: "Senior Developer",
+ team: "Development",
+ status: "active",
+ age: "22",
+ avatar: "https://i.pravatar.cc/150?u=a04258114e29026702d",
+ email: "jane.fisher@example.com",
+ },
+ {
+ id: 4,
+ name: "William Howard",
+ role: "Community Manager",
+ team: "Marketing",
+ status: "vacation",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?u=a048581f4e29026701d",
+ email: "william.howard@example.com",
+ },
+ {
+ id: 5,
+ name: "Kristen Copper",
+ role: "Sales Manager",
+ team: "Sales",
+ status: "active",
+ age: "24",
+ avatar: "https://i.pravatar.cc/150?u=a092581d4ef9026700d",
+ email: "kristen.cooper@example.com",
+ },
+];
+
+export const EyeIcon = (props) => {
+ return (
+
+ );
+};
+
+export const DeleteIcon = (props) => {
+ return (
+
+ );
+};
+
+export const EditIcon = (props) => {
+ return (
+
+ );
+};
+
+const statusColorMap = {
+ active: "success",
+ paused: "danger",
+ vacation: "warning",
+};
+
+export default function App() {
+ const renderCell = React.useCallback((user, columnKey) => {
+ const cellValue = user[columnKey];
+
+ switch (columnKey) {
+ case "name":
+ return (
+
+ {user.email}
+
+ );
+ case "role":
+ return (
+
+
{cellValue}
+
{user.team}
+
+ );
+ case "status":
+ return (
+
+ {cellValue}
+
+ );
+ case "actions":
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ default:
+ return cellValue;
+ }
+ }, []);
+
+ return (
+
+
+ {(column) => (
+
+ {column.name}
+
+ )}
+
+
+ {(item) => (
+
+ {(columnKey) => {renderCell(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/custom-cells.raw.tsx b/apps/docs/content/components/table/custom-cells.raw.tsx
new file mode 100644
index 0000000000..46ff88e48c
--- /dev/null
+++ b/apps/docs/content/components/table/custom-cells.raw.tsx
@@ -0,0 +1,278 @@
+import React, {SVGProps} from "react";
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ User,
+ Chip,
+ Tooltip,
+ ChipProps,
+} from "@nextui-org/react";
+
+export type IconSvgProps = SVGProps & {
+ size?: number;
+};
+
+export const columns = [
+ {name: "NAME", uid: "name"},
+ {name: "ROLE", uid: "role"},
+ {name: "STATUS", uid: "status"},
+ {name: "ACTIONS", uid: "actions"},
+];
+
+export const users = [
+ {
+ id: 1,
+ name: "Tony Reichert",
+ role: "CEO",
+ team: "Management",
+ status: "active",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
+ email: "tony.reichert@example.com",
+ },
+ {
+ id: 2,
+ name: "Zoey Lang",
+ role: "Technical Lead",
+ team: "Development",
+ status: "paused",
+ age: "25",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
+ email: "zoey.lang@example.com",
+ },
+ {
+ id: 3,
+ name: "Jane Fisher",
+ role: "Senior Developer",
+ team: "Development",
+ status: "active",
+ age: "22",
+ avatar: "https://i.pravatar.cc/150?u=a04258114e29026702d",
+ email: "jane.fisher@example.com",
+ },
+ {
+ id: 4,
+ name: "William Howard",
+ role: "Community Manager",
+ team: "Marketing",
+ status: "vacation",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?u=a048581f4e29026701d",
+ email: "william.howard@example.com",
+ },
+ {
+ id: 5,
+ name: "Kristen Copper",
+ role: "Sales Manager",
+ team: "Sales",
+ status: "active",
+ age: "24",
+ avatar: "https://i.pravatar.cc/150?u=a092581d4ef9026700d",
+ email: "kristen.cooper@example.com",
+ },
+];
+
+export const EyeIcon = (props: IconSvgProps) => {
+ return (
+
+ );
+};
+
+export const DeleteIcon = (props: IconSvgProps) => {
+ return (
+
+ );
+};
+
+export const EditIcon = (props: IconSvgProps) => {
+ return (
+
+ );
+};
+const statusColorMap: Record = {
+ active: "success",
+ paused: "danger",
+ vacation: "warning",
+};
+
+type User = (typeof users)[0];
+
+export default function App() {
+ const renderCell = React.useCallback((user: User, columnKey: React.Key) => {
+ const cellValue = user[columnKey as keyof User];
+
+ switch (columnKey) {
+ case "name":
+ return (
+
+ {user.email}
+
+ );
+ case "role":
+ return (
+
+
{cellValue}
+
{user.team}
+
+ );
+ case "status":
+ return (
+
+ {cellValue}
+
+ );
+ case "actions":
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+ default:
+ return cellValue;
+ }
+ }, []);
+
+ return (
+
+
+ {(column) => (
+
+ {column.name}
+
+ )}
+
+
+ {(item) => (
+
+ {(columnKey) => {renderCell(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/custom-cells.ts b/apps/docs/content/components/table/custom-cells.ts
index 92680efd5f..9b7f207298 100644
--- a/apps/docs/content/components/table/custom-cells.ts
+++ b/apps/docs/content/components/table/custom-cells.ts
@@ -1,366 +1,12 @@
-const data = `const columns = [
- {name: "NAME", uid: "name"},
- {name: "ROLE", uid: "role"},
- {name: "STATUS", uid: "status"},
- {name: "ACTIONS", uid: "actions"},
-];
-
-const users = [
- {
- id: 1,
- name: "Tony Reichert",
- role: "CEO",
- team: "Management",
- status: "active",
- age: "29",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
- email: "tony.reichert@example.com",
- },
- {
- id: 2,
- name: "Zoey Lang",
- role: "Technical Lead",
- team: "Development",
- status: "paused",
- age: "25",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
- email: "zoey.lang@example.com",
- },
- {
- id: 3,
- name: "Jane Fisher",
- role: "Senior Developer",
- team: "Development",
- status: "active",
- age: "22",
- avatar: "https://i.pravatar.cc/150?u=a04258114e29026702d",
- email: "jane.fisher@example.com",
- },
- {
- id: 4,
- name: "William Howard",
- role: "Community Manager",
- team: "Marketing",
- status: "vacation",
- age: "28",
- avatar: "https://i.pravatar.cc/150?u=a048581f4e29026701d",
- email: "william.howard@example.com",
- },
- {
- id: 5,
- name: "Kristen Copper",
- role: "Sales Manager",
- team: "Sales",
- status: "active",
- age: "24",
- avatar: "https://i.pravatar.cc/150?u=a092581d4ef9026700d",
- email: "kristen.cooper@example.com",
- },
-];
-
-export {columns, users};`;
-
-const EyeIcon = `export const EyeIcon = (props) => (
-
-);`;
-
-const DeleteIcon = `export const DeleteIcon = (props) => (
-
-);`;
-
-const EditIcon = `export const EditIcon = (props) => (
-
-);`;
-
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, User, Chip, Tooltip, getKeyValue} from "@nextui-org/react";
-import {EditIcon} from "./EditIcon";
-import {DeleteIcon} from "./DeleteIcon";
-import {EyeIcon} from "./EyeIcon";
-import {columns, users} from "./data";
-
-const statusColorMap = {
- active: "success",
- paused: "danger",
- vacation: "warning",
-};
-
-export default function App() {
- const renderCell = React.useCallback((user, columnKey) => {
- const cellValue = user[columnKey];
-
- switch (columnKey) {
- case "name":
- return (
-
- {user.email}
-
- );
- case "role":
- return (
-
-
{cellValue}
-
{user.team}
-
- );
- case "status":
- return (
-
- {cellValue}
-
- );
- case "actions":
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- default:
- return cellValue;
- }
- }, []);
-
- return (
-
-
- {(column) => (
-
- {column.name}
-
- )}
-
-
- {(item) => (
-
- {(columnKey) => {renderCell(item, columnKey)}}
-
- )}
-
-
- );
-}`;
-
-const AppTs = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, User, Chip, Tooltip, ChipProps, getKeyValue} from "@nextui-org/react";
-import {EditIcon} from "./EditIcon";
-import {DeleteIcon} from "./DeleteIcon";
-import {EyeIcon} from "./EyeIcon";
-import {columns, users} from "./data";
-
-const statusColorMap: Record = {
- active: "success",
- paused: "danger",
- vacation: "warning",
-};
-
-type User = typeof users[0];
-
-export default function App() {
- const renderCell = React.useCallback((user: User, columnKey: React.Key) => {
- const cellValue = user[columnKey as keyof User];
-
- switch (columnKey) {
- case "name":
- return (
-
- {user.email}
-
- );
- case "role":
- return (
-
-
{cellValue}
-
{user.team}
-
- );
- case "status":
- return (
-
- {cellValue}
-
- );
- case "actions":
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
- default:
- return cellValue;
- }
- }, []);
-
- return (
-
-
- {(column) => (
-
- {column.name}
-
- )}
-
-
- {(item) => (
-
- {(columnKey) => {renderCell(item, columnKey)}}
-
- )}
-
-
- );
-}`;
+import App from "./custom-cells.raw.jsx?raw";
+import AppTs from "./custom-cells.raw.tsx?raw";
const react = {
"/App.jsx": App,
- "/data.js": data,
- "/EditIcon.jsx": EditIcon,
- "/DeleteIcon.jsx": DeleteIcon,
- "/EyeIcon.jsx": EyeIcon,
};
const reactTs = {
"/App.tsx": AppTs,
- "/data.js": data,
- "/EditIcon.jsx": EditIcon,
- "/DeleteIcon.jsx": DeleteIcon,
- "/EyeIcon.jsx": EyeIcon,
};
export default {
diff --git a/apps/docs/content/components/table/custom-styles.raw.jsx b/apps/docs/content/components/table/custom-styles.raw.jsx
new file mode 100644
index 0000000000..f00049bb6f
--- /dev/null
+++ b/apps/docs/content/components/table/custom-styles.raw.jsx
@@ -0,0 +1,662 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ Input,
+ Button,
+ DropdownTrigger,
+ Dropdown,
+ DropdownMenu,
+ DropdownItem,
+ Chip,
+ User,
+ Pagination,
+} from "@nextui-org/react";
+
+export const columns = [
+ {name: "ID", uid: "id", sortable: true},
+ {name: "NAME", uid: "name", sortable: true},
+ {name: "AGE", uid: "age", sortable: true},
+ {name: "ROLE", uid: "role", sortable: true},
+ {name: "TEAM", uid: "team"},
+ {name: "EMAIL", uid: "email"},
+ {name: "STATUS", uid: "status", sortable: true},
+ {name: "ACTIONS", uid: "actions"},
+];
+
+export const statusOptions = [
+ {name: "Active", uid: "active"},
+ {name: "Paused", uid: "paused"},
+ {name: "Vacation", uid: "vacation"},
+];
+
+export const users = [
+ {
+ id: 1,
+ name: "Tony Reichert",
+ role: "CEO",
+ team: "Management",
+ status: "active",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
+ email: "tony.reichert@example.com",
+ },
+ {
+ id: 2,
+ name: "Zoey Lang",
+ role: "Tech Lead",
+ team: "Development",
+ status: "paused",
+ age: "25",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
+ email: "zoey.lang@example.com",
+ },
+ {
+ id: 3,
+ name: "Jane Fisher",
+ role: "Sr. Dev",
+ team: "Development",
+ status: "active",
+ age: "22",
+ avatar: "https://i.pravatar.cc/150?u=a04258114e29026702d",
+ email: "jane.fisher@example.com",
+ },
+ {
+ id: 4,
+ name: "William Howard",
+ role: "C.M.",
+ team: "Marketing",
+ status: "vacation",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?u=a048581f4e29026701d",
+ email: "william.howard@example.com",
+ },
+ {
+ id: 5,
+ name: "Kristen Copper",
+ role: "S. Manager",
+ team: "Sales",
+ status: "active",
+ age: "24",
+ avatar: "https://i.pravatar.cc/150?u=a092581d4ef9026700d",
+ email: "kristen.cooper@example.com",
+ },
+ {
+ id: 6,
+ name: "Brian Kim",
+ role: "P. Manager",
+ team: "Management",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
+ email: "brian.kim@example.com",
+ status: "active",
+ },
+ {
+ id: 7,
+ name: "Michael Hunt",
+ role: "Designer",
+ team: "Design",
+ status: "paused",
+ age: "27",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29027007d",
+ email: "michael.hunt@example.com",
+ },
+ {
+ id: 8,
+ name: "Samantha Brooks",
+ role: "HR Manager",
+ team: "HR",
+ status: "active",
+ age: "31",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e27027008d",
+ email: "samantha.brooks@example.com",
+ },
+ {
+ id: 9,
+ name: "Frank Harrison",
+ role: "F. Manager",
+ team: "Finance",
+ status: "vacation",
+ age: "33",
+ avatar: "https://i.pravatar.cc/150?img=4",
+ email: "frank.harrison@example.com",
+ },
+ {
+ id: 10,
+ name: "Emma Adams",
+ role: "Ops Manager",
+ team: "Operations",
+ status: "active",
+ age: "35",
+ avatar: "https://i.pravatar.cc/150?img=5",
+ email: "emma.adams@example.com",
+ },
+ {
+ id: 11,
+ name: "Brandon Stevens",
+ role: "Jr. Dev",
+ team: "Development",
+ status: "active",
+ age: "22",
+ avatar: "https://i.pravatar.cc/150?img=8",
+ email: "brandon.stevens@example.com",
+ },
+ {
+ id: 12,
+ name: "Megan Richards",
+ role: "P. Manager",
+ team: "Product",
+ status: "paused",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?img=10",
+ email: "megan.richards@example.com",
+ },
+ {
+ id: 13,
+ name: "Oliver Scott",
+ role: "S. Manager",
+ team: "Security",
+ status: "active",
+ age: "37",
+ avatar: "https://i.pravatar.cc/150?img=12",
+ email: "oliver.scott@example.com",
+ },
+ {
+ id: 14,
+ name: "Grace Allen",
+ role: "M. Specialist",
+ team: "Marketing",
+ status: "active",
+ age: "30",
+ avatar: "https://i.pravatar.cc/150?img=16",
+ email: "grace.allen@example.com",
+ },
+ {
+ id: 15,
+ name: "Noah Carter",
+ role: "IT Specialist",
+ team: "I. Technology",
+ status: "paused",
+ age: "31",
+ avatar: "https://i.pravatar.cc/150?img=15",
+ email: "noah.carter@example.com",
+ },
+ {
+ id: 16,
+ name: "Ava Perez",
+ role: "Manager",
+ team: "Sales",
+ status: "active",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?img=20",
+ email: "ava.perez@example.com",
+ },
+ {
+ id: 17,
+ name: "Liam Johnson",
+ role: "Data Analyst",
+ team: "Analysis",
+ status: "active",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?img=33",
+ email: "liam.johnson@example.com",
+ },
+ {
+ id: 18,
+ name: "Sophia Taylor",
+ role: "QA Analyst",
+ team: "Testing",
+ status: "active",
+ age: "27",
+ avatar: "https://i.pravatar.cc/150?img=29",
+ email: "sophia.taylor@example.com",
+ },
+ {
+ id: 19,
+ name: "Lucas Harris",
+ role: "Administrator",
+ team: "Information Technology",
+ status: "paused",
+ age: "32",
+ avatar: "https://i.pravatar.cc/150?img=50",
+ email: "lucas.harris@example.com",
+ },
+ {
+ id: 20,
+ name: "Mia Robinson",
+ role: "Coordinator",
+ team: "Operations",
+ status: "active",
+ age: "26",
+ avatar: "https://i.pravatar.cc/150?img=45",
+ email: "mia.robinson@example.com",
+ },
+];
+
+export function capitalize(s) {
+ return s ? s.charAt(0).toUpperCase() + s.slice(1).toLowerCase() : "";
+}
+
+export const PlusIcon = ({size = 24, width, height, ...props}) => {
+ return (
+
+ );
+};
+
+export const VerticalDotsIcon = ({size = 24, width, height, ...props}) => {
+ return (
+
+ );
+};
+
+export const SearchIcon = (props) => {
+ return (
+
+ );
+};
+
+export const ChevronDownIcon = ({strokeWidth = 1.5, ...otherProps}) => {
+ return (
+
+ );
+};
+
+const statusColorMap = {
+ active: "success",
+ paused: "danger",
+ vacation: "warning",
+};
+
+const INITIAL_VISIBLE_COLUMNS = ["name", "role", "status", "actions"];
+
+export default function App() {
+ const [filterValue, setFilterValue] = React.useState("");
+ const [selectedKeys, setSelectedKeys] = React.useState(new Set([]));
+ const [visibleColumns, setVisibleColumns] = React.useState(new Set(INITIAL_VISIBLE_COLUMNS));
+ const [statusFilter, setStatusFilter] = React.useState("all");
+ const [rowsPerPage, setRowsPerPage] = React.useState(5);
+ const [sortDescriptor, setSortDescriptor] = React.useState({
+ column: "age",
+ direction: "ascending",
+ });
+ const [page, setPage] = React.useState(1);
+
+ const pages = Math.ceil(users.length / rowsPerPage);
+
+ const hasSearchFilter = Boolean(filterValue);
+
+ const headerColumns = React.useMemo(() => {
+ if (visibleColumns === "all") return columns;
+
+ return columns.filter((column) => Array.from(visibleColumns).includes(column.uid));
+ }, [visibleColumns]);
+
+ const filteredItems = React.useMemo(() => {
+ let filteredUsers = [...users];
+
+ if (hasSearchFilter) {
+ filteredUsers = filteredUsers.filter((user) =>
+ user.name.toLowerCase().includes(filterValue.toLowerCase()),
+ );
+ }
+ if (statusFilter !== "all" && Array.from(statusFilter).length !== statusOptions.length) {
+ filteredUsers = filteredUsers.filter((user) =>
+ Array.from(statusFilter).includes(user.status),
+ );
+ }
+
+ return filteredUsers;
+ }, [users, filterValue, statusFilter]);
+
+ const items = React.useMemo(() => {
+ const start = (page - 1) * rowsPerPage;
+ const end = start + rowsPerPage;
+
+ return filteredItems.slice(start, end);
+ }, [page, filteredItems, rowsPerPage]);
+
+ const sortedItems = React.useMemo(() => {
+ return [...items].sort((a, b) => {
+ const first = a[sortDescriptor.column];
+ const second = b[sortDescriptor.column];
+ const cmp = first < second ? -1 : first > second ? 1 : 0;
+
+ return sortDescriptor.direction === "descending" ? -cmp : cmp;
+ });
+ }, [sortDescriptor, items]);
+
+ const renderCell = React.useCallback((user, columnKey) => {
+ const cellValue = user[columnKey];
+
+ switch (columnKey) {
+ case "name":
+ return (
+
+ {user.email}
+
+ );
+ case "role":
+ return (
+
+
{cellValue}
+
{user.team}
+
+ );
+ case "status":
+ return (
+
+ {cellValue}
+
+ );
+ case "actions":
+ return (
+
+
+
+
+
+
+ View
+ Edit
+ Delete
+
+
+
+ );
+ default:
+ return cellValue;
+ }
+ }, []);
+
+ const onRowsPerPageChange = React.useCallback((e) => {
+ setRowsPerPage(Number(e.target.value));
+ setPage(1);
+ }, []);
+
+ const onSearchChange = React.useCallback((value) => {
+ if (value) {
+ setFilterValue(value);
+ setPage(1);
+ } else {
+ setFilterValue("");
+ }
+ }, []);
+
+ const topContent = React.useMemo(() => {
+ return (
+
+
+
}
+ value={filterValue}
+ variant="bordered"
+ onClear={() => setFilterValue("")}
+ onValueChange={onSearchChange}
+ />
+
+
+
+ }
+ size="sm"
+ variant="flat"
+ >
+ Status
+
+
+
+ {statusOptions.map((status) => (
+
+ {capitalize(status.name)}
+
+ ))}
+
+
+
+
+ }
+ size="sm"
+ variant="flat"
+ >
+ Columns
+
+
+
+ {columns.map((column) => (
+
+ {capitalize(column.name)}
+
+ ))}
+
+
+ } size="sm">
+ Add New
+
+
+
+
+ Total {users.length} users
+
+
+
+ );
+ }, [
+ filterValue,
+ statusFilter,
+ visibleColumns,
+ onSearchChange,
+ onRowsPerPageChange,
+ users.length,
+ hasSearchFilter,
+ ]);
+
+ const bottomContent = React.useMemo(() => {
+ return (
+
+
+
+ {selectedKeys === "all"
+ ? "All items selected"
+ : `${selectedKeys.size} of ${items.length} selected`}
+
+
+ );
+ }, [selectedKeys, items.length, page, pages, hasSearchFilter]);
+
+ const classNames = React.useMemo(
+ () => ({
+ wrapper: ["max-h-[382px]", "max-w-3xl"],
+ th: ["bg-transparent", "text-default-500", "border-b", "border-divider"],
+ td: [
+ // changing the rows border radius
+ // first
+ "group-data-[first=true]/tr:first:before:rounded-none",
+ "group-data-[first=true]/tr:last:before:rounded-none",
+ // middle
+ "group-data-[middle=true]/tr:before:rounded-none",
+ // last
+ "group-data-[last=true]/tr:first:before:rounded-none",
+ "group-data-[last=true]/tr:last:before:rounded-none",
+ ],
+ }),
+ [],
+ );
+
+ return (
+
+
+ {(column) => (
+
+ {column.name}
+
+ )}
+
+
+ {(item) => (
+
+ {(columnKey) => {renderCell(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/custom-styles.raw.tsx b/apps/docs/content/components/table/custom-styles.raw.tsx
new file mode 100644
index 0000000000..4529846f56
--- /dev/null
+++ b/apps/docs/content/components/table/custom-styles.raw.tsx
@@ -0,0 +1,674 @@
+import React, {SVGProps} from "react";
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ Input,
+ Button,
+ DropdownTrigger,
+ Dropdown,
+ DropdownMenu,
+ DropdownItem,
+ Chip,
+ User,
+ Pagination,
+ Selection,
+ ChipProps,
+ SortDescriptor,
+} from "@nextui-org/react";
+
+export type IconSvgProps = SVGProps & {
+ size?: number;
+};
+
+export const columns = [
+ {name: "ID", uid: "id", sortable: true},
+ {name: "NAME", uid: "name", sortable: true},
+ {name: "AGE", uid: "age", sortable: true},
+ {name: "ROLE", uid: "role", sortable: true},
+ {name: "TEAM", uid: "team"},
+ {name: "EMAIL", uid: "email"},
+ {name: "STATUS", uid: "status", sortable: true},
+ {name: "ACTIONS", uid: "actions"},
+];
+
+export const statusOptions = [
+ {name: "Active", uid: "active"},
+ {name: "Paused", uid: "paused"},
+ {name: "Vacation", uid: "vacation"},
+];
+
+export const users = [
+ {
+ id: 1,
+ name: "Tony Reichert",
+ role: "CEO",
+ team: "Management",
+ status: "active",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
+ email: "tony.reichert@example.com",
+ },
+ {
+ id: 2,
+ name: "Zoey Lang",
+ role: "Tech Lead",
+ team: "Development",
+ status: "paused",
+ age: "25",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
+ email: "zoey.lang@example.com",
+ },
+ {
+ id: 3,
+ name: "Jane Fisher",
+ role: "Sr. Dev",
+ team: "Development",
+ status: "active",
+ age: "22",
+ avatar: "https://i.pravatar.cc/150?u=a04258114e29026702d",
+ email: "jane.fisher@example.com",
+ },
+ {
+ id: 4,
+ name: "William Howard",
+ role: "C.M.",
+ team: "Marketing",
+ status: "vacation",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?u=a048581f4e29026701d",
+ email: "william.howard@example.com",
+ },
+ {
+ id: 5,
+ name: "Kristen Copper",
+ role: "S. Manager",
+ team: "Sales",
+ status: "active",
+ age: "24",
+ avatar: "https://i.pravatar.cc/150?u=a092581d4ef9026700d",
+ email: "kristen.cooper@example.com",
+ },
+ {
+ id: 6,
+ name: "Brian Kim",
+ role: "P. Manager",
+ team: "Management",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
+ email: "brian.kim@example.com",
+ status: "active",
+ },
+ {
+ id: 7,
+ name: "Michael Hunt",
+ role: "Designer",
+ team: "Design",
+ status: "paused",
+ age: "27",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29027007d",
+ email: "michael.hunt@example.com",
+ },
+ {
+ id: 8,
+ name: "Samantha Brooks",
+ role: "HR Manager",
+ team: "HR",
+ status: "active",
+ age: "31",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e27027008d",
+ email: "samantha.brooks@example.com",
+ },
+ {
+ id: 9,
+ name: "Frank Harrison",
+ role: "F. Manager",
+ team: "Finance",
+ status: "vacation",
+ age: "33",
+ avatar: "https://i.pravatar.cc/150?img=4",
+ email: "frank.harrison@example.com",
+ },
+ {
+ id: 10,
+ name: "Emma Adams",
+ role: "Ops Manager",
+ team: "Operations",
+ status: "active",
+ age: "35",
+ avatar: "https://i.pravatar.cc/150?img=5",
+ email: "emma.adams@example.com",
+ },
+ {
+ id: 11,
+ name: "Brandon Stevens",
+ role: "Jr. Dev",
+ team: "Development",
+ status: "active",
+ age: "22",
+ avatar: "https://i.pravatar.cc/150?img=8",
+ email: "brandon.stevens@example.com",
+ },
+ {
+ id: 12,
+ name: "Megan Richards",
+ role: "P. Manager",
+ team: "Product",
+ status: "paused",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?img=10",
+ email: "megan.richards@example.com",
+ },
+ {
+ id: 13,
+ name: "Oliver Scott",
+ role: "S. Manager",
+ team: "Security",
+ status: "active",
+ age: "37",
+ avatar: "https://i.pravatar.cc/150?img=12",
+ email: "oliver.scott@example.com",
+ },
+ {
+ id: 14,
+ name: "Grace Allen",
+ role: "M. Specialist",
+ team: "Marketing",
+ status: "active",
+ age: "30",
+ avatar: "https://i.pravatar.cc/150?img=16",
+ email: "grace.allen@example.com",
+ },
+ {
+ id: 15,
+ name: "Noah Carter",
+ role: "IT Specialist",
+ team: "I. Technology",
+ status: "paused",
+ age: "31",
+ avatar: "https://i.pravatar.cc/150?img=15",
+ email: "noah.carter@example.com",
+ },
+ {
+ id: 16,
+ name: "Ava Perez",
+ role: "Manager",
+ team: "Sales",
+ status: "active",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?img=20",
+ email: "ava.perez@example.com",
+ },
+ {
+ id: 17,
+ name: "Liam Johnson",
+ role: "Data Analyst",
+ team: "Analysis",
+ status: "active",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?img=33",
+ email: "liam.johnson@example.com",
+ },
+ {
+ id: 18,
+ name: "Sophia Taylor",
+ role: "QA Analyst",
+ team: "Testing",
+ status: "active",
+ age: "27",
+ avatar: "https://i.pravatar.cc/150?img=29",
+ email: "sophia.taylor@example.com",
+ },
+ {
+ id: 19,
+ name: "Lucas Harris",
+ role: "Administrator",
+ team: "Information Technology",
+ status: "paused",
+ age: "32",
+ avatar: "https://i.pravatar.cc/150?img=50",
+ email: "lucas.harris@example.com",
+ },
+ {
+ id: 20,
+ name: "Mia Robinson",
+ role: "Coordinator",
+ team: "Operations",
+ status: "active",
+ age: "26",
+ avatar: "https://i.pravatar.cc/150?img=45",
+ email: "mia.robinson@example.com",
+ },
+];
+
+export function capitalize(s) {
+ return s ? s.charAt(0).toUpperCase() + s.slice(1).toLowerCase() : "";
+}
+
+export const PlusIcon = ({size = 24, width, height, ...props}: IconSvgProps) => {
+ return (
+
+ );
+};
+
+export const VerticalDotsIcon = ({size = 24, width, height, ...props}: IconSvgProps) => {
+ return (
+
+ );
+};
+
+export const SearchIcon = (props: IconSvgProps) => {
+ return (
+
+ );
+};
+
+export const ChevronDownIcon = ({strokeWidth = 1.5, ...otherProps}: IconSvgProps) => {
+ return (
+
+ );
+};
+
+const statusColorMap: Record = {
+ active: "success",
+ paused: "danger",
+ vacation: "warning",
+};
+
+const INITIAL_VISIBLE_COLUMNS = ["name", "role", "status", "actions"];
+
+type User = (typeof users)[0];
+
+export default function App() {
+ const [filterValue, setFilterValue] = React.useState("");
+ const [selectedKeys, setSelectedKeys] = React.useState(new Set([]));
+ const [visibleColumns, setVisibleColumns] = React.useState(
+ new Set(INITIAL_VISIBLE_COLUMNS),
+ );
+ const [statusFilter, setStatusFilter] = React.useState("all");
+ const [rowsPerPage, setRowsPerPage] = React.useState(5);
+ const [sortDescriptor, setSortDescriptor] = React.useState({
+ column: "age",
+ direction: "ascending",
+ });
+ const [page, setPage] = React.useState(1);
+
+ const pages = Math.ceil(users.length / rowsPerPage);
+
+ const hasSearchFilter = Boolean(filterValue);
+
+ const headerColumns = React.useMemo(() => {
+ if (visibleColumns === "all") return columns;
+
+ return columns.filter((column) => Array.from(visibleColumns).includes(column.uid));
+ }, [visibleColumns]);
+
+ const filteredItems = React.useMemo(() => {
+ let filteredUsers = [...users];
+
+ if (hasSearchFilter) {
+ filteredUsers = filteredUsers.filter((user) =>
+ user.name.toLowerCase().includes(filterValue.toLowerCase()),
+ );
+ }
+ if (statusFilter !== "all" && Array.from(statusFilter).length !== statusOptions.length) {
+ filteredUsers = filteredUsers.filter((user) =>
+ Array.from(statusFilter).includes(user.status),
+ );
+ }
+
+ return filteredUsers;
+ }, [users, filterValue, statusFilter]);
+
+ const items = React.useMemo(() => {
+ const start = (page - 1) * rowsPerPage;
+ const end = start + rowsPerPage;
+
+ return filteredItems.slice(start, end);
+ }, [page, filteredItems, rowsPerPage]);
+
+ const sortedItems = React.useMemo(() => {
+ return [...items].sort((a: User, b: User) => {
+ const first = a[sortDescriptor.column as keyof User] as number;
+ const second = b[sortDescriptor.column as keyof User] as number;
+ const cmp = first < second ? -1 : first > second ? 1 : 0;
+
+ return sortDescriptor.direction === "descending" ? -cmp : cmp;
+ });
+ }, [sortDescriptor, items]);
+
+ const renderCell = React.useCallback((user: User, columnKey: React.Key) => {
+ const cellValue = user[columnKey as keyof User];
+
+ switch (columnKey) {
+ case "name":
+ return (
+
+ {user.email}
+
+ );
+ case "role":
+ return (
+
+
{cellValue}
+
{user.team}
+
+ );
+ case "status":
+ return (
+
+ {cellValue}
+
+ );
+ case "actions":
+ return (
+
+
+
+
+
+
+ View
+ Edit
+ Delete
+
+
+
+ );
+ default:
+ return cellValue;
+ }
+ }, []);
+
+ const onRowsPerPageChange = React.useCallback((e: React.ChangeEvent) => {
+ setRowsPerPage(Number(e.target.value));
+ setPage(1);
+ }, []);
+
+ const onSearchChange = React.useCallback((value?: string) => {
+ if (value) {
+ setFilterValue(value);
+ setPage(1);
+ } else {
+ setFilterValue("");
+ }
+ }, []);
+
+ const topContent = React.useMemo(() => {
+ return (
+
+
+
}
+ value={filterValue}
+ variant="bordered"
+ onClear={() => setFilterValue("")}
+ onValueChange={onSearchChange}
+ />
+
+
+
+ }
+ size="sm"
+ variant="flat"
+ >
+ Status
+
+
+
+ {statusOptions.map((status) => (
+
+ {capitalize(status.name)}
+
+ ))}
+
+
+
+
+ }
+ size="sm"
+ variant="flat"
+ >
+ Columns
+
+
+
+ {columns.map((column) => (
+
+ {capitalize(column.name)}
+
+ ))}
+
+
+ } size="sm">
+ Add New
+
+
+
+
+ Total {users.length} users
+
+
+
+ );
+ }, [
+ filterValue,
+ statusFilter,
+ visibleColumns,
+ onSearchChange,
+ onRowsPerPageChange,
+ users.length,
+ hasSearchFilter,
+ ]);
+
+ const bottomContent = React.useMemo(() => {
+ return (
+
+
+
+ {selectedKeys === "all"
+ ? "All items selected"
+ : `${selectedKeys.size} of ${items.length} selected`}
+
+
+ );
+ }, [selectedKeys, items.length, page, pages, hasSearchFilter]);
+
+ const classNames = React.useMemo(
+ () => ({
+ wrapper: ["max-h-[382px]", "max-w-3xl"],
+ th: ["bg-transparent", "text-default-500", "border-b", "border-divider"],
+ td: [
+ // changing the rows border radius
+ // first
+ "group-data-[first=true]/tr:first:before:rounded-none",
+ "group-data-[first=true]/tr:last:before:rounded-none",
+ // middle
+ "group-data-[middle=true]/tr:before:rounded-none",
+ // last
+ "group-data-[last=true]/tr:first:before:rounded-none",
+ "group-data-[last=true]/tr:last:before:rounded-none",
+ ],
+ }),
+ [],
+ );
+
+ return (
+
+
+ {(column) => (
+
+ {column.name}
+
+ )}
+
+
+ {(item) => (
+
+ {(columnKey) => {renderCell(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/custom-styles.ts b/apps/docs/content/components/table/custom-styles.ts
index e57b2904e9..29cf5fd0ee 100644
--- a/apps/docs/content/components/table/custom-styles.ts
+++ b/apps/docs/content/components/table/custom-styles.ts
@@ -1,1034 +1,8 @@
-const data = `const columns = [
- {name: "ID", uid: "id", sortable: true},
- {name: "NAME", uid: "name", sortable: true},
- {name: "AGE", uid: "age", sortable: true},
- {name: "ROLE", uid: "role", sortable: true},
- {name: "TEAM", uid: "team"},
- {name: "EMAIL", uid: "email"},
- {name: "STATUS", uid: "status", sortable: true},
- {name: "ACTIONS", uid: "actions"},
-];
-
-const statusOptions = [
- {name: "Active", uid: "active"},
- {name: "Paused", uid: "paused"},
- {name: "Vacation", uid: "vacation"},
-];
-
-const users = [
- {
- id: 1,
- name: "Tony Reichert",
- role: "CEO",
- team: "Management",
- status: "active",
- age: "29",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
- email: "tony.reichert@example.com",
- },
- {
- id: 2,
- name: "Zoey Lang",
- role: "Tech Lead",
- team: "Development",
- status: "paused",
- age: "25",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
- email: "zoey.lang@example.com",
- },
- {
- id: 3,
- name: "Jane Fisher",
- role: "Sr. Dev",
- team: "Development",
- status: "active",
- age: "22",
- avatar: "https://i.pravatar.cc/150?u=a04258114e29026702d",
- email: "jane.fisher@example.com",
- },
- {
- id: 4,
- name: "William Howard",
- role: "C.M.",
- team: "Marketing",
- status: "vacation",
- age: "28",
- avatar: "https://i.pravatar.cc/150?u=a048581f4e29026701d",
- email: "william.howard@example.com",
- },
- {
- id: 5,
- name: "Kristen Copper",
- role: "S. Manager",
- team: "Sales",
- status: "active",
- age: "24",
- avatar: "https://i.pravatar.cc/150?u=a092581d4ef9026700d",
- email: "kristen.cooper@example.com",
- },
- {
- id: 6,
- name: "Brian Kim",
- role: "P. Manager",
- team: "Management",
- age: "29",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
- email: "brian.kim@example.com",
- status: "active",
- },
- {
- id: 7,
- name: "Michael Hunt",
- role: "Designer",
- team: "Design",
- status: "paused",
- age: "27",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29027007d",
- email: "michael.hunt@example.com",
- },
- {
- id: 8,
- name: "Samantha Brooks",
- role: "HR Manager",
- team: "HR",
- status: "active",
- age: "31",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e27027008d",
- email: "samantha.brooks@example.com",
- },
- {
- id: 9,
- name: "Frank Harrison",
- role: "F. Manager",
- team: "Finance",
- status: "vacation",
- age: "33",
- avatar: "https://i.pravatar.cc/150?img=4",
- email: "frank.harrison@example.com",
- },
- {
- id: 10,
- name: "Emma Adams",
- role: "Ops Manager",
- team: "Operations",
- status: "active",
- age: "35",
- avatar: "https://i.pravatar.cc/150?img=5",
- email: "emma.adams@example.com",
- },
- {
- id: 11,
- name: "Brandon Stevens",
- role: "Jr. Dev",
- team: "Development",
- status: "active",
- age: "22",
- avatar: "https://i.pravatar.cc/150?img=8",
- email: "brandon.stevens@example.com",
- },
- {
- id: 12,
- name: "Megan Richards",
- role: "P. Manager",
- team: "Product",
- status: "paused",
- age: "28",
- avatar: "https://i.pravatar.cc/150?img=10",
- email: "megan.richards@example.com",
- },
- {
- id: 13,
- name: "Oliver Scott",
- role: "S. Manager",
- team: "Security",
- status: "active",
- age: "37",
- avatar: "https://i.pravatar.cc/150?img=12",
- email: "oliver.scott@example.com",
- },
- {
- id: 14,
- name: "Grace Allen",
- role: "M. Specialist",
- team: "Marketing",
- status: "active",
- age: "30",
- avatar: "https://i.pravatar.cc/150?img=16",
- email: "grace.allen@example.com",
- },
- {
- id: 15,
- name: "Noah Carter",
- role: "IT Specialist",
- team: "I. Technology",
- status: "paused",
- age: "31",
- avatar: "https://i.pravatar.cc/150?img=15",
- email: "noah.carter@example.com",
- },
- {
- id: 16,
- name: "Ava Perez",
- role: "Manager",
- team: "Sales",
- status: "active",
- age: "29",
- avatar: "https://i.pravatar.cc/150?img=20",
- email: "ava.perez@example.com",
- },
- {
- id: 17,
- name: "Liam Johnson",
- role: "Data Analyst",
- team: "Analysis",
- status: "active",
- age: "28",
- avatar: "https://i.pravatar.cc/150?img=33",
- email: "liam.johnson@example.com",
- },
- {
- id: 18,
- name: "Sophia Taylor",
- role: "QA Analyst",
- team: "Testing",
- status: "active",
- age: "27",
- avatar: "https://i.pravatar.cc/150?img=29",
- email: "sophia.taylor@example.com",
- },
- {
- id: 19,
- name: "Lucas Harris",
- role: "Administrator",
- team: "Information Technology",
- status: "paused",
- age: "32",
- avatar: "https://i.pravatar.cc/150?img=50",
- email: "lucas.harris@example.com",
- },
- {
- id: 20,
- name: "Mia Robinson",
- role: "Coordinator",
- team: "Operations",
- status: "active",
- age: "26",
- avatar: "https://i.pravatar.cc/150?img=45",
- email: "mia.robinson@example.com",
- },
-];
-
-export {columns, users, statusOptions};`;
-
-const utils = `export function capitalize(s) {
- return s ? s.charAt(0).toUpperCase() + s.slice(1).toLowerCase() : "";
-}`;
-
-const PlusIcon = `export const PlusIcon = ({size = 24, width, height, ...props}) => (
-
-);`;
-
-const VerticalDotsIcon = `export const VerticalDotsIcon = ({size = 24, width, height, ...props}) => (
-
-);`;
-
-const SearchIcon = `export const SearchIcon = (props) => (
-
-);`;
-
-const ChevronDownIcon = `export const ChevronDownIcon = ({strokeWidth = 1.5, ...otherProps}) => (
-
-);`;
-
-const App = `import {
- Table,
- TableHeader,
- TableColumn,
- TableBody,
- TableRow,
- TableCell,
- Input,
- Button,
- DropdownTrigger,
- Dropdown,
- DropdownMenu,
- DropdownItem,
- Chip,
- User,
- Pagination,
-} from "@nextui-org/react";
-import {PlusIcon} from "./PlusIcon";
-import {VerticalDotsIcon} from "./VerticalDotsIcon";
-import {SearchIcon} from "./SearchIcon";
-import {ChevronDownIcon} from "./ChevronDownIcon";
-import {columns, users, statusOptions} from "./data";
-import {capitalize} from "./utils";
-
-const statusColorMap = {
- active: "success",
- paused: "danger",
- vacation: "warning",
-};
-
-const INITIAL_VISIBLE_COLUMNS = ["name", "role", "status", "actions"];
-
-export default function App() {
- const [filterValue, setFilterValue] = React.useState("");
- const [selectedKeys, setSelectedKeys] = React.useState(new Set([]));
- const [visibleColumns, setVisibleColumns] = React.useState(new Set(INITIAL_VISIBLE_COLUMNS));
- const [statusFilter, setStatusFilter] = React.useState("all");
- const [rowsPerPage, setRowsPerPage] = React.useState(5);
- const [sortDescriptor, setSortDescriptor] = React.useState({
- column: "age",
- direction: "ascending",
- });
- const [page, setPage] = React.useState(1);
-
- const pages = Math.ceil(users.length / rowsPerPage);
-
- const hasSearchFilter = Boolean(filterValue);
-
- const headerColumns = React.useMemo(() => {
- if (visibleColumns === "all") return columns;
-
- return columns.filter((column) => Array.from(visibleColumns).includes(column.uid));
- }, [visibleColumns]);
-
- const filteredItems = React.useMemo(() => {
- let filteredUsers = [...users];
-
- if (hasSearchFilter) {
- filteredUsers = filteredUsers.filter((user) =>
- user.name.toLowerCase().includes(filterValue.toLowerCase()),
- );
- }
- if (statusFilter !== "all" && Array.from(statusFilter).length !== statusOptions.length) {
- filteredUsers = filteredUsers.filter((user) =>
- Array.from(statusFilter).includes(user.status),
- );
- }
-
- return filteredUsers;
- }, [users, filterValue, statusFilter]);
-
- const items = React.useMemo(() => {
- const start = (page - 1) * rowsPerPage;
- const end = start + rowsPerPage;
-
- return filteredItems.slice(start, end);
- }, [page, filteredItems, rowsPerPage]);
-
- const sortedItems = React.useMemo(() => {
- return [...items].sort((a, b) => {
- const first = a[sortDescriptor.column];
- const second = b[sortDescriptor.column];
- const cmp = first < second ? -1 : first > second ? 1 : 0;
-
- return sortDescriptor.direction === "descending" ? -cmp : cmp;
- });
- }, [sortDescriptor, items]);
-
- const renderCell = React.useCallback((user, columnKey) => {
- const cellValue = user[columnKey];
-
- switch (columnKey) {
- case "name":
- return (
-
- {user.email}
-
- );
- case "role":
- return (
-
-
{cellValue}
-
{user.team}
-
- );
- case "status":
- return (
-
- {cellValue}
-
- );
- case "actions":
- return (
-
-
-
-
-
-
- View
- Edit
- Delete
-
-
-
- );
- default:
- return cellValue;
- }
- }, []);
-
- const onRowsPerPageChange = React.useCallback((e) => {
- setRowsPerPage(Number(e.target.value));
- setPage(1);
- }, []);
-
-
- const onSearchChange = React.useCallback((value) => {
- if (value) {
- setFilterValue(value);
- setPage(1);
- } else {
- setFilterValue("");
- }
- }, []);
-
- const topContent = React.useMemo(() => {
- return (
-
-
-
}
- value={filterValue}
- variant="bordered"
- onClear={() => setFilterValue("")}
- onValueChange={onSearchChange}
- />
-
-
-
- }
- size="sm"
- variant="flat"
- >
- Status
-
-
-
- {statusOptions.map((status) => (
-
- {capitalize(status.name)}
-
- ))}
-
-
-
-
- }
- size="sm"
- variant="flat"
- >
- Columns
-
-
-
- {columns.map((column) => (
-
- {capitalize(column.name)}
-
- ))}
-
-
- }
- size="sm"
- >
- Add New
-
-
-
-
- Total {users.length} users
-
-
-
- );
- }, [
- filterValue,
- statusFilter,
- visibleColumns,
- onSearchChange,
- onRowsPerPageChange,
- users.length,
- hasSearchFilter,
- ]);
-
- const bottomContent = React.useMemo(() => {
- return (
-
-
-
- {selectedKeys === "all"
- ? "All items selected"
- : \`\${selectedKeys.size} of \${items.length} selected\`}
-
-
- );
- }, [selectedKeys, items.length, page, pages, hasSearchFilter]);
-
- const classNames = React.useMemo(
- () => ({
- wrapper: ["max-h-[382px]", "max-w-3xl"],
- th: ["bg-transparent", "text-default-500", "border-b", "border-divider"],
- td: [
- // changing the rows border radius
- // first
- "group-data-[first=true]/tr:first:before:rounded-none",
- "group-data-[first=true]/tr:last:before:rounded-none",
- // middle
- "group-data-[middle=true]/tr:before:rounded-none",
- // last
- "group-data-[last=true]/tr:first:before:rounded-none",
- "group-data-[last=true]/tr:last:before:rounded-none",
- ],
- }),
- [],
- );
-
- return (
-
-
- {(column) => (
-
- {column.name}
-
- )}
-
-
- {(item) => (
-
- {(columnKey) => {renderCell(item, columnKey)}}
-
- )}
-
-
- );
-}`;
-
-const AppTs = `import {
- Table,
- TableHeader,
- TableColumn,
- TableBody,
- TableRow,
- TableCell,
- Input,
- Button,
- DropdownTrigger,
- Dropdown,
- DropdownMenu,
- DropdownItem,
- Chip,
- User,
- Pagination,
- Selection,
- ChipProps,
- SortDescriptor
-} from "@nextui-org/react";
-import {PlusIcon} from "./PlusIcon";
-import {VerticalDotsIcon} from "./VerticalDotsIcon";
-import {ChevronDownIcon} from "./ChevronDownIcon";
-import {SearchIcon} from "./SearchIcon";
-import {columns, users, statusOptions} from "./data";
-import {capitalize} from "./utils";
-
-const statusColorMap: Record = {
- active: "success",
- paused: "danger",
- vacation: "warning",
-};
-
-const INITIAL_VISIBLE_COLUMNS = ["name", "role", "status", "actions"];
-
-type User = typeof users[0];
-
-export default function App() {
- const [filterValue, setFilterValue] = React.useState("");
- const [selectedKeys, setSelectedKeys] = React.useState(new Set([]));
- const [visibleColumns, setVisibleColumns] = React.useState(new Set(INITIAL_VISIBLE_COLUMNS));
- const [statusFilter, setStatusFilter] = React.useState("all");
- const [rowsPerPage, setRowsPerPage] = React.useState(5);
- const [sortDescriptor, setSortDescriptor] = React.useState({
- column: "age",
- direction: "ascending",
- });
- const [page, setPage] = React.useState(1);
-
- const pages = Math.ceil(users.length / rowsPerPage);
-
- const hasSearchFilter = Boolean(filterValue);
-
- const headerColumns = React.useMemo(() => {
- if (visibleColumns === "all") return columns;
-
- return columns.filter((column) => Array.from(visibleColumns).includes(column.uid));
- }, [visibleColumns]);
-
- const filteredItems = React.useMemo(() => {
- let filteredUsers = [...users];
-
- if (hasSearchFilter) {
- filteredUsers = filteredUsers.filter((user) =>
- user.name.toLowerCase().includes(filterValue.toLowerCase()),
- );
- }
- if (statusFilter !== "all" && Array.from(statusFilter).length !== statusOptions.length) {
- filteredUsers = filteredUsers.filter((user) =>
- Array.from(statusFilter).includes(user.status),
- );
- }
-
- return filteredUsers;
- }, [users, filterValue, statusFilter]);
-
- const items = React.useMemo(() => {
- const start = (page - 1) * rowsPerPage;
- const end = start + rowsPerPage;
-
- return filteredItems.slice(start, end);
- }, [page, filteredItems, rowsPerPage]);
-
- const sortedItems = React.useMemo(() => {
- return [...items].sort((a: User, b: User) => {
- const first = a[sortDescriptor.column as keyof User] as number;
- const second = b[sortDescriptor.column as keyof User] as number;
- const cmp = first < second ? -1 : first > second ? 1 : 0;
-
- return sortDescriptor.direction === "descending" ? -cmp : cmp;
- });
- }, [sortDescriptor, items]);
-
- const renderCell = React.useCallback((user: User, columnKey: React.Key) => {
- const cellValue = user[columnKey as keyof User];
-
- switch (columnKey) {
- case "name":
- return (
-
- {user.email}
-
- );
- case "role":
- return (
-
-
{cellValue}
-
{user.team}
-
- );
- case "status":
- return (
-
- {cellValue}
-
- );
- case "actions":
- return (
-
-
-
-
-
-
- View
- Edit
- Delete
-
-
-
- );
- default:
- return cellValue;
- }
- }, []);
-
-
- const onRowsPerPageChange = React.useCallback((e: React.ChangeEvent) => {
- setRowsPerPage(Number(e.target.value));
- setPage(1);
- }, []);
-
- const onSearchChange = React.useCallback((value?: string) => {
- if (value) {
- setFilterValue(value);
- setPage(1);
- } else {
- setFilterValue("");
- }
- }, []);
-
- const topContent = React.useMemo(() => {
- return (
-
-
-
}
- value={filterValue}
- variant="bordered"
- onClear={() => setFilterValue("")}
- onValueChange={onSearchChange}
- />
-
-
-
- }
- size="sm"
- variant="flat"
- >
- Status
-
-
-
- {statusOptions.map((status) => (
-
- {capitalize(status.name)}
-
- ))}
-
-
-
-
- }
- size="sm"
- variant="flat"
- >
- Columns
-
-
-
- {columns.map((column) => (
-
- {capitalize(column.name)}
-
- ))}
-
-
- }
- size="sm"
- >
- Add New
-
-
-
-
- Total {users.length} users
-
-
-
- );
- }, [
- filterValue,
- statusFilter,
- visibleColumns,
- onSearchChange,
- onRowsPerPageChange,
- users.length,
- hasSearchFilter,
- ]);
-
- const bottomContent = React.useMemo(() => {
- return (
-
-
-
- {selectedKeys === "all"
- ? "All items selected"
- : \`\${selectedKeys.size} of \${items.length} selected\`}
-
-
- );
- }, [selectedKeys, items.length, page, pages, hasSearchFilter]);
-
- const classNames = React.useMemo(
- () => ({
- wrapper: ["max-h-[382px]", "max-w-3xl"],
- th: ["bg-transparent", "text-default-500", "border-b", "border-divider"],
- td: [
- // changing the rows border radius
- // first
- "group-data-[first=true]/tr:first:before:rounded-none",
- "group-data-[first=true]/tr:last:before:rounded-none",
- // middle
- "group-data-[middle=true]/tr:before:rounded-none",
- // last
- "group-data-[last=true]/tr:first:before:rounded-none",
- "group-data-[last=true]/tr:last:before:rounded-none",
- ],
- }),
- [],
- );
-
- return (
-
-
- {(column) => (
-
- {column.name}
-
- )}
-
-
- {(item) => (
-
- {(columnKey) => {renderCell(item, columnKey)}}
-
- )}
-
-
- );
-}`;
+import App from "./custom-styles.raw.jsx?raw";
+import AppTs from "./custom-styles.raw.tsx?raw";
const react = {
"/App.jsx": App,
- "/data.js": data,
- "/utils.js": utils,
- "/PlusIcon.jsx": PlusIcon,
- "/VerticalDotsIcon.jsx": VerticalDotsIcon,
- "/SearchIcon.jsx": SearchIcon,
- "/ChevronDownIcon.jsx": ChevronDownIcon,
};
const reactTs = {
diff --git a/apps/docs/content/components/table/disabled-rows.raw.jsx b/apps/docs/content/components/table/disabled-rows.raw.jsx
new file mode 100644
index 0000000000..2866f2b0a6
--- /dev/null
+++ b/apps/docs/content/components/table/disabled-rows.raw.jsx
@@ -0,0 +1,76 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ getKeyValue,
+} from "@nextui-org/react";
+
+const rows = [
+ {
+ key: "1",
+ name: "Tony Reichert",
+ role: "CEO",
+ status: "Active",
+ },
+ {
+ key: "2",
+ name: "Zoey Lang",
+ role: "Technical Lead",
+ status: "Paused",
+ },
+ {
+ key: "3",
+ name: "Jane Fisher",
+ role: "Senior Developer",
+ status: "Active",
+ },
+ {
+ key: "4",
+ name: "William Howard",
+ role: "Community Manager",
+ status: "Vacation",
+ },
+];
+
+const columns = [
+ {
+ key: "name",
+ label: "NAME",
+ },
+ {
+ key: "role",
+ label: "ROLE",
+ },
+ {
+ key: "status",
+ label: "STATUS",
+ },
+];
+
+export default function App() {
+ const [selectedKeys, setSelectedKeys] = React.useState(new Set(["2"]));
+
+ return (
+
+
+ {(column) => {column.label}}
+
+
+ {(item) => (
+
+ {(columnKey) => {getKeyValue(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/disabled-rows.ts b/apps/docs/content/components/table/disabled-rows.ts
index bdb9ba21f6..c619fe06f6 100644
--- a/apps/docs/content/components/table/disabled-rows.ts
+++ b/apps/docs/content/components/table/disabled-rows.ts
@@ -1,71 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue} from "@nextui-org/react";
-
-const rows = [
- {
- key: "1",
- name: "Tony Reichert",
- role: "CEO",
- status: "Active",
- },
- {
- key: "2",
- name: "Zoey Lang",
- role: "Technical Lead",
- status: "Paused",
- },
- {
- key: "3",
- name: "Jane Fisher",
- role: "Senior Developer",
- status: "Active",
- },
- {
- key: "4",
- name: "William Howard",
- role: "Community Manager",
- status: "Vacation",
- },
-];
-
-const columns = [
- {
- key: "name",
- label: "NAME",
- },
- {
- key: "role",
- label: "ROLE",
- },
- {
- key: "status",
- label: "STATUS",
- },
-];
-
-export default function App() {
- const [selectedKeys, setSelectedKeys] = React.useState(new Set(["2"]));
-
- return (
-
-
- {(column) => {column.label}}
-
-
- {(item) => (
-
- {(columnKey) => {getKeyValue(item, columnKey)}}
-
- )}
-
-
- );
-}`;
+import App from "./disabled-rows.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/disallow-empty-selection.raw.jsx b/apps/docs/content/components/table/disallow-empty-selection.raw.jsx
new file mode 100644
index 0000000000..14a5db7045
--- /dev/null
+++ b/apps/docs/content/components/table/disallow-empty-selection.raw.jsx
@@ -0,0 +1,68 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ RadioGroup,
+ Radio,
+} from "@nextui-org/react";
+
+const colors = ["default", "primary", "secondary", "success", "warning", "danger"];
+
+export default function App() {
+ const [selectedColor, setSelectedColor] = React.useState("default");
+
+ return (
+
+
+
+ NAME
+ ROLE
+ STATUS
+
+
+
+ Tony Reichert
+ CEO
+ Active
+
+
+ Zoey Lang
+ Technical Lead
+ Paused
+
+
+ Jane Fisher
+ Senior Developer
+ Active
+
+
+ William Howard
+ Community Manager
+ Vacation
+
+
+
+
+ {colors.map((color) => (
+
+ {color}
+
+ ))}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/disallow-empty-selection.ts b/apps/docs/content/components/table/disallow-empty-selection.ts
index 474b257da0..a1abceee1f 100644
--- a/apps/docs/content/components/table/disallow-empty-selection.ts
+++ b/apps/docs/content/components/table/disallow-empty-selection.ts
@@ -1,67 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, RadioGroup, Radio} from "@nextui-org/react";
-
-const colors = ["default", "primary", "secondary", "success", "warning", "danger"];
-
-export default function App() {
- const [selectedColor, setSelectedColor] = React.useState("default");
-
- return (
-
-
-
- NAME
- ROLE
- STATUS
-
-
-
- Tony Reichert
- CEO
- Active
-
-
- Zoey Lang
- Technical Lead
- Paused
-
-
- Jane Fisher
- Senior Developer
- Active
-
-
- William Howard
- Community Manager
- Vacation
-
-
-
-
- {colors.map((color) => (
-
- {color}
-
- ))}
-
-
- );
-}`;
+import App from "./disallow-empty-selection.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/dynamic.raw.jsx b/apps/docs/content/components/table/dynamic.raw.jsx
new file mode 100644
index 0000000000..a6e733dd18
--- /dev/null
+++ b/apps/docs/content/components/table/dynamic.raw.jsx
@@ -0,0 +1,68 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ getKeyValue,
+} from "@nextui-org/react";
+
+const rows = [
+ {
+ key: "1",
+ name: "Tony Reichert",
+ role: "CEO",
+ status: "Active",
+ },
+ {
+ key: "2",
+ name: "Zoey Lang",
+ role: "Technical Lead",
+ status: "Paused",
+ },
+ {
+ key: "3",
+ name: "Jane Fisher",
+ role: "Senior Developer",
+ status: "Active",
+ },
+ {
+ key: "4",
+ name: "William Howard",
+ role: "Community Manager",
+ status: "Vacation",
+ },
+];
+
+const columns = [
+ {
+ key: "name",
+ label: "NAME",
+ },
+ {
+ key: "role",
+ label: "ROLE",
+ },
+ {
+ key: "status",
+ label: "STATUS",
+ },
+];
+
+export default function App() {
+ return (
+
+
+ {(column) => {column.label}}
+
+
+ {(item) => (
+
+ {(columnKey) => {getKeyValue(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/dynamic.ts b/apps/docs/content/components/table/dynamic.ts
index bf20c16d51..5d3c97bb9a 100644
--- a/apps/docs/content/components/table/dynamic.ts
+++ b/apps/docs/content/components/table/dynamic.ts
@@ -1,63 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue} from "@nextui-org/react";
-
-const rows = [
- {
- key: "1",
- name: "Tony Reichert",
- role: "CEO",
- status: "Active",
- },
- {
- key: "2",
- name: "Zoey Lang",
- role: "Technical Lead",
- status: "Paused",
- },
- {
- key: "3",
- name: "Jane Fisher",
- role: "Senior Developer",
- status: "Active",
- },
- {
- key: "4",
- name: "William Howard",
- role: "Community Manager",
- status: "Vacation",
- },
-];
-
-const columns = [
- {
- key: "name",
- label: "NAME",
- },
- {
- key: "role",
- label: "ROLE",
- },
- {
- key: "status",
- label: "STATUS",
- },
-];
-
-export default function App() {
- return (
-
-
- {(column) => {column.label}}
-
-
- {(item) => (
-
- {(columnKey) => {getKeyValue(item, columnKey)}}
-
- )}
-
-
- );
-}`;
+import App from "./dynamic.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/empty.raw.jsx b/apps/docs/content/components/table/empty.raw.jsx
new file mode 100644
index 0000000000..2d27a10705
--- /dev/null
+++ b/apps/docs/content/components/table/empty.raw.jsx
@@ -0,0 +1,14 @@
+import {Table, TableHeader, TableColumn, TableBody} from "@nextui-org/react";
+
+export default function App() {
+ return (
+
+
+ NAME
+ ROLE
+ STATUS
+
+ {[]}
+
+ );
+}
diff --git a/apps/docs/content/components/table/empty.ts b/apps/docs/content/components/table/empty.ts
index 1a6e0ced1e..962836358a 100644
--- a/apps/docs/content/components/table/empty.ts
+++ b/apps/docs/content/components/table/empty.ts
@@ -1,17 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell} from "@nextui-org/react";
-
-export default function App() {
- return (
-
-
- NAME
- ROLE
- STATUS
-
- {[]}
-
- );
-}`;
+import App from "./empty.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/infinite-pagination.raw.jsx b/apps/docs/content/components/table/infinite-pagination.raw.jsx
new file mode 100644
index 0000000000..2af4de3203
--- /dev/null
+++ b/apps/docs/content/components/table/infinite-pagination.raw.jsx
@@ -0,0 +1,76 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ Spinner,
+ getKeyValue,
+} from "@nextui-org/react";
+import {useInfiniteScroll} from "@nextui-org/use-infinite-scroll";
+import {useAsyncList} from "@react-stately/data";
+
+export default function App() {
+ const [isLoading, setIsLoading] = React.useState(true);
+ const [hasMore, setHasMore] = React.useState(false);
+
+ let list = useAsyncList({
+ async load({signal, cursor}) {
+ if (cursor) {
+ setIsLoading(false);
+ }
+
+ // If no cursor is available, then we're loading the first page.
+ // Otherwise, the cursor is the next URL to load, as returned from the previous page.
+ const res = await fetch(cursor || "https://swapi.py4e.com/api/people/?search=", {signal});
+ let json = await res.json();
+
+ setHasMore(json.next !== null);
+
+ return {
+ items: json.results,
+ cursor: json.next,
+ };
+ },
+ });
+
+ const [loaderRef, scrollerRef] = useInfiniteScroll({hasMore, onLoadMore: list.loadMore});
+
+ return (
+
+
+
+ ) : null
+ }
+ classNames={{
+ base: "max-h-[520px] overflow-scroll",
+ table: "min-h-[400px]",
+ }}
+ >
+
+ Name
+ Height
+ Mass
+ Birth year
+
+ }
+ >
+ {(item) => (
+
+ {(columnKey) => {getKeyValue(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/infinite-pagination.raw.tsx b/apps/docs/content/components/table/infinite-pagination.raw.tsx
new file mode 100644
index 0000000000..4d69e33341
--- /dev/null
+++ b/apps/docs/content/components/table/infinite-pagination.raw.tsx
@@ -0,0 +1,87 @@
+import React from "react";
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ Spinner,
+ getKeyValue,
+} from "@nextui-org/react";
+import {useInfiniteScroll} from "@nextui-org/use-infinite-scroll";
+import {useAsyncList} from "@react-stately/data";
+
+interface SWCharacter {
+ name: string;
+ height: string;
+ mass: string;
+ birth_year: string;
+}
+
+export default function App() {
+ const [isLoading, setIsLoading] = React.useState(true);
+ const [hasMore, setHasMore] = React.useState(false);
+
+ let list = useAsyncList({
+ async load({signal, cursor}) {
+ if (cursor) {
+ setIsLoading(false);
+ }
+
+ // If no cursor is available, then we're loading the first page.
+ // Otherwise, the cursor is the next URL to load, as returned from the previous page.
+ const res = await fetch(cursor || "https://swapi.py4e.com/api/people/?search=", {signal});
+ let json = await res.json();
+
+ setHasMore(json.next !== null);
+
+ return {
+ items: json.results,
+ cursor: json.next,
+ };
+ },
+ });
+
+ const [loaderRef, scrollerRef] = useInfiniteScroll({
+ hasMore,
+ onLoadMore: list.loadMore,
+ });
+
+ return (
+
+
+
+ ) : null
+ }
+ classNames={{
+ base: "max-h-[520px] overflow-scroll",
+ table: "min-h-[400px]",
+ }}
+ >
+
+ Name
+ Height
+ Mass
+ Birth year
+
+ }
+ >
+ {(item: SWCharacter) => (
+
+ {(columnKey) => {getKeyValue(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/infinite-pagination.ts b/apps/docs/content/components/table/infinite-pagination.ts
index 145813869a..cdee063a64 100644
--- a/apps/docs/content/components/table/infinite-pagination.ts
+++ b/apps/docs/content/components/table/infinite-pagination.ts
@@ -1,154 +1,5 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Pagination, Spinner, getKeyValue} from "@nextui-org/react";
-import {useInfiniteScroll} from "@nextui-org/use-infinite-scroll";
-import {useAsyncList} from "@react-stately/data";
-
-export default function App() {
- const [isLoading, setIsLoading] = React.useState(true);
- const [hasMore, setHasMore] = React.useState(false);
-
- let list = useAsyncList({
- async load({signal, cursor}) {
-
- if (cursor) {
- setIsLoading(false);
- }
-
- // If no cursor is available, then we're loading the first page.
- // Otherwise, the cursor is the next URL to load, as returned from the previous page.
- const res = await fetch(cursor || "https://swapi.py4e.com/api/people/?search=", {signal});
- let json = await res.json();
-
- setHasMore(json.next !== null);
-
- return {
- items: json.results,
- cursor: json.next,
- };
- },
- });
-
- const [loaderRef, scrollerRef] = useInfiniteScroll({hasMore, onLoadMore: list.loadMore});
-
- return (
-
-
-
- ) : null
- }
- classNames={{
- base: "max-h-[520px] overflow-scroll",
- table: "min-h-[400px]",
- }}
- >
-
- Name
- Height
- Mass
- Birth year
-
- }
- >
- {(item) => (
-
- {(columnKey) => {getKeyValue(item, columnKey)}}
-
- )}
-
-
- );
-}`;
-
-const AppTs = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Pagination, Spinner, getKeyValue} from "@nextui-org/react";
-import { useInfiniteScroll } from "@nextui-org/use-infinite-scroll";
-import { useAsyncList } from "@react-stately/data";
-
-interface SWCharacter {
- name: string;
- height: string;
- mass: string;
- birth_year: string;
-}
-
-export default function App() {
- const [isLoading, setIsLoading] = React.useState(true);
- const [hasMore, setHasMore] = React.useState(false);
-
- let list = useAsyncList({
- async load({ signal, cursor }) {
- if (cursor) {
- setIsLoading(false);
- }
-
- // If no cursor is available, then we're loading the first page.
- // Otherwise, the cursor is the next URL to load, as returned from the previous page.
- const res = await fetch(
- cursor || "https://swapi.py4e.com/api/people/?search=",
- { signal }
- );
- let json = await res.json();
-
- setHasMore(json.next !== null);
-
- return {
- items: json.results,
- cursor: json.next,
- };
- },
- });
-
- const [loaderRef, scrollerRef] = useInfiniteScroll({
- hasMore,
- onLoadMore: list.loadMore,
- });
-
- return (
-
-
-
- ) : null
- }
- classNames={{
- base: "max-h-[520px] overflow-scroll",
- table: "min-h-[400px]",
- }}
- >
-
- Name
- Height
- Mass
- Birth year
-
- }
- >
- {(item: SWCharacter) => (
-
- {(columnKey) => (
- {getKeyValue(item, columnKey)}
- )}
-
- )}
-
-
- );
-}`;
+import App from "./infinite-pagination.raw.jsx?raw";
+import AppTs from "./infinite-pagination.raw.tsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/load-more.raw.jsx b/apps/docs/content/components/table/load-more.raw.jsx
new file mode 100644
index 0000000000..a011985059
--- /dev/null
+++ b/apps/docs/content/components/table/load-more.raw.jsx
@@ -0,0 +1,80 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ getKeyValue,
+ Spinner,
+ Button,
+} from "@nextui-org/react";
+import {useAsyncList} from "@react-stately/data";
+
+export default function App() {
+ const [page, setPage] = React.useState(1);
+ const [isLoading, setIsLoading] = React.useState(true);
+
+ let list = useAsyncList({
+ async load({signal, cursor}) {
+ if (cursor) {
+ setPage((prev) => prev + 1);
+ }
+
+ // If no cursor is available, then we're loading the first page.
+ // Otherwise, the cursor is the next URL to load, as returned from the previous page.
+ const res = await fetch(cursor || "https://swapi.py4e.com/api/people/?search=", {signal});
+ let json = await res.json();
+
+ if (!cursor) {
+ setIsLoading(false);
+ }
+
+ return {
+ items: json.results,
+ cursor: json.next,
+ };
+ },
+ });
+
+ const hasMore = page < 9;
+
+ return (
+
+
+
+ ) : null
+ }
+ classNames={{
+ base: "max-h-[520px] overflow-scroll",
+ table: "min-h-[420px]",
+ }}
+ >
+
+ Name
+ Height
+ Mass
+ Birth year
+
+ }
+ >
+ {(item) => (
+
+ {(columnKey) => {getKeyValue(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/load-more.ts b/apps/docs/content/components/table/load-more.ts
index 70e8cd3825..872717cc04 100644
--- a/apps/docs/content/components/table/load-more.ts
+++ b/apps/docs/content/components/table/load-more.ts
@@ -1,73 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue, Spinner, Button} from "@nextui-org/react";
-import {useAsyncList} from "@react-stately/data";
-
-export default function App() {
- const [page, setPage] = React.useState(1);
- const [isLoading, setIsLoading] = React.useState(true);
-
- let list = useAsyncList({
- async load({signal, cursor}) {
- if (cursor) {
- setPage((prev) => prev + 1);
- }
-
- // If no cursor is available, then we're loading the first page.
- // Otherwise, the cursor is the next URL to load, as returned from the previous page.
- const res = await fetch(cursor || "https://swapi.py4e.com/api/people/?search=", {signal});
- let json = await res.json();
-
- if (!cursor) {
- setIsLoading(false);
- }
-
- return {
- items: json.results,
- cursor: json.next,
- };
- },
- });
-
- const hasMore = page < 9;
-
- return (
-
-
-
- ) : null
- }
- classNames={{
- base: "max-h-[520px] overflow-scroll",
- table: "min-h-[420px]",
- }}
- >
-
- Name
- Height
- Mass
- Birth year
-
- }
- >
- {(item) => (
-
- {(columnKey) => {getKeyValue(item, columnKey)}}
-
- )}
-
-
- );
-}`;
+import App from "./load-more.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/multiple-selection.raw.jsx b/apps/docs/content/components/table/multiple-selection.raw.jsx
new file mode 100644
index 0000000000..e6abd5b42e
--- /dev/null
+++ b/apps/docs/content/components/table/multiple-selection.raw.jsx
@@ -0,0 +1,67 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ RadioGroup,
+ Radio,
+} from "@nextui-org/react";
+
+const colors = ["default", "primary", "secondary", "success", "warning", "danger"];
+
+export default function App() {
+ const [selectedColor, setSelectedColor] = React.useState("default");
+
+ return (
+
+
+
+ NAME
+ ROLE
+ STATUS
+
+
+
+ Tony Reichert
+ CEO
+ Active
+
+
+ Zoey Lang
+ Technical Lead
+ Paused
+
+
+ Jane Fisher
+ Senior Developer
+ Active
+
+
+ William Howard
+ Community Manager
+ Vacation
+
+
+
+
+ {colors.map((color) => (
+
+ {color}
+
+ ))}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/multiple-selection.ts b/apps/docs/content/components/table/multiple-selection.ts
index e5be5d114a..f03bb84fb5 100644
--- a/apps/docs/content/components/table/multiple-selection.ts
+++ b/apps/docs/content/components/table/multiple-selection.ts
@@ -1,66 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, RadioGroup, Radio} from "@nextui-org/react";
-
-const colors = ["default", "primary", "secondary", "success", "warning", "danger"];
-
-export default function App() {
- const [selectedColor, setSelectedColor] = React.useState("default");
-
- return (
-
-
-
- NAME
- ROLE
- STATUS
-
-
-
- Tony Reichert
- CEO
- Active
-
-
- Zoey Lang
- Technical Lead
- Paused
-
-
- Jane Fisher
- Senior Developer
- Active
-
-
- William Howard
- Community Manager
- Vacation
-
-
-
-
- {colors.map((color) => (
-
- {color}
-
- ))}
-
-
- );
-}`;
+import App from "./multiple-selection.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/paginated.raw.jsx b/apps/docs/content/components/table/paginated.raw.jsx
new file mode 100644
index 0000000000..962c2dfdd1
--- /dev/null
+++ b/apps/docs/content/components/table/paginated.raw.jsx
@@ -0,0 +1,212 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ Pagination,
+ getKeyValue,
+} from "@nextui-org/react";
+
+export const users = [
+ {
+ key: "1",
+ name: "Tony Reichert",
+ role: "CEO",
+ status: "Active",
+ },
+ {
+ key: "2",
+ name: "Zoey Lang",
+ role: "Technical Lead",
+ status: "Paused",
+ },
+ {
+ key: "3",
+ name: "Jane Fisher",
+ role: "Senior Developer",
+ status: "Active",
+ },
+ {
+ key: "4",
+ name: "William Howard",
+ role: "Community Manager",
+ status: "Vacation",
+ },
+ {
+ key: "5",
+ name: "Emily Collins",
+ role: "Marketing Manager",
+ status: "Active",
+ },
+ {
+ key: "6",
+ name: "Brian Kim",
+ role: "Product Manager",
+ status: "Active",
+ },
+ {
+ key: "7",
+ name: "Laura Thompson",
+ role: "UX Designer",
+ status: "Active",
+ },
+ {
+ key: "8",
+ name: "Michael Stevens",
+ role: "Data Analyst",
+ status: "Paused",
+ },
+ {
+ key: "9",
+ name: "Sophia Nguyen",
+ role: "Quality Assurance",
+ status: "Active",
+ },
+ {
+ key: "10",
+ name: "James Wilson",
+ role: "Front-end Developer",
+ status: "Vacation",
+ },
+ {
+ key: "11",
+ name: "Ava Johnson",
+ role: "Back-end Developer",
+ status: "Active",
+ },
+ {
+ key: "12",
+ name: "Isabella Smith",
+ role: "Graphic Designer",
+ status: "Active",
+ },
+ {
+ key: "13",
+ name: "Oliver Brown",
+ role: "Content Writer",
+ status: "Paused",
+ },
+ {
+ key: "14",
+ name: "Lucas Jones",
+ role: "Project Manager",
+ status: "Active",
+ },
+ {
+ key: "15",
+ name: "Grace Davis",
+ role: "HR Manager",
+ status: "Active",
+ },
+ {
+ key: "16",
+ name: "Elijah Garcia",
+ role: "Network Administrator",
+ status: "Active",
+ },
+ {
+ key: "17",
+ name: "Emma Martinez",
+ role: "Accountant",
+ status: "Vacation",
+ },
+ {
+ key: "18",
+ name: "Benjamin Lee",
+ role: "Operations Manager",
+ status: "Active",
+ },
+ {
+ key: "19",
+ name: "Mia Hernandez",
+ role: "Sales Manager",
+ status: "Paused",
+ },
+ {
+ key: "20",
+ name: "Daniel Lewis",
+ role: "DevOps Engineer",
+ status: "Active",
+ },
+ {
+ key: "21",
+ name: "Amelia Clark",
+ role: "Social Media Specialist",
+ status: "Active",
+ },
+ {
+ key: "22",
+ name: "Jackson Walker",
+ role: "Customer Support",
+ status: "Active",
+ },
+ {
+ key: "23",
+ name: "Henry Hall",
+ role: "Security Analyst",
+ status: "Active",
+ },
+ {
+ key: "24",
+ name: "Charlotte Young",
+ role: "PR Specialist",
+ status: "Paused",
+ },
+ {
+ key: "25",
+ name: "Liam King",
+ role: "Mobile App Developer",
+ status: "Active",
+ },
+];
+
+export default function App() {
+ const [page, setPage] = React.useState(1);
+ const rowsPerPage = 4;
+
+ const pages = Math.ceil(users.length / rowsPerPage);
+
+ const items = React.useMemo(() => {
+ const start = (page - 1) * rowsPerPage;
+ const end = start + rowsPerPage;
+
+ return users.slice(start, end);
+ }, [page, users]);
+
+ return (
+
+ setPage(page)}
+ />
+
+ }
+ classNames={{
+ wrapper: "min-h-[222px]",
+ }}
+ >
+
+ NAME
+ ROLE
+ STATUS
+
+
+ {(item) => (
+
+ {(columnKey) => {getKeyValue(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/paginated.ts b/apps/docs/content/components/table/paginated.ts
index 75be89dc52..557add2fce 100644
--- a/apps/docs/content/components/table/paginated.ts
+++ b/apps/docs/content/components/table/paginated.ts
@@ -1,211 +1,7 @@
-const data = `export const users = [
- {
- key: "1",
- name: "Tony Reichert",
- role: "CEO",
- status: "Active",
- },
- {
- key: "2",
- name: "Zoey Lang",
- role: "Technical Lead",
- status: "Paused",
- },
- {
- key: "3",
- name: "Jane Fisher",
- role: "Senior Developer",
- status: "Active",
- },
- {
- key: "4",
- name: "William Howard",
- role: "Community Manager",
- status: "Vacation",
- },
- {
- key: "5",
- name: "Emily Collins",
- role: "Marketing Manager",
- status: "Active",
- },
- {
- key: "6",
- name: "Brian Kim",
- role: "Product Manager",
- status: "Active",
- },
- {
- key: "7",
- name: "Laura Thompson",
- role: "UX Designer",
- status: "Active",
- },
- {
- key: "8",
- name: "Michael Stevens",
- role: "Data Analyst",
- status: "Paused",
- },
- {
- key: "9",
- name: "Sophia Nguyen",
- role: "Quality Assurance",
- status: "Active",
- },
- {
- key: "10",
- name: "James Wilson",
- role: "Front-end Developer",
- status: "Vacation",
- },
- {
- key: "11",
- name: "Ava Johnson",
- role: "Back-end Developer",
- status: "Active",
- },
- {
- key: "12",
- name: "Isabella Smith",
- role: "Graphic Designer",
- status: "Active",
- },
- {
- key: "13",
- name: "Oliver Brown",
- role: "Content Writer",
- status: "Paused",
- },
- {
- key: "14",
- name: "Lucas Jones",
- role: "Project Manager",
- status: "Active",
- },
- {
- key: "15",
- name: "Grace Davis",
- role: "HR Manager",
- status: "Active",
- },
- {
- key: "16",
- name: "Elijah Garcia",
- role: "Network Administrator",
- status: "Active",
- },
- {
- key: "17",
- name: "Emma Martinez",
- role: "Accountant",
- status: "Vacation",
- },
- {
- key: "18",
- name: "Benjamin Lee",
- role: "Operations Manager",
- status: "Active",
- },
- {
- key: "19",
- name: "Mia Hernandez",
- role: "Sales Manager",
- status: "Paused",
- },
- {
- key: "20",
- name: "Daniel Lewis",
- role: "DevOps Engineer",
- status: "Active",
- },
- {
- key: "21",
- name: "Amelia Clark",
- role: "Social Media Specialist",
- status: "Active",
- },
- {
- key: "22",
- name: "Jackson Walker",
- role: "Customer Support",
- status: "Active",
- },
- {
- key: "23",
- name: "Henry Hall",
- role: "Security Analyst",
- status: "Active",
- },
- {
- key: "24",
- name: "Charlotte Young",
- role: "PR Specialist",
- status: "Paused",
- },
- {
- key: "25",
- name: "Liam King",
- role: "Mobile App Developer",
- status: "Active",
- },
-];`;
-
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, Pagination, getKeyValue} from "@nextui-org/react";
-import {users} from "./data";
-
-export default function App() {
- const [page, setPage] = React.useState(1);
- const rowsPerPage = 4;
-
- const pages = Math.ceil(users.length / rowsPerPage);
-
- const items = React.useMemo(() => {
- const start = (page - 1) * rowsPerPage;
- const end = start + rowsPerPage;
-
- return users.slice(start, end);
- }, [page, users]);
-
- return (
-
- setPage(page)}
- />
-
- }
- classNames={{
- wrapper: "min-h-[222px]",
- }}
- >
-
- NAME
- ROLE
- STATUS
-
-
- {(item) => (
-
- {(columnKey) => {getKeyValue(item, columnKey)}}
-
- )}
-
-
- );
-}`;
+import App from "./paginated.raw.jsx?raw";
const react = {
"/App.jsx": App,
- "/data.js": data,
};
export default {
diff --git a/apps/docs/content/components/table/row-actions.raw.jsx b/apps/docs/content/components/table/row-actions.raw.jsx
new file mode 100644
index 0000000000..1e6cf2dc5a
--- /dev/null
+++ b/apps/docs/content/components/table/row-actions.raw.jsx
@@ -0,0 +1,88 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ getKeyValue,
+ Radio,
+ RadioGroup,
+} from "@nextui-org/react";
+
+const rows = [
+ {
+ key: "1",
+ name: "Tony Reichert",
+ role: "CEO",
+ status: "Active",
+ },
+ {
+ key: "2",
+ name: "Zoey Lang",
+ role: "Technical Lead",
+ status: "Paused",
+ },
+ {
+ key: "3",
+ name: "Jane Fisher",
+ role: "Senior Developer",
+ status: "Active",
+ },
+ {
+ key: "4",
+ name: "William Howard",
+ role: "Community Manager",
+ status: "Vacation",
+ },
+];
+
+const columns = [
+ {
+ key: "name",
+ label: "NAME",
+ },
+ {
+ key: "role",
+ label: "ROLE",
+ },
+ {
+ key: "status",
+ label: "STATUS",
+ },
+];
+
+export default function App() {
+ const [selectionBehavior, setSelectionBehavior] = React.useState("toggle");
+
+ return (
+
+
alert(`Opening item ${key}...`)}
+ >
+
+ {(column) => {column.label}}
+
+
+ {(item) => (
+
+ {(columnKey) => {getKeyValue(item, columnKey)}}
+
+ )}
+
+
+
+ Toggle
+ Replace
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/row-actions.ts b/apps/docs/content/components/table/row-actions.ts
index d9d0782566..06178c6b7f 100644
--- a/apps/docs/content/components/table/row-actions.ts
+++ b/apps/docs/content/components/table/row-actions.ts
@@ -1,81 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue, Radio, RadioGroup} from "@nextui-org/react";
-
-const rows = [
- {
- key: "1",
- name: "Tony Reichert",
- role: "CEO",
- status: "Active",
- },
- {
- key: "2",
- name: "Zoey Lang",
- role: "Technical Lead",
- status: "Paused",
- },
- {
- key: "3",
- name: "Jane Fisher",
- role: "Senior Developer",
- status: "Active",
- },
- {
- key: "4",
- name: "William Howard",
- role: "Community Manager",
- status: "Vacation",
- },
-];
-
-const columns = [
- {
- key: "name",
- label: "NAME",
- },
- {
- key: "role",
- label: "ROLE",
- },
- {
- key: "status",
- label: "STATUS",
- },
-];
-
-export default function App() {
- const [selectionBehavior, setSelectionBehavior] = React.useState("toggle");
-
- return (
-
-
alert(\`Opening item \${key}...\`)}
- >
-
- {(column) => {column.label}}
-
-
- {(item) => (
-
- {(columnKey) => {getKeyValue(item, columnKey)}}
-
- )}
-
-
-
- Toggle
- Replace
-
-
- );
-}`;
+import App from "./row-actions.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/selection-behavior.raw.jsx b/apps/docs/content/components/table/selection-behavior.raw.jsx
new file mode 100644
index 0000000000..d0fec4a868
--- /dev/null
+++ b/apps/docs/content/components/table/selection-behavior.raw.jsx
@@ -0,0 +1,87 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ getKeyValue,
+ Radio,
+ RadioGroup,
+} from "@nextui-org/react";
+
+const rows = [
+ {
+ key: "1",
+ name: "Tony Reichert",
+ role: "CEO",
+ status: "Active",
+ },
+ {
+ key: "2",
+ name: "Zoey Lang",
+ role: "Technical Lead",
+ status: "Paused",
+ },
+ {
+ key: "3",
+ name: "Jane Fisher",
+ role: "Senior Developer",
+ status: "Active",
+ },
+ {
+ key: "4",
+ name: "William Howard",
+ role: "Community Manager",
+ status: "Vacation",
+ },
+];
+
+const columns = [
+ {
+ key: "name",
+ label: "NAME",
+ },
+ {
+ key: "role",
+ label: "ROLE",
+ },
+ {
+ key: "status",
+ label: "STATUS",
+ },
+];
+
+export default function App() {
+ const [selectionBehavior, setSelectionBehavior] = React.useState("toggle");
+
+ return (
+
+
+
+ {(column) => {column.label}}
+
+
+ {(item) => (
+
+ {(columnKey) => {getKeyValue(item, columnKey)}}
+
+ )}
+
+
+
+ Toggle
+ Replace
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/selection-behavior.ts b/apps/docs/content/components/table/selection-behavior.ts
index 566480015f..b36dec6d8b 100644
--- a/apps/docs/content/components/table/selection-behavior.ts
+++ b/apps/docs/content/components/table/selection-behavior.ts
@@ -1,80 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue, Radio, RadioGroup} from "@nextui-org/react";
-
-const rows = [
- {
- key: "1",
- name: "Tony Reichert",
- role: "CEO",
- status: "Active",
- },
- {
- key: "2",
- name: "Zoey Lang",
- role: "Technical Lead",
- status: "Paused",
- },
- {
- key: "3",
- name: "Jane Fisher",
- role: "Senior Developer",
- status: "Active",
- },
- {
- key: "4",
- name: "William Howard",
- role: "Community Manager",
- status: "Vacation",
- },
-];
-
-const columns = [
- {
- key: "name",
- label: "NAME",
- },
- {
- key: "role",
- label: "ROLE",
- },
- {
- key: "status",
- label: "STATUS",
- },
-];
-
-export default function App() {
- const [selectionBehavior, setSelectionBehavior] = React.useState("toggle");
-
- return (
-
-
-
- {(column) => {column.label}}
-
-
- {(item) => (
-
- {(columnKey) => {getKeyValue(item, columnKey)}}
-
- )}
-
-
-
- Toggle
- Replace
-
-
- );
-}`;
+import App from "./selection-behavior.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/single-selection.raw.jsx b/apps/docs/content/components/table/single-selection.raw.jsx
new file mode 100644
index 0000000000..35122ba3f8
--- /dev/null
+++ b/apps/docs/content/components/table/single-selection.raw.jsx
@@ -0,0 +1,67 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ RadioGroup,
+ Radio,
+} from "@nextui-org/react";
+
+const colors = ["default", "primary", "secondary", "success", "warning", "danger"];
+
+export default function App() {
+ const [selectedColor, setSelectedColor] = React.useState("default");
+
+ return (
+
+
+
+ NAME
+ ROLE
+ STATUS
+
+
+
+ Tony Reichert
+ CEO
+ Active
+
+
+ Zoey Lang
+ Technical Lead
+ Paused
+
+
+ Jane Fisher
+ Senior Developer
+ Active
+
+
+ William Howard
+ Community Manager
+ Vacation
+
+
+
+
+ {colors.map((color) => (
+
+ {color}
+
+ ))}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/single-selection.ts b/apps/docs/content/components/table/single-selection.ts
index e187ab933c..65d8454ff8 100644
--- a/apps/docs/content/components/table/single-selection.ts
+++ b/apps/docs/content/components/table/single-selection.ts
@@ -1,66 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, RadioGroup, Radio} from "@nextui-org/react";
-
-const colors = ["default", "primary", "secondary", "success", "warning", "danger"];
-
-export default function App() {
- const [selectedColor, setSelectedColor] = React.useState("default");
-
- return (
-
-
-
- NAME
- ROLE
- STATUS
-
-
-
- Tony Reichert
- CEO
- Active
-
-
- Zoey Lang
- Technical Lead
- Paused
-
-
- Jane Fisher
- Senior Developer
- Active
-
-
- William Howard
- Community Manager
- Vacation
-
-
-
-
- {colors.map((color) => (
-
- {color}
-
- ))}
-
-
- );
-}`;
+import App from "./single-selection.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/sorting.raw.jsx b/apps/docs/content/components/table/sorting.raw.jsx
new file mode 100644
index 0000000000..ddc13bfbbb
--- /dev/null
+++ b/apps/docs/content/components/table/sorting.raw.jsx
@@ -0,0 +1,82 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ getKeyValue,
+ Spinner,
+} from "@nextui-org/react";
+import {useAsyncList} from "@react-stately/data";
+
+export default function App() {
+ const [isLoading, setIsLoading] = React.useState(true);
+
+ let list = useAsyncList({
+ async load({signal}) {
+ let res = await fetch("https://swapi.py4e.com/api/people/?search", {
+ signal,
+ });
+ let json = await res.json();
+
+ setIsLoading(false);
+
+ return {
+ items: json.results,
+ };
+ },
+ async sort({items, sortDescriptor}) {
+ return {
+ items: items.sort((a, b) => {
+ let first = a[sortDescriptor.column];
+ let second = b[sortDescriptor.column];
+ let cmp = (parseInt(first) || first) < (parseInt(second) || second) ? -1 : 1;
+
+ if (sortDescriptor.direction === "descending") {
+ cmp *= -1;
+ }
+
+ return cmp;
+ }),
+ };
+ },
+ });
+
+ return (
+
+
+
+ Name
+
+
+ Height
+
+
+ Mass
+
+
+ Birth year
+
+
+ }
+ >
+ {(item) => (
+
+ {(columnKey) => {getKeyValue(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/sorting.ts b/apps/docs/content/components/table/sorting.ts
index be3f41afb6..231fa295c0 100644
--- a/apps/docs/content/components/table/sorting.ts
+++ b/apps/docs/content/components/table/sorting.ts
@@ -1,75 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell, getKeyValue, Spinner} from "@nextui-org/react";
-import {useAsyncList} from "@react-stately/data";
-
-export default function App() {
- const [isLoading, setIsLoading] = React.useState(true);
-
- let list = useAsyncList({
- async load({signal}) {
- let res = await fetch('https://swapi.py4e.com/api/people/?search', {
- signal,
- });
- let json = await res.json();
- setIsLoading(false);
-
- return {
- items: json.results,
- };
- },
- async sort({items, sortDescriptor}) {
- return {
- items: items.sort((a, b) => {
- let first = a[sortDescriptor.column];
- let second = b[sortDescriptor.column];
- let cmp = (parseInt(first) || first) < (parseInt(second) || second) ? -1 : 1;
-
- if (sortDescriptor.direction === "descending") {
- cmp *= -1;
- }
-
- return cmp;
- }),
- };
- },
- });
-
- return (
-
-
-
- Name
-
-
- Height
-
-
- Mass
-
-
- Birth year
-
-
- }
- >
- {(item) => (
-
- {(columnKey) => {getKeyValue(item, columnKey)}}
-
- )}
-
-
- );
-}`;
+import App from "./sorting.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/striped.raw.jsx b/apps/docs/content/components/table/striped.raw.jsx
new file mode 100644
index 0000000000..a032ad7f63
--- /dev/null
+++ b/apps/docs/content/components/table/striped.raw.jsx
@@ -0,0 +1,35 @@
+import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell} from "@nextui-org/react";
+
+export default function App() {
+ return (
+
+
+ NAME
+ ROLE
+ STATUS
+
+
+
+ Tony Reichert
+ CEO
+ Active
+
+
+ Zoey Lang
+ Technical Lead
+ Paused
+
+
+ Jane Fisher
+ Senior Developer
+ Active
+
+
+ William Howard
+ Community Manager
+ Vacation
+
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/striped.ts b/apps/docs/content/components/table/striped.ts
index 2d9f32ff59..efcbdde82e 100644
--- a/apps/docs/content/components/table/striped.ts
+++ b/apps/docs/content/components/table/striped.ts
@@ -1,38 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell} from "@nextui-org/react";
-
-export default function App() {
- return (
-
-
- NAME
- ROLE
- STATUS
-
-
-
- Tony Reichert
- CEO
- Active
-
-
- Zoey Lang
- Technical Lead
- Paused
-
-
- Jane Fisher
- Senior Developer
- Active
-
-
- William Howard
- Community Manager
- Vacation
-
-
-
- );
-}`;
+import App from "./striped.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/usage.raw.jsx b/apps/docs/content/components/table/usage.raw.jsx
new file mode 100644
index 0000000000..b6a8bf0c51
--- /dev/null
+++ b/apps/docs/content/components/table/usage.raw.jsx
@@ -0,0 +1,35 @@
+import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell} from "@nextui-org/react";
+
+export default function App() {
+ return (
+
+
+ NAME
+ ROLE
+ STATUS
+
+
+
+ Tony Reichert
+ CEO
+ Active
+
+
+ Zoey Lang
+ Technical Lead
+ Paused
+
+
+ Jane Fisher
+ Senior Developer
+ Active
+
+
+ William Howard
+ Community Manager
+ Vacation
+
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/usage.ts b/apps/docs/content/components/table/usage.ts
index b6e06ec81f..1118304c37 100644
--- a/apps/docs/content/components/table/usage.ts
+++ b/apps/docs/content/components/table/usage.ts
@@ -1,38 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell} from "@nextui-org/react";
-
-export default function App() {
- return (
-
-
- NAME
- ROLE
- STATUS
-
-
-
- Tony Reichert
- CEO
- Active
-
-
- Zoey Lang
- Technical Lead
- Paused
-
-
- Jane Fisher
- Senior Developer
- Active
-
-
- William Howard
- Community Manager
- Vacation
-
-
-
- );
-}`;
+import App from "./usage.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/use-case.raw.jsx b/apps/docs/content/components/table/use-case.raw.jsx
new file mode 100644
index 0000000000..b1bbeaf73c
--- /dev/null
+++ b/apps/docs/content/components/table/use-case.raw.jsx
@@ -0,0 +1,640 @@
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ Input,
+ Button,
+ DropdownTrigger,
+ Dropdown,
+ DropdownMenu,
+ DropdownItem,
+ Chip,
+ User,
+ Pagination,
+} from "@nextui-org/react";
+
+export const columns = [
+ {name: "ID", uid: "id", sortable: true},
+ {name: "NAME", uid: "name", sortable: true},
+ {name: "AGE", uid: "age", sortable: true},
+ {name: "ROLE", uid: "role", sortable: true},
+ {name: "TEAM", uid: "team"},
+ {name: "EMAIL", uid: "email"},
+ {name: "STATUS", uid: "status", sortable: true},
+ {name: "ACTIONS", uid: "actions"},
+];
+
+export const statusOptions = [
+ {name: "Active", uid: "active"},
+ {name: "Paused", uid: "paused"},
+ {name: "Vacation", uid: "vacation"},
+];
+
+export const users = [
+ {
+ id: 1,
+ name: "Tony Reichert",
+ role: "CEO",
+ team: "Management",
+ status: "active",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
+ email: "tony.reichert@example.com",
+ },
+ {
+ id: 2,
+ name: "Zoey Lang",
+ role: "Tech Lead",
+ team: "Development",
+ status: "paused",
+ age: "25",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
+ email: "zoey.lang@example.com",
+ },
+ {
+ id: 3,
+ name: "Jane Fisher",
+ role: "Sr. Dev",
+ team: "Development",
+ status: "active",
+ age: "22",
+ avatar: "https://i.pravatar.cc/150?u=a04258114e29026702d",
+ email: "jane.fisher@example.com",
+ },
+ {
+ id: 4,
+ name: "William Howard",
+ role: "C.M.",
+ team: "Marketing",
+ status: "vacation",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?u=a048581f4e29026701d",
+ email: "william.howard@example.com",
+ },
+ {
+ id: 5,
+ name: "Kristen Copper",
+ role: "S. Manager",
+ team: "Sales",
+ status: "active",
+ age: "24",
+ avatar: "https://i.pravatar.cc/150?u=a092581d4ef9026700d",
+ email: "kristen.cooper@example.com",
+ },
+ {
+ id: 6,
+ name: "Brian Kim",
+ role: "P. Manager",
+ team: "Management",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
+ email: "brian.kim@example.com",
+ status: "Active",
+ },
+ {
+ id: 7,
+ name: "Michael Hunt",
+ role: "Designer",
+ team: "Design",
+ status: "paused",
+ age: "27",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29027007d",
+ email: "michael.hunt@example.com",
+ },
+ {
+ id: 8,
+ name: "Samantha Brooks",
+ role: "HR Manager",
+ team: "HR",
+ status: "active",
+ age: "31",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e27027008d",
+ email: "samantha.brooks@example.com",
+ },
+ {
+ id: 9,
+ name: "Frank Harrison",
+ role: "F. Manager",
+ team: "Finance",
+ status: "vacation",
+ age: "33",
+ avatar: "https://i.pravatar.cc/150?img=4",
+ email: "frank.harrison@example.com",
+ },
+ {
+ id: 10,
+ name: "Emma Adams",
+ role: "Ops Manager",
+ team: "Operations",
+ status: "active",
+ age: "35",
+ avatar: "https://i.pravatar.cc/150?img=5",
+ email: "emma.adams@example.com",
+ },
+ {
+ id: 11,
+ name: "Brandon Stevens",
+ role: "Jr. Dev",
+ team: "Development",
+ status: "active",
+ age: "22",
+ avatar: "https://i.pravatar.cc/150?img=8",
+ email: "brandon.stevens@example.com",
+ },
+ {
+ id: 12,
+ name: "Megan Richards",
+ role: "P. Manager",
+ team: "Product",
+ status: "paused",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?img=10",
+ email: "megan.richards@example.com",
+ },
+ {
+ id: 13,
+ name: "Oliver Scott",
+ role: "S. Manager",
+ team: "Security",
+ status: "active",
+ age: "37",
+ avatar: "https://i.pravatar.cc/150?img=12",
+ email: "oliver.scott@example.com",
+ },
+ {
+ id: 14,
+ name: "Grace Allen",
+ role: "M. Specialist",
+ team: "Marketing",
+ status: "active",
+ age: "30",
+ avatar: "https://i.pravatar.cc/150?img=16",
+ email: "grace.allen@example.com",
+ },
+ {
+ id: 15,
+ name: "Noah Carter",
+ role: "IT Specialist",
+ team: "I. Technology",
+ status: "paused",
+ age: "31",
+ avatar: "https://i.pravatar.cc/150?img=15",
+ email: "noah.carter@example.com",
+ },
+ {
+ id: 16,
+ name: "Ava Perez",
+ role: "Manager",
+ team: "Sales",
+ status: "active",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?img=20",
+ email: "ava.perez@example.com",
+ },
+ {
+ id: 17,
+ name: "Liam Johnson",
+ role: "Data Analyst",
+ team: "Analysis",
+ status: "active",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?img=33",
+ email: "liam.johnson@example.com",
+ },
+ {
+ id: 18,
+ name: "Sophia Taylor",
+ role: "QA Analyst",
+ team: "Testing",
+ status: "active",
+ age: "27",
+ avatar: "https://i.pravatar.cc/150?img=29",
+ email: "sophia.taylor@example.com",
+ },
+ {
+ id: 19,
+ name: "Lucas Harris",
+ role: "Administrator",
+ team: "Information Technology",
+ status: "paused",
+ age: "32",
+ avatar: "https://i.pravatar.cc/150?img=50",
+ email: "lucas.harris@example.com",
+ },
+ {
+ id: 20,
+ name: "Mia Robinson",
+ role: "Coordinator",
+ team: "Operations",
+ status: "active",
+ age: "26",
+ avatar: "https://i.pravatar.cc/150?img=45",
+ email: "mia.robinson@example.com",
+ },
+];
+
+export function capitalize(s) {
+ return s ? s.charAt(0).toUpperCase() + s.slice(1).toLowerCase() : "";
+}
+
+export const PlusIcon = ({size = 24, width, height, ...props}) => {
+ return (
+
+ );
+};
+
+export const VerticalDotsIcon = ({size = 24, width, height, ...props}) => {
+ return (
+
+ );
+};
+
+export const SearchIcon = (props) => {
+ return (
+
+ );
+};
+
+export const ChevronDownIcon = ({strokeWidth = 1.5, ...otherProps}) => {
+ return (
+
+ );
+};
+
+const statusColorMap = {
+ active: "success",
+ paused: "danger",
+ vacation: "warning",
+};
+
+const INITIAL_VISIBLE_COLUMNS = ["name", "role", "status", "actions"];
+
+export default function App() {
+ const [filterValue, setFilterValue] = React.useState("");
+ const [selectedKeys, setSelectedKeys] = React.useState(new Set([]));
+ const [visibleColumns, setVisibleColumns] = React.useState(new Set(INITIAL_VISIBLE_COLUMNS));
+ const [statusFilter, setStatusFilter] = React.useState("all");
+ const [rowsPerPage, setRowsPerPage] = React.useState(5);
+ const [sortDescriptor, setSortDescriptor] = React.useState({
+ column: "age",
+ direction: "ascending",
+ });
+ const [page, setPage] = React.useState(1);
+
+ const hasSearchFilter = Boolean(filterValue);
+
+ const headerColumns = React.useMemo(() => {
+ if (visibleColumns === "all") return columns;
+
+ return columns.filter((column) => Array.from(visibleColumns).includes(column.uid));
+ }, [visibleColumns]);
+
+ const filteredItems = React.useMemo(() => {
+ let filteredUsers = [...users];
+
+ if (hasSearchFilter) {
+ filteredUsers = filteredUsers.filter((user) =>
+ user.name.toLowerCase().includes(filterValue.toLowerCase()),
+ );
+ }
+ if (statusFilter !== "all" && Array.from(statusFilter).length !== statusOptions.length) {
+ filteredUsers = filteredUsers.filter((user) =>
+ Array.from(statusFilter).includes(user.status),
+ );
+ }
+
+ return filteredUsers;
+ }, [users, filterValue, statusFilter]);
+
+ const pages = Math.ceil(filteredItems.length / rowsPerPage);
+
+ const items = React.useMemo(() => {
+ const start = (page - 1) * rowsPerPage;
+ const end = start + rowsPerPage;
+
+ return filteredItems.slice(start, end);
+ }, [page, filteredItems, rowsPerPage]);
+
+ const sortedItems = React.useMemo(() => {
+ return [...items].sort((a, b) => {
+ const first = a[sortDescriptor.column];
+ const second = b[sortDescriptor.column];
+ const cmp = first < second ? -1 : first > second ? 1 : 0;
+
+ return sortDescriptor.direction === "descending" ? -cmp : cmp;
+ });
+ }, [sortDescriptor, items]);
+
+ const renderCell = React.useCallback((user, columnKey) => {
+ const cellValue = user[columnKey];
+
+ switch (columnKey) {
+ case "name":
+ return (
+
+ {user.email}
+
+ );
+ case "role":
+ return (
+
+
{cellValue}
+
{user.team}
+
+ );
+ case "status":
+ return (
+
+ {cellValue}
+
+ );
+ case "actions":
+ return (
+
+
+
+
+
+
+ View
+ Edit
+ Delete
+
+
+
+ );
+ default:
+ return cellValue;
+ }
+ }, []);
+
+ const onNextPage = React.useCallback(() => {
+ if (page < pages) {
+ setPage(page + 1);
+ }
+ }, [page, pages]);
+
+ const onPreviousPage = React.useCallback(() => {
+ if (page > 1) {
+ setPage(page - 1);
+ }
+ }, [page]);
+
+ const onRowsPerPageChange = React.useCallback((e) => {
+ setRowsPerPage(Number(e.target.value));
+ setPage(1);
+ }, []);
+
+ const onSearchChange = React.useCallback((value) => {
+ if (value) {
+ setFilterValue(value);
+ setPage(1);
+ } else {
+ setFilterValue("");
+ }
+ }, []);
+
+ const onClear = React.useCallback(() => {
+ setFilterValue("");
+ setPage(1);
+ }, []);
+
+ const topContent = React.useMemo(() => {
+ return (
+
+
+
}
+ value={filterValue}
+ onClear={() => onClear()}
+ onValueChange={onSearchChange}
+ />
+
+
+
+ } variant="flat">
+ Status
+
+
+
+ {statusOptions.map((status) => (
+
+ {capitalize(status.name)}
+
+ ))}
+
+
+
+
+ } variant="flat">
+ Columns
+
+
+
+ {columns.map((column) => (
+
+ {capitalize(column.name)}
+
+ ))}
+
+
+ }>
+ Add New
+
+
+
+
+ Total {users.length} users
+
+
+
+ );
+ }, [
+ filterValue,
+ statusFilter,
+ visibleColumns,
+ onRowsPerPageChange,
+ users.length,
+ onSearchChange,
+ hasSearchFilter,
+ ]);
+
+ const bottomContent = React.useMemo(() => {
+ return (
+
+
+ {selectedKeys === "all"
+ ? "All items selected"
+ : `${selectedKeys.size} of ${filteredItems.length} selected`}
+
+
+
+
+
+
+
+ );
+ }, [selectedKeys, items.length, page, pages, hasSearchFilter]);
+
+ return (
+
+
+ {(column) => (
+
+ {column.name}
+
+ )}
+
+
+ {(item) => (
+
+ {(columnKey) => {renderCell(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/use-case.raw.tsx b/apps/docs/content/components/table/use-case.raw.tsx
new file mode 100644
index 0000000000..e5c0113e35
--- /dev/null
+++ b/apps/docs/content/components/table/use-case.raw.tsx
@@ -0,0 +1,653 @@
+import React, {SVGProps} from "react";
+import {
+ Table,
+ TableHeader,
+ TableColumn,
+ TableBody,
+ TableRow,
+ TableCell,
+ Input,
+ Button,
+ DropdownTrigger,
+ Dropdown,
+ DropdownMenu,
+ DropdownItem,
+ Chip,
+ User,
+ Pagination,
+ Selection,
+ ChipProps,
+ SortDescriptor,
+} from "@nextui-org/react";
+
+export type IconSvgProps = SVGProps & {
+ size?: number;
+};
+
+export function capitalize(s: string) {
+ return s ? s.charAt(0).toUpperCase() + s.slice(1).toLowerCase() : "";
+}
+
+export const PlusIcon = ({size = 24, width, height, ...props}: IconSvgProps) => {
+ return (
+
+ );
+};
+
+export const VerticalDotsIcon = ({size = 24, width, height, ...props}: IconSvgProps) => {
+ return (
+
+ );
+};
+
+export const SearchIcon = (props: IconSvgProps) => {
+ return (
+
+ );
+};
+
+export const ChevronDownIcon = ({strokeWidth = 1.5, ...otherProps}: IconSvgProps) => {
+ return (
+
+ );
+};
+
+export const columns = [
+ {name: "ID", uid: "id", sortable: true},
+ {name: "NAME", uid: "name", sortable: true},
+ {name: "AGE", uid: "age", sortable: true},
+ {name: "ROLE", uid: "role", sortable: true},
+ {name: "TEAM", uid: "team"},
+ {name: "EMAIL", uid: "email"},
+ {name: "STATUS", uid: "status", sortable: true},
+ {name: "ACTIONS", uid: "actions"},
+];
+
+export const statusOptions = [
+ {name: "Active", uid: "active"},
+ {name: "Paused", uid: "paused"},
+ {name: "Vacation", uid: "vacation"},
+];
+
+export const users = [
+ {
+ id: 1,
+ name: "Tony Reichert",
+ role: "CEO",
+ team: "Management",
+ status: "active",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
+ email: "tony.reichert@example.com",
+ },
+ {
+ id: 2,
+ name: "Zoey Lang",
+ role: "Tech Lead",
+ team: "Development",
+ status: "paused",
+ age: "25",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
+ email: "zoey.lang@example.com",
+ },
+ {
+ id: 3,
+ name: "Jane Fisher",
+ role: "Sr. Dev",
+ team: "Development",
+ status: "active",
+ age: "22",
+ avatar: "https://i.pravatar.cc/150?u=a04258114e29026702d",
+ email: "jane.fisher@example.com",
+ },
+ {
+ id: 4,
+ name: "William Howard",
+ role: "C.M.",
+ team: "Marketing",
+ status: "vacation",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?u=a048581f4e29026701d",
+ email: "william.howard@example.com",
+ },
+ {
+ id: 5,
+ name: "Kristen Copper",
+ role: "S. Manager",
+ team: "Sales",
+ status: "active",
+ age: "24",
+ avatar: "https://i.pravatar.cc/150?u=a092581d4ef9026700d",
+ email: "kristen.cooper@example.com",
+ },
+ {
+ id: 6,
+ name: "Brian Kim",
+ role: "P. Manager",
+ team: "Management",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
+ email: "brian.kim@example.com",
+ status: "Active",
+ },
+ {
+ id: 7,
+ name: "Michael Hunt",
+ role: "Designer",
+ team: "Design",
+ status: "paused",
+ age: "27",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e29027007d",
+ email: "michael.hunt@example.com",
+ },
+ {
+ id: 8,
+ name: "Samantha Brooks",
+ role: "HR Manager",
+ team: "HR",
+ status: "active",
+ age: "31",
+ avatar: "https://i.pravatar.cc/150?u=a042581f4e27027008d",
+ email: "samantha.brooks@example.com",
+ },
+ {
+ id: 9,
+ name: "Frank Harrison",
+ role: "F. Manager",
+ team: "Finance",
+ status: "vacation",
+ age: "33",
+ avatar: "https://i.pravatar.cc/150?img=4",
+ email: "frank.harrison@example.com",
+ },
+ {
+ id: 10,
+ name: "Emma Adams",
+ role: "Ops Manager",
+ team: "Operations",
+ status: "active",
+ age: "35",
+ avatar: "https://i.pravatar.cc/150?img=5",
+ email: "emma.adams@example.com",
+ },
+ {
+ id: 11,
+ name: "Brandon Stevens",
+ role: "Jr. Dev",
+ team: "Development",
+ status: "active",
+ age: "22",
+ avatar: "https://i.pravatar.cc/150?img=8",
+ email: "brandon.stevens@example.com",
+ },
+ {
+ id: 12,
+ name: "Megan Richards",
+ role: "P. Manager",
+ team: "Product",
+ status: "paused",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?img=10",
+ email: "megan.richards@example.com",
+ },
+ {
+ id: 13,
+ name: "Oliver Scott",
+ role: "S. Manager",
+ team: "Security",
+ status: "active",
+ age: "37",
+ avatar: "https://i.pravatar.cc/150?img=12",
+ email: "oliver.scott@example.com",
+ },
+ {
+ id: 14,
+ name: "Grace Allen",
+ role: "M. Specialist",
+ team: "Marketing",
+ status: "active",
+ age: "30",
+ avatar: "https://i.pravatar.cc/150?img=16",
+ email: "grace.allen@example.com",
+ },
+ {
+ id: 15,
+ name: "Noah Carter",
+ role: "IT Specialist",
+ team: "I. Technology",
+ status: "paused",
+ age: "31",
+ avatar: "https://i.pravatar.cc/150?img=15",
+ email: "noah.carter@example.com",
+ },
+ {
+ id: 16,
+ name: "Ava Perez",
+ role: "Manager",
+ team: "Sales",
+ status: "active",
+ age: "29",
+ avatar: "https://i.pravatar.cc/150?img=20",
+ email: "ava.perez@example.com",
+ },
+ {
+ id: 17,
+ name: "Liam Johnson",
+ role: "Data Analyst",
+ team: "Analysis",
+ status: "active",
+ age: "28",
+ avatar: "https://i.pravatar.cc/150?img=33",
+ email: "liam.johnson@example.com",
+ },
+ {
+ id: 18,
+ name: "Sophia Taylor",
+ role: "QA Analyst",
+ team: "Testing",
+ status: "active",
+ age: "27",
+ avatar: "https://i.pravatar.cc/150?img=29",
+ email: "sophia.taylor@example.com",
+ },
+ {
+ id: 19,
+ name: "Lucas Harris",
+ role: "Administrator",
+ team: "Information Technology",
+ status: "paused",
+ age: "32",
+ avatar: "https://i.pravatar.cc/150?img=50",
+ email: "lucas.harris@example.com",
+ },
+ {
+ id: 20,
+ name: "Mia Robinson",
+ role: "Coordinator",
+ team: "Operations",
+ status: "active",
+ age: "26",
+ avatar: "https://i.pravatar.cc/150?img=45",
+ email: "mia.robinson@example.com",
+ },
+];
+
+const statusColorMap: Record = {
+ active: "success",
+ paused: "danger",
+ vacation: "warning",
+};
+
+const INITIAL_VISIBLE_COLUMNS = ["name", "role", "status", "actions"];
+
+type User = (typeof users)[0];
+
+export default function App() {
+ const [filterValue, setFilterValue] = React.useState("");
+ const [selectedKeys, setSelectedKeys] = React.useState(new Set([]));
+ const [visibleColumns, setVisibleColumns] = React.useState(
+ new Set(INITIAL_VISIBLE_COLUMNS),
+ );
+ const [statusFilter, setStatusFilter] = React.useState("all");
+ const [rowsPerPage, setRowsPerPage] = React.useState(5);
+ const [sortDescriptor, setSortDescriptor] = React.useState({
+ column: "age",
+ direction: "ascending",
+ });
+
+ const [page, setPage] = React.useState(1);
+
+ const hasSearchFilter = Boolean(filterValue);
+
+ const headerColumns = React.useMemo(() => {
+ if (visibleColumns === "all") return columns;
+
+ return columns.filter((column) => Array.from(visibleColumns).includes(column.uid));
+ }, [visibleColumns]);
+
+ const filteredItems = React.useMemo(() => {
+ let filteredUsers = [...users];
+
+ if (hasSearchFilter) {
+ filteredUsers = filteredUsers.filter((user) =>
+ user.name.toLowerCase().includes(filterValue.toLowerCase()),
+ );
+ }
+ if (statusFilter !== "all" && Array.from(statusFilter).length !== statusOptions.length) {
+ filteredUsers = filteredUsers.filter((user) =>
+ Array.from(statusFilter).includes(user.status),
+ );
+ }
+
+ return filteredUsers;
+ }, [users, filterValue, statusFilter]);
+
+ const pages = Math.ceil(filteredItems.length / rowsPerPage);
+
+ const items = React.useMemo(() => {
+ const start = (page - 1) * rowsPerPage;
+ const end = start + rowsPerPage;
+
+ return filteredItems.slice(start, end);
+ }, [page, filteredItems, rowsPerPage]);
+
+ const sortedItems = React.useMemo(() => {
+ return [...items].sort((a: User, b: User) => {
+ const first = a[sortDescriptor.column as keyof User] as number;
+ const second = b[sortDescriptor.column as keyof User] as number;
+ const cmp = first < second ? -1 : first > second ? 1 : 0;
+
+ return sortDescriptor.direction === "descending" ? -cmp : cmp;
+ });
+ }, [sortDescriptor, items]);
+
+ const renderCell = React.useCallback((user: User, columnKey: React.Key) => {
+ const cellValue = user[columnKey as keyof User];
+
+ switch (columnKey) {
+ case "name":
+ return (
+
+ {user.email}
+
+ );
+ case "role":
+ return (
+
+
{cellValue}
+
{user.team}
+
+ );
+ case "status":
+ return (
+
+ {cellValue}
+
+ );
+ case "actions":
+ return (
+
+
+
+
+
+
+ View
+ Edit
+ Delete
+
+
+
+ );
+ default:
+ return cellValue;
+ }
+ }, []);
+
+ const onNextPage = React.useCallback(() => {
+ if (page < pages) {
+ setPage(page + 1);
+ }
+ }, [page, pages]);
+
+ const onPreviousPage = React.useCallback(() => {
+ if (page > 1) {
+ setPage(page - 1);
+ }
+ }, [page]);
+
+ const onRowsPerPageChange = React.useCallback((e: React.ChangeEvent) => {
+ setRowsPerPage(Number(e.target.value));
+ setPage(1);
+ }, []);
+
+ const onSearchChange = React.useCallback((value?: string) => {
+ if (value) {
+ setFilterValue(value);
+ setPage(1);
+ } else {
+ setFilterValue("");
+ }
+ }, []);
+
+ const onClear = React.useCallback(() => {
+ setFilterValue("");
+ setPage(1);
+ }, []);
+
+ const topContent = React.useMemo(() => {
+ return (
+
+
+
}
+ value={filterValue}
+ onClear={() => onClear()}
+ onValueChange={onSearchChange}
+ />
+
+
+
+ } variant="flat">
+ Status
+
+
+
+ {statusOptions.map((status) => (
+
+ {capitalize(status.name)}
+
+ ))}
+
+
+
+
+ } variant="flat">
+ Columns
+
+
+
+ {columns.map((column) => (
+
+ {capitalize(column.name)}
+
+ ))}
+
+
+ }>
+ Add New
+
+
+
+
+ Total {users.length} users
+
+
+
+ );
+ }, [
+ filterValue,
+ statusFilter,
+ visibleColumns,
+ onSearchChange,
+ onRowsPerPageChange,
+ users.length,
+ hasSearchFilter,
+ ]);
+
+ const bottomContent = React.useMemo(() => {
+ return (
+
+
+ {selectedKeys === "all"
+ ? "All items selected"
+ : `${selectedKeys.size} of ${filteredItems.length} selected`}
+
+
+
+
+
+
+
+ );
+ }, [selectedKeys, items.length, page, pages, hasSearchFilter]);
+
+ return (
+
+
+ {(column) => (
+
+ {column.name}
+
+ )}
+
+
+ {(item) => (
+
+ {(columnKey) => {renderCell(item, columnKey)}}
+
+ )}
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/use-case.ts b/apps/docs/content/components/table/use-case.ts
index b46e960e7c..a03774d7c8 100644
--- a/apps/docs/content/components/table/use-case.ts
+++ b/apps/docs/content/components/table/use-case.ts
@@ -1,1324 +1,12 @@
-const data = `const columns = [
- {name: "ID", uid: "id", sortable: true},
- {name: "NAME", uid: "name", sortable: true},
- {name: "AGE", uid: "age", sortable: true},
- {name: "ROLE", uid: "role", sortable: true},
- {name: "TEAM", uid: "team"},
- {name: "EMAIL", uid: "email"},
- {name: "STATUS", uid: "status", sortable: true},
- {name: "ACTIONS", uid: "actions"},
-];
-
-const statusOptions = [
- {name: "Active", uid: "active"},
- {name: "Paused", uid: "paused"},
- {name: "Vacation", uid: "vacation"},
-];
-
-const users = [
- {
- id: 1,
- name: "Tony Reichert",
- role: "CEO",
- team: "Management",
- status: "active",
- age: "29",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
- email: "tony.reichert@example.com",
- },
- {
- id: 2,
- name: "Zoey Lang",
- role: "Tech Lead",
- team: "Development",
- status: "paused",
- age: "25",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
- email: "zoey.lang@example.com",
- },
- {
- id: 3,
- name: "Jane Fisher",
- role: "Sr. Dev",
- team: "Development",
- status: "active",
- age: "22",
- avatar: "https://i.pravatar.cc/150?u=a04258114e29026702d",
- email: "jane.fisher@example.com",
- },
- {
- id: 4,
- name: "William Howard",
- role: "C.M.",
- team: "Marketing",
- status: "vacation",
- age: "28",
- avatar: "https://i.pravatar.cc/150?u=a048581f4e29026701d",
- email: "william.howard@example.com",
- },
- {
- id: 5,
- name: "Kristen Copper",
- role: "S. Manager",
- team: "Sales",
- status: "active",
- age: "24",
- avatar: "https://i.pravatar.cc/150?u=a092581d4ef9026700d",
- email: "kristen.cooper@example.com",
- },
- {
- id: 6,
- name: "Brian Kim",
- role: "P. Manager",
- team: "Management",
- age: "29",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
- email: "brian.kim@example.com",
- status: "active",
- },
- {
- id: 7,
- name: "Michael Hunt",
- role: "Designer",
- team: "Design",
- status: "paused",
- age: "27",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29027007d",
- email: "michael.hunt@example.com",
- },
- {
- id: 8,
- name: "Samantha Brooks",
- role: "HR Manager",
- team: "HR",
- status: "active",
- age: "31",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e27027008d",
- email: "samantha.brooks@example.com",
- },
- {
- id: 9,
- name: "Frank Harrison",
- role: "F. Manager",
- team: "Finance",
- status: "vacation",
- age: "33",
- avatar: "https://i.pravatar.cc/150?img=4",
- email: "frank.harrison@example.com",
- },
- {
- id: 10,
- name: "Emma Adams",
- role: "Ops Manager",
- team: "Operations",
- status: "active",
- age: "35",
- avatar: "https://i.pravatar.cc/150?img=5",
- email: "emma.adams@example.com",
- },
- {
- id: 11,
- name: "Brandon Stevens",
- role: "Jr. Dev",
- team: "Development",
- status: "active",
- age: "22",
- avatar: "https://i.pravatar.cc/150?img=8",
- email: "brandon.stevens@example.com",
- },
- {
- id: 12,
- name: "Megan Richards",
- role: "P. Manager",
- team: "Product",
- status: "paused",
- age: "28",
- avatar: "https://i.pravatar.cc/150?img=10",
- email: "megan.richards@example.com",
- },
- {
- id: 13,
- name: "Oliver Scott",
- role: "S. Manager",
- team: "Security",
- status: "active",
- age: "37",
- avatar: "https://i.pravatar.cc/150?img=12",
- email: "oliver.scott@example.com",
- },
- {
- id: 14,
- name: "Grace Allen",
- role: "M. Specialist",
- team: "Marketing",
- status: "active",
- age: "30",
- avatar: "https://i.pravatar.cc/150?img=16",
- email: "grace.allen@example.com",
- },
- {
- id: 15,
- name: "Noah Carter",
- role: "IT Specialist",
- team: "I. Technology",
- status: "paused",
- age: "31",
- avatar: "https://i.pravatar.cc/150?img=15",
- email: "noah.carter@example.com",
- },
- {
- id: 16,
- name: "Ava Perez",
- role: "Manager",
- team: "Sales",
- status: "active",
- age: "29",
- avatar: "https://i.pravatar.cc/150?img=20",
- email: "ava.perez@example.com",
- },
- {
- id: 17,
- name: "Liam Johnson",
- role: "Data Analyst",
- team: "Analysis",
- status: "active",
- age: "28",
- avatar: "https://i.pravatar.cc/150?img=33",
- email: "liam.johnson@example.com",
- },
- {
- id: 18,
- name: "Sophia Taylor",
- role: "QA Analyst",
- team: "Testing",
- status: "active",
- age: "27",
- avatar: "https://i.pravatar.cc/150?img=29",
- email: "sophia.taylor@example.com",
- },
- {
- id: 19,
- name: "Lucas Harris",
- role: "Administrator",
- team: "Information Technology",
- status: "paused",
- age: "32",
- avatar: "https://i.pravatar.cc/150?img=50",
- email: "lucas.harris@example.com",
- },
- {
- id: 20,
- name: "Mia Robinson",
- role: "Coordinator",
- team: "Operations",
- status: "active",
- age: "26",
- avatar: "https://i.pravatar.cc/150?img=45",
- email: "mia.robinson@example.com",
- },
-];
-
-export {columns, users, statusOptions};`;
-
-const dataTs = `const columns = [
- {name: "ID", uid: "id", sortable: true},
- {name: "NAME", uid: "name", sortable: true},
- {name: "AGE", uid: "age", sortable: true},
- {name: "ROLE", uid: "role", sortable: true},
- {name: "TEAM", uid: "team"},
- {name: "EMAIL", uid: "email"},
- {name: "STATUS", uid: "status", sortable: true},
- {name: "ACTIONS", uid: "actions"},
-];
-
-const statusOptions = [
- {name: "Active", uid: "active"},
- {name: "Paused", uid: "paused"},
- {name: "Vacation", uid: "vacation"},
-];
-
-const users = [
- {
- id: 1,
- name: "Tony Reichert",
- role: "CEO",
- team: "Management",
- status: "active",
- age: "29",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
- email: "tony.reichert@example.com",
- },
- {
- id: 2,
- name: "Zoey Lang",
- role: "Tech Lead",
- team: "Development",
- status: "paused",
- age: "25",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29026704d",
- email: "zoey.lang@example.com",
- },
- {
- id: 3,
- name: "Jane Fisher",
- role: "Sr. Dev",
- team: "Development",
- status: "active",
- age: "22",
- avatar: "https://i.pravatar.cc/150?u=a04258114e29026702d",
- email: "jane.fisher@example.com",
- },
- {
- id: 4,
- name: "William Howard",
- role: "C.M.",
- team: "Marketing",
- status: "vacation",
- age: "28",
- avatar: "https://i.pravatar.cc/150?u=a048581f4e29026701d",
- email: "william.howard@example.com",
- },
- {
- id: 5,
- name: "Kristen Copper",
- role: "S. Manager",
- team: "Sales",
- status: "active",
- age: "24",
- avatar: "https://i.pravatar.cc/150?u=a092581d4ef9026700d",
- email: "kristen.cooper@example.com",
- },
- {
- id: 6,
- name: "Brian Kim",
- role: "P. Manager",
- team: "Management",
- age: "29",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
- email: "brian.kim@example.com",
- status: "Active",
- },
- {
- id: 7,
- name: "Michael Hunt",
- role: "Designer",
- team: "Design",
- status: "paused",
- age: "27",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e29027007d",
- email: "michael.hunt@example.com",
- },
- {
- id: 8,
- name: "Samantha Brooks",
- role: "HR Manager",
- team: "HR",
- status: "active",
- age: "31",
- avatar: "https://i.pravatar.cc/150?u=a042581f4e27027008d",
- email: "samantha.brooks@example.com",
- },
- {
- id: 9,
- name: "Frank Harrison",
- role: "F. Manager",
- team: "Finance",
- status: "vacation",
- age: "33",
- avatar: "https://i.pravatar.cc/150?img=4",
- email: "frank.harrison@example.com",
- },
- {
- id: 10,
- name: "Emma Adams",
- role: "Ops Manager",
- team: "Operations",
- status: "active",
- age: "35",
- avatar: "https://i.pravatar.cc/150?img=5",
- email: "emma.adams@example.com",
- },
- {
- id: 11,
- name: "Brandon Stevens",
- role: "Jr. Dev",
- team: "Development",
- status: "active",
- age: "22",
- avatar: "https://i.pravatar.cc/150?img=8",
- email: "brandon.stevens@example.com",
- },
- {
- id: 12,
- name: "Megan Richards",
- role: "P. Manager",
- team: "Product",
- status: "paused",
- age: "28",
- avatar: "https://i.pravatar.cc/150?img=10",
- email: "megan.richards@example.com",
- },
- {
- id: 13,
- name: "Oliver Scott",
- role: "S. Manager",
- team: "Security",
- status: "active",
- age: "37",
- avatar: "https://i.pravatar.cc/150?img=12",
- email: "oliver.scott@example.com",
- },
- {
- id: 14,
- name: "Grace Allen",
- role: "M. Specialist",
- team: "Marketing",
- status: "active",
- age: "30",
- avatar: "https://i.pravatar.cc/150?img=16",
- email: "grace.allen@example.com",
- },
- {
- id: 15,
- name: "Noah Carter",
- role: "IT Specialist",
- team: "I. Technology",
- status: "paused",
- age: "31",
- avatar: "https://i.pravatar.cc/150?img=15",
- email: "noah.carter@example.com",
- },
- {
- id: 16,
- name: "Ava Perez",
- role: "Manager",
- team: "Sales",
- status: "active",
- age: "29",
- avatar: "https://i.pravatar.cc/150?img=20",
- email: "ava.perez@example.com",
- },
- {
- id: 17,
- name: "Liam Johnson",
- role: "Data Analyst",
- team: "Analysis",
- status: "active",
- age: "28",
- avatar: "https://i.pravatar.cc/150?img=33",
- email: "liam.johnson@example.com",
- },
- {
- id: 18,
- name: "Sophia Taylor",
- role: "QA Analyst",
- team: "Testing",
- status: "active",
- age: "27",
- avatar: "https://i.pravatar.cc/150?img=29",
- email: "sophia.taylor@example.com",
- },
- {
- id: 19,
- name: "Lucas Harris",
- role: "Administrator",
- team: "Information Technology",
- status: "paused",
- age: "32",
- avatar: "https://i.pravatar.cc/150?img=50",
- email: "lucas.harris@example.com",
- },
- {
- id: 20,
- name: "Mia Robinson",
- role: "Coordinator",
- team: "Operations",
- status: "active",
- age: "26",
- avatar: "https://i.pravatar.cc/150?img=45",
- email: "mia.robinson@example.com",
- },
-];
-
-export {columns, users, statusOptions};`;
-
-const types = `import {SVGProps} from "react";
-
-export type IconSvgProps = SVGProps & {
- size?: number;
-};`;
-
-const utils = `export function capitalize(s) {
- return s ? s.charAt(0).toUpperCase() + s.slice(1).toLowerCase() : "";
-}`;
-
-const PlusIcon = `export const PlusIcon = ({size = 24, width, height, ...props}) => (
-
-);`;
-
-const VerticalDotsIcon = `export const VerticalDotsIcon = ({size = 24, width, height, ...props}) => (
-
-);`;
-
-const SearchIcon = `export const SearchIcon = (props) => (
-
-);`;
-
-const ChevronDownIcon = `export const ChevronDownIcon = ({strokeWidth = 1.5, ...otherProps}) => (
-
-);`;
-
-const utilsTs = `export function capitalize(s: string) {
- return s ? s.charAt(0).toUpperCase() + s.slice(1).toLowerCase() : "";
-}`;
-
-const PlusIconTs = `import {IconSvgProps} from "./types";
-
-export const PlusIcon = ({size = 24, width, height, ...props}: IconSvgProps) => (
-
-);`;
-
-const VerticalDotsIconTs = `import {IconSvgProps} from "./types";
-
-export const VerticalDotsIcon = ({size = 24, width, height, ...props}: IconSvgProps) => (
-
-);`;
-
-const SearchIconTs = `import {IconSvgProps} from "./types";
-
-export const SearchIcon = (props: IconSvgProps) => (
-
-);`;
-
-const ChevronDownIconTs = `import {IconSvgProps} from "./types";
-
-export const ChevronDownIcon = ({strokeWidth = 1.5, ...otherProps}: IconSvgProps) => (
-
-);`;
-
-const App = `import {
- Table,
- TableHeader,
- TableColumn,
- TableBody,
- TableRow,
- TableCell,
- Input,
- Button,
- DropdownTrigger,
- Dropdown,
- DropdownMenu,
- DropdownItem,
- Chip,
- User,
- Pagination,
-} from "@nextui-org/react";
-import {PlusIcon} from "./PlusIcon";
-import {VerticalDotsIcon} from "./VerticalDotsIcon";
-import {SearchIcon} from "./SearchIcon";
-import {ChevronDownIcon} from "./ChevronDownIcon";
-import {columns, users, statusOptions} from "./data";
-import {capitalize} from "./utils";
-
-const statusColorMap = {
- active: "success",
- paused: "danger",
- vacation: "warning",
-};
-
-const INITIAL_VISIBLE_COLUMNS = ["name", "role", "status", "actions"];
-
-export default function App() {
- const [filterValue, setFilterValue] = React.useState("");
- const [selectedKeys, setSelectedKeys] = React.useState(new Set([]));
- const [visibleColumns, setVisibleColumns] = React.useState(new Set(INITIAL_VISIBLE_COLUMNS));
- const [statusFilter, setStatusFilter] = React.useState("all");
- const [rowsPerPage, setRowsPerPage] = React.useState(5);
- const [sortDescriptor, setSortDescriptor] = React.useState({
- column: "age",
- direction: "ascending",
- });
- const [page, setPage] = React.useState(1);
-
- const hasSearchFilter = Boolean(filterValue);
-
- const headerColumns = React.useMemo(() => {
- if (visibleColumns === "all") return columns;
-
- return columns.filter((column) => Array.from(visibleColumns).includes(column.uid));
- }, [visibleColumns]);
-
- const filteredItems = React.useMemo(() => {
- let filteredUsers = [...users];
-
- if (hasSearchFilter) {
- filteredUsers = filteredUsers.filter((user) =>
- user.name.toLowerCase().includes(filterValue.toLowerCase()),
- );
- }
- if (statusFilter !== "all" && Array.from(statusFilter).length !== statusOptions.length) {
- filteredUsers = filteredUsers.filter((user) =>
- Array.from(statusFilter).includes(user.status),
- );
- }
-
- return filteredUsers;
- }, [users, filterValue, statusFilter]);
-
- const pages = Math.ceil(filteredItems.length / rowsPerPage);
-
- const items = React.useMemo(() => {
- const start = (page - 1) * rowsPerPage;
- const end = start + rowsPerPage;
-
- return filteredItems.slice(start, end);
- }, [page, filteredItems, rowsPerPage]);
-
- const sortedItems = React.useMemo(() => {
- return [...items].sort((a, b) => {
- const first = a[sortDescriptor.column];
- const second = b[sortDescriptor.column];
- const cmp = first < second ? -1 : first > second ? 1 : 0;
-
- return sortDescriptor.direction === "descending" ? -cmp : cmp;
- });
- }, [sortDescriptor, items]);
-
- const renderCell = React.useCallback((user, columnKey) => {
- const cellValue = user[columnKey];
-
- switch (columnKey) {
- case "name":
- return (
-
- {user.email}
-
- );
- case "role":
- return (
-
-
{cellValue}
-
{user.team}
-
- );
- case "status":
- return (
-
- {cellValue}
-
- );
- case "actions":
- return (
-
-
-
-
-
-
- View
- Edit
- Delete
-
-
-
- );
- default:
- return cellValue;
- }
- }, []);
-
- const onNextPage = React.useCallback(() => {
- if (page < pages) {
- setPage(page + 1);
- }
- }, [page, pages]);
-
- const onPreviousPage = React.useCallback(() => {
- if (page > 1) {
- setPage(page - 1);
- }
- }, [page]);
-
- const onRowsPerPageChange = React.useCallback((e) => {
- setRowsPerPage(Number(e.target.value));
- setPage(1);
- }, []);
-
- const onSearchChange = React.useCallback((value) => {
- if (value) {
- setFilterValue(value);
- setPage(1);
- } else {
- setFilterValue("");
- }
- }, []);
-
- const onClear = React.useCallback(()=>{
- setFilterValue("")
- setPage(1)
- },[])
-
- const topContent = React.useMemo(() => {
- return (
-
-
-
}
- value={filterValue}
- onClear={() => onClear()}
- onValueChange={onSearchChange}
- />
-
-
-
- } variant="flat">
- Status
-
-
-
- {statusOptions.map((status) => (
-
- {capitalize(status.name)}
-
- ))}
-
-
-
-
- } variant="flat">
- Columns
-
-
-
- {columns.map((column) => (
-
- {capitalize(column.name)}
-
- ))}
-
-
- }>
- Add New
-
-
-
-
- Total {users.length} users
-
-
-
- );
- }, [
- filterValue,
- statusFilter,
- visibleColumns,
- onRowsPerPageChange,
- users.length,
- onSearchChange,
- hasSearchFilter,
- ]);
-
- const bottomContent = React.useMemo(() => {
- return (
-
-
- {selectedKeys === "all"
- ? "All items selected"
- : \`\${selectedKeys.size} of \${filteredItems.length} selected\`}
-
-
-
-
-
-
-
- );
- }, [selectedKeys, items.length, page, pages, hasSearchFilter]);
-
- return (
-
-
- {(column) => (
-
- {column.name}
-
- )}
-
-
- {(item) => (
-
- {(columnKey) => {renderCell(item, columnKey)}}
-
- )}
-
-
- );
-}`;
-
-const AppTs = `import {
- Table,
- TableHeader,
- TableColumn,
- TableBody,
- TableRow,
- TableCell,
- Input,
- Button,
- DropdownTrigger,
- Dropdown,
- DropdownMenu,
- DropdownItem,
- Chip,
- User,
- Pagination,
- Selection,
- ChipProps,
- SortDescriptor
-} from "@nextui-org/react";
-import {PlusIcon} from "./PlusIcon";
-import {VerticalDotsIcon} from "./VerticalDotsIcon";
-import {ChevronDownIcon} from "./ChevronDownIcon";
-import {SearchIcon} from "./SearchIcon";
-import {columns, users, statusOptions} from "./data";
-import {capitalize} from "./utils";
-
-const statusColorMap: Record = {
- active: "success",
- paused: "danger",
- vacation: "warning",
-};
-
-const INITIAL_VISIBLE_COLUMNS = ["name", "role", "status", "actions"];
-
-type User = typeof users[0];
-
-export default function App() {
- const [filterValue, setFilterValue] = React.useState("");
- const [selectedKeys, setSelectedKeys] = React.useState(new Set([]));
- const [visibleColumns, setVisibleColumns] = React.useState(new Set(INITIAL_VISIBLE_COLUMNS));
- const [statusFilter, setStatusFilter] = React.useState("all");
- const [rowsPerPage, setRowsPerPage] = React.useState(5);
- const [sortDescriptor, setSortDescriptor] = React.useState({
- column: "age",
- direction: "ascending",
- });
-
- const [page, setPage] = React.useState(1);
-
- const hasSearchFilter = Boolean(filterValue);
-
- const headerColumns = React.useMemo(() => {
- if (visibleColumns === "all") return columns;
-
- return columns.filter((column) => Array.from(visibleColumns).includes(column.uid));
- }, [visibleColumns]);
-
- const filteredItems = React.useMemo(() => {
- let filteredUsers = [...users];
-
- if (hasSearchFilter) {
- filteredUsers = filteredUsers.filter((user) =>
- user.name.toLowerCase().includes(filterValue.toLowerCase()),
- );
- }
- if (statusFilter !== "all" && Array.from(statusFilter).length !== statusOptions.length) {
- filteredUsers = filteredUsers.filter((user) =>
- Array.from(statusFilter).includes(user.status),
- );
- }
-
- return filteredUsers;
- }, [users, filterValue, statusFilter]);
-
- const pages = Math.ceil(filteredItems.length / rowsPerPage);
-
- const items = React.useMemo(() => {
- const start = (page - 1) * rowsPerPage;
- const end = start + rowsPerPage;
-
- return filteredItems.slice(start, end);
- }, [page, filteredItems, rowsPerPage]);
-
- const sortedItems = React.useMemo(() => {
- return [...items].sort((a: User, b: User) => {
- const first = a[sortDescriptor.column as keyof User] as number;
- const second = b[sortDescriptor.column as keyof User] as number;
- const cmp = first < second ? -1 : first > second ? 1 : 0;
-
- return sortDescriptor.direction === "descending" ? -cmp : cmp;
- });
- }, [sortDescriptor, items]);
-
- const renderCell = React.useCallback((user: User, columnKey: React.Key) => {
- const cellValue = user[columnKey as keyof User];
-
- switch (columnKey) {
- case "name":
- return (
-
- {user.email}
-
- );
- case "role":
- return (
-
-
{cellValue}
-
{user.team}
-
- );
- case "status":
- return (
-
- {cellValue}
-
- );
- case "actions":
- return (
-
-
-
-
-
-
- View
- Edit
- Delete
-
-
-
- );
- default:
- return cellValue;
- }
- }, []);
-
- const onNextPage = React.useCallback(() => {
- if (page < pages) {
- setPage(page + 1);
- }
- }, [page, pages]);
-
- const onPreviousPage = React.useCallback(() => {
- if (page > 1) {
- setPage(page - 1);
- }
- }, [page]);
-
- const onRowsPerPageChange = React.useCallback((e: React.ChangeEvent) => {
- setRowsPerPage(Number(e.target.value));
- setPage(1);
- }, []);
-
- const onSearchChange = React.useCallback((value?: string) => {
- if (value) {
- setFilterValue(value);
- setPage(1);
- } else {
- setFilterValue("");
- }
- }, []);
-
- const onClear = React.useCallback(()=>{
- setFilterValue("")
- setPage(1)
- },[])
-
- const topContent = React.useMemo(() => {
- return (
-
-
-
}
- value={filterValue}
- onClear={() => onClear()}
- onValueChange={onSearchChange}
- />
-
-
-
- } variant="flat">
- Status
-
-
-
- {statusOptions.map((status) => (
-
- {capitalize(status.name)}
-
- ))}
-
-
-
-
- } variant="flat">
- Columns
-
-
-
- {columns.map((column) => (
-
- {capitalize(column.name)}
-
- ))}
-
-
- }>
- Add New
-
-
-
-
- Total {users.length} users
-
-
-
- );
- }, [
- filterValue,
- statusFilter,
- visibleColumns,
- onSearchChange,
- onRowsPerPageChange,
- users.length,
- hasSearchFilter,
- ]);
-
- const bottomContent = React.useMemo(() => {
- return (
-
-
- {selectedKeys === "all"
- ? "All items selected"
- : \`\${selectedKeys.size} of \${filteredItems.length} selected\`}
-
-
-
-
-
-
-
- );
- }, [selectedKeys, items.length, page, pages, hasSearchFilter]);
-
- return (
-
-
- {(column) => (
-
- {column.name}
-
- )}
-
-
- {(item) => (
-
- {(columnKey) => {renderCell(item, columnKey)}}
-
- )}
-
-
- );
-}`;
+import App from "./use-case.raw.jsx?raw";
+import AppTs from "./use-case.raw.tsx?raw";
const react = {
"/App.jsx": App,
- "/data.js": data,
- "/utils.js": utils,
- "/PlusIcon.jsx": PlusIcon,
- "/SearchIcon.jsx": SearchIcon,
- "/ChevronDownIcon.jsx": ChevronDownIcon,
- "/VerticalDotsIcon.jsx": VerticalDotsIcon,
};
const reactTs = {
"/App.tsx": AppTs,
- "/types.ts": types,
- "/data.ts": dataTs,
- "/utils.ts": utilsTs,
- "/PlusIcon.tsx": PlusIconTs,
- "/VerticalDotsIcon.tsx": VerticalDotsIconTs,
- "/SearchIcon.tsx": SearchIconTs,
- "/ChevronDownIcon.tsx": ChevronDownIconTs,
};
export default {
diff --git a/apps/docs/content/components/table/without-header.raw.jsx b/apps/docs/content/components/table/without-header.raw.jsx
new file mode 100644
index 0000000000..e5506cc19f
--- /dev/null
+++ b/apps/docs/content/components/table/without-header.raw.jsx
@@ -0,0 +1,35 @@
+import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell} from "@nextui-org/react";
+
+export default function App() {
+ return (
+
+
+ NAME
+ ROLE
+ STATUS
+
+
+
+ Tony Reichert
+ CEO
+ Active
+
+
+ Zoey Lang
+ Technical Lead
+ Paused
+
+
+ Jane Fisher
+ Senior Developer
+ Active
+
+
+ William Howard
+ Community Manager
+ Vacation
+
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/without-header.ts b/apps/docs/content/components/table/without-header.ts
index 18c4b55d98..90f0321bcc 100644
--- a/apps/docs/content/components/table/without-header.ts
+++ b/apps/docs/content/components/table/without-header.ts
@@ -1,38 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell} from "@nextui-org/react";
-
-export default function App() {
- return (
-
-
- NAME
- ROLE
- STATUS
-
-
-
- Tony Reichert
- CEO
- Active
-
-
- Zoey Lang
- Technical Lead
- Paused
-
-
- Jane Fisher
- Senior Developer
- Active
-
-
- William Howard
- Community Manager
- Vacation
-
-
-
- );
-}`;
+import App from "./without-header.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/components/table/without-wrapper.raw.jsx b/apps/docs/content/components/table/without-wrapper.raw.jsx
new file mode 100644
index 0000000000..26d6e38715
--- /dev/null
+++ b/apps/docs/content/components/table/without-wrapper.raw.jsx
@@ -0,0 +1,35 @@
+import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell} from "@nextui-org/react";
+
+export default function App() {
+ return (
+
+
+ NAME
+ ROLE
+ STATUS
+
+
+
+ Tony Reichert
+ CEO
+ Active
+
+
+ Zoey Lang
+ Technical Lead
+ Paused
+
+
+ Jane Fisher
+ Senior Developer
+ Active
+
+
+ William Howard
+ Community Manager
+ Vacation
+
+
+
+ );
+}
diff --git a/apps/docs/content/components/table/without-wrapper.ts b/apps/docs/content/components/table/without-wrapper.ts
index 74e22f5a2a..326e580709 100644
--- a/apps/docs/content/components/table/without-wrapper.ts
+++ b/apps/docs/content/components/table/without-wrapper.ts
@@ -1,38 +1,4 @@
-const App = `import {Table, TableHeader, TableColumn, TableBody, TableRow, TableCell} from "@nextui-org/react";
-
-export default function App() {
- return (
-
-
- NAME
- ROLE
- STATUS
-
-
-
- Tony Reichert
- CEO
- Active
-
-
- Zoey Lang
- Technical Lead
- Paused
-
-
- Jane Fisher
- Senior Developer
- Active
-
-
- William Howard
- Community Manager
- Vacation
-
-
-
- );
-}`;
+import App from "./without-wrapper.raw.jsx?raw";
const react = {
"/App.jsx": App,
diff --git a/apps/docs/content/docs/components/table.mdx b/apps/docs/content/docs/components/table.mdx
index 5415aa1e65..afa8e40228 100644
--- a/apps/docs/content/docs/components/table.mdx
+++ b/apps/docs/content/docs/components/table.mdx
@@ -43,20 +43,20 @@ NextUI exports 6 table-related components:
@@ -300,7 +300,6 @@ Table also supports infinite pagination. To do so, you can use the `useAsyncList
```jsx
import { useInfiniteScroll } from "@nextui-org/use-infinite-scroll";
-
import { useAsyncList } from "@react-stately/data";
```