Skip to main content

Rc Table

React table component with useful functions.

Installation


  1. Install the rc-table package.
npm i rc-table
  1. Create a table component, components/table.tsx
import React from "react";
import Table from "rc-table";
import { Empty, cn } from "rizzui";

export type ExtractProps<T> = T extends React.ComponentType<infer P> ? P : T;

const tableStyles = {
table:
"[&_.rc-table-content]:overflow-x-auto [&_table]:w-full [&_.rc-table-row:hover]:bg-muted/60",
thead:
"[&_thead]:text-left [&_thead]:rtl:text-right [&_th.rc-table-cell]:uppercase [&_th.rc-table-cell]:text-xs [&_th.rc-table-cell]:font-medium [&_th.rc-table-cell]:tracking-wide",
tCell:
"[&_.rc-table-cell]:px-3 [&_th.rc-table-cell]:py-3 [&_td.rc-table-cell]:py-4",
variants: {
classic:
"[&_thead]:bg-muted/50 [&_.rc-table-container]:border-x [&_.rc-table-container]:border-muted [&_td.rc-table-cell]:border-b [&_td.rc-table-cell]:border-muted [&_thead]:border-y [&_thead]:border-muted",
modern:
"[&_thead]:bg-muted/50 [&_td.rc-table-cell]:border-b [&_td.rc-table-cell]:border-muted",
minimal: "[&_thead]:bg-muted/50",
elegant:
"[&_thead]:border-y [&_thead]:border-muted [&_td.rc-table-cell]:border-b [&_td.rc-table-cell]:border-muted",
},
striped: "[&_.rc-table-row:nth-child(2n)_.rc-table-cell]:bg-muted/40",
};

type RCTableProps = ExtractProps<typeof Table>;

export interface TableProps
extends Omit<RCTableProps, "className" | "emptyText"> {
emptyText?: React.ReactElement;
variant?: keyof typeof tableStyles.variants;
striped?: boolean;
className?: string;
}

export default function RcTable({
striped,
variant = "classic",
emptyText,
className,
...props
}: TableProps) {
return (
<Table
className={cn(
tableStyles.table,
tableStyles.thead,
tableStyles.tCell,
tableStyles.variants[variant],
striped && tableStyles.striped,
className
)}
emptyText={emptyText ?? <Empty />}
{...props}
/>
);
}

RcTable.displayName = "Table";
  1. You need to create one more component for the table header cell
import React from "react";
import { cn } from "rizzui";

type TextAlign = "left" | "center" | "right";

export interface HeaderCellProps {
title: React.ReactNode;
width?: number;
align?: TextAlign;
ellipsis?: boolean;
sortable?: boolean;
ascending?: boolean;
iconClassName?: string;
className?: string;
}

function handleTextAlignment(align: TextAlign) {
if (align === "center") return "justify-center";
if (align === "right") return "justify-end rtl:justify-start";
return "";
}

export default function HeaderCell({
title,
align = "left",
width,
ellipsis,
sortable,
ascending,
iconClassName,
className,
}: HeaderCellProps) {
if (ellipsis && width === undefined) {
console.warn(
"When ellipsis is true make sure you are using the same column width in HeaderCell component too."
);
}

if (width !== undefined && ellipsis !== true) {
console.warn(
"width prop without ellipsis won't work, please set ellipsis prop true."
);
}

return (
<div
className={cn(
"flex items-center gap-1",
sortable && "cursor-pointer",
handleTextAlignment(align),
className
)}
>
<div
{...(ellipsis && { className: "truncate" })}
{...(ellipsis && width && { style: { width } })}
>
{title}
</div>

{sortable && (
<div className="inline-flex">
{ascending ? (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
className={cn("h-auto w-3", iconClassName)}
viewBox="0 0 16 16"
>
<path d="m7.247 4.86-4.796 5.481c-.566.647-.106 1.659.753 1.659h9.592a1 1 0 0 0 .753-1.659l-4.796-5.48a1 1 0 0 0-1.506 0z" />
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
className={cn("h-auto w-3", iconClassName)}
viewBox="0 0 16 16"
>
<path d="M7.247 11.14 2.451 5.658C1.885 5.013 2.345 4 3.204 4h9.592a1 1 0 0 1 .753 1.659l-4.796 5.48a1 1 0 0 1-1.506 0z" />
</svg>
)}
</div>
)}
</div>
);
}

HeaderCell.displayName = "HeaderCell";

Default

The default style of Table component.

Id
Employee
Designation
Phone Number
Email
Status
1
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
2
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
3
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
4
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
5
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
6
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
import React from "react";
import Table from "@components/table";
import HeaderCell from "@components/header-cell";
import { Checkbox, Avatar, Text, Badge } from "rizzui";

const initialData = [
{
id: "1",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/1.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "2",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/2.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "3",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/3.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "4",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/4.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "5",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/5.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "6",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/6.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
];

function getStatusBadge(status: string) {
switch (status.toLowerCase()) {
case "pending":
return <Badge variant="flat">{status}</Badge>;
case "active":
return (
<Badge variant="flat" color="success">
{status}
</Badge>
);
case "warning":
return (
<Badge variant="flat" color="warning">
{status}
</Badge>
);
case "danger":
return (
<Badge variant="flat" color="danger">
{status}
</Badge>
);
default:
return null;
}
}

const getColumns = (
order: string,
column: string,
onHeaderClick: (value: string) => any
) => [
{
title: <></>,
dataIndex: "checked",
key: "checked",
width: 50,
render: () => (
<div className="inline-flex cursor-pointer">
<Checkbox variant="flat" />
</div>
),
},
{
title: (
<HeaderCell
title="Id"
sortable
ascending={order === "asc" && column === "id"}
/>
),
onHeaderCell: () => onHeaderClick("id"),
dataIndex: "id",
key: "id",
width: 50,
},
{
title: <HeaderCell title="Employee" />,
dataIndex: "employee",
key: "employee",
width: 250,
render: (employee: any) => (
<div className="flex items-center">
<Avatar name="John Doe" src={employee.avatar} />
<div className="ml-3 rtl:ml-0 rtl:mr-3">
<Text as="h6" className="mb-0.5 !text-sm font-medium">
{employee.name}
</Text>
<Text as="p" className="text-xs text-gray-400">
{employee.userName}
</Text>
</div>
</div>
),
},
{
title: <HeaderCell title="Designation" />,
dataIndex: "designation",
key: "designation",
width: 320,
render: (designation: any) => (
<div>
<Text as="h6" className="mb-0.5 !text-sm font-medium">
{designation.role}
</Text>
<Text as="p" className="text-xs text-gray-400">
{designation.company}
</Text>
</div>
),
},
{
title: <HeaderCell title="Phone Number" />,
dataIndex: "phoneNumber",
key: "phoneNumber",
width: 200,
},
{
title: <HeaderCell title="Email" />,
dataIndex: "email",
key: "email",
width: 200,
},
{
title: <HeaderCell title="Status" />,
dataIndex: "status",
key: "status",
width: 120,
render: (value: string) => getStatusBadge(value),
},
{
title: <></>,
dataIndex: "action",
key: "action",
width: 120,
render: (_: string, row: any) => (
<div className="flex items-center gap-2">
<button
type="button"
className="text-primary underline"
onClick={() => alert(`Edit item #${row.id}`)}
>
Edit
</button>
<button type="button" className="underline">
View
</button>
</div>
),
},
];

export default function App() {
const [order, setOrder] = React.useState<string>("desc");
const [column, setColumn] = React.useState<string>("");
const [data, setData] = React.useState<typeof initialData>(initialData);
const onHeaderClick = (value: string) => ({
onClick: () => {
setColumn(value);
setOrder(order === "desc" ? "asc" : "desc");
if (order === "desc") {
// @ts-ignore
setData([...data.sort((a, b) => (a[value] > b[value] ? -1 : 1))]);
} else {
// @ts-ignore
setData([...data.sort((a, b) => (a[value] > b[value] ? 1 : -1))]);
}
},
});
const columns: any = React.useMemo(
() => getColumns(order, column, onHeaderClick),
[order, column, onHeaderClick]
);

return <Table data={data} columns={columns} className="text-sm" />;
}

Modern

You can change the style of Table by changing property variant.

Id
Employee
Designation
Phone Number
Email
Status
1
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
2
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
3
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
4
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
5
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
6
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
import React from "react";
import Table from "@components/table";
import HeaderCell from "@components/header-cell";
import { Checkbox, Avatar, Text, Badge } from "rizzui";

const initialData = [
{
id: "1",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/1.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "2",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/2.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "3",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/3.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "4",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/4.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "5",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/5.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "6",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/6.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
];

function getStatusBadge(status: string) {
switch (status.toLowerCase()) {
case "pending":
return <Badge variant="flat">{status}</Badge>;
case "active":
return (
<Badge variant="flat" color="success">
{status}
</Badge>
);
case "warning":
return (
<Badge variant="flat" color="warning">
{status}
</Badge>
);
case "danger":
return (
<Badge variant="flat" color="danger">
{status}
</Badge>
);
default:
return null;
}
}

const getColumns = (
order: string,
column: string,
onHeaderClick: (value: string) => any
) => [
{
title: <></>,
dataIndex: "checked",
key: "checked",
width: 50,
render: () => (
<div className="inline-flex cursor-pointer">
<Checkbox variant="flat" />
</div>
),
},
{
title: (
<HeaderCell
title="Id"
sortable
ascending={order === "asc" && column === "id"}
/>
),
onHeaderCell: () => onHeaderClick("id"),
dataIndex: "id",
key: "id",
width: 50,
},
{
title: <HeaderCell title="Employee" />,
dataIndex: "employee",
key: "employee",
width: 250,
render: (employee: any) => (
<div className="flex items-center">
<Avatar name="John Doe" src={employee.avatar} />
<div className="ml-3 rtl:ml-0 rtl:mr-3">
<Text as="h6" className="mb-0.5 !text-sm font-medium">
{employee.name}
</Text>
<Text as="p" className="text-xs text-gray-400">
{employee.userName}
</Text>
</div>
</div>
),
},
{
title: <HeaderCell title="Designation" />,
dataIndex: "designation",
key: "designation",
width: 320,
render: (designation: any) => (
<div>
<Text as="h6" className="mb-0.5 !text-sm font-medium">
{designation.role}
</Text>
<Text as="p" className="text-xs text-gray-400">
{designation.company}
</Text>
</div>
),
},
{
title: <HeaderCell title="Phone Number" />,
dataIndex: "phoneNumber",
key: "phoneNumber",
width: 200,
},
{
title: <HeaderCell title="Email" />,
dataIndex: "email",
key: "email",
width: 200,
},
{
title: <HeaderCell title="Status" />,
dataIndex: "status",
key: "status",
width: 120,
render: (value: string) => getStatusBadge(value),
},
{
title: <></>,
dataIndex: "action",
key: "action",
width: 120,
render: (_: string, row: any) => (
<div className="flex items-center gap-2">
<button
type="button"
className="text-primary underline"
onClick={() => alert(`Edit item #${row.id}`)}
>
Edit
</button>
<button type="button" className="underline">
View
</button>
</div>
),
},
];

export default function App() {
const [order, setOrder] = React.useState<string>("desc");
const [column, setColumn] = React.useState<string>("");
const [data, setData] = React.useState<typeof initialData>(initialData);
const onHeaderClick = (value: string) => ({
onClick: () => {
setColumn(value);
setOrder(order === "desc" ? "asc" : "desc");
if (order === "desc") {
// @ts-ignore
setData([...data.sort((a, b) => (a[value] > b[value] ? -1 : 1))]);
} else {
// @ts-ignore
setData([...data.sort((a, b) => (a[value] > b[value] ? 1 : -1))]);
}
},
});
const columns: any = React.useMemo(
() => getColumns(order, column, onHeaderClick),
[order, column, onHeaderClick]
);

return (
<Table data={data} columns={columns} className="text-sm" variant="modern" />
);
}

Elegant

You can change the style of Table by changing property variant.

Id
Employee
Designation
Phone Number
Email
Status
1
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
2
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
3
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
4
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
5
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
6
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
import React from "react";
import Table from "@components/table";
import HeaderCell from "@components/header-cell";
import { Checkbox, Avatar, Text, Badge } from "rizzui";

const initialData = [
{
id: "1",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/1.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "2",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/2.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "3",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/3.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "4",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/4.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "5",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/5.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "6",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/6.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
];

function getStatusBadge(status: string) {
switch (status.toLowerCase()) {
case "pending":
return <Badge variant="flat">{status}</Badge>;
case "active":
return (
<Badge variant="flat" color="success">
{status}
</Badge>
);
case "warning":
return (
<Badge variant="flat" color="warning">
{status}
</Badge>
);
case "danger":
return (
<Badge variant="flat" color="danger">
{status}
</Badge>
);
default:
return null;
}
}

const getColumns = (
order: string,
column: string,
onHeaderClick: (value: string) => any
) => [
{
title: <></>,
dataIndex: "checked",
key: "checked",
width: 50,
render: () => (
<div className="inline-flex cursor-pointer">
<Checkbox variant="flat" />
</div>
),
},
{
title: (
<HeaderCell
title="Id"
sortable
ascending={order === "asc" && column === "id"}
/>
),
onHeaderCell: () => onHeaderClick("id"),
dataIndex: "id",
key: "id",
width: 50,
},
{
title: <HeaderCell title="Employee" />,
dataIndex: "employee",
key: "employee",
width: 250,
render: (employee: any) => (
<div className="flex items-center">
<Avatar name="John Doe" src={employee.avatar} />
<div className="ml-3 rtl:ml-0 rtl:mr-3">
<Text as="h6" className="mb-0.5 !text-sm font-medium">
{employee.name}
</Text>
<Text as="p" className="text-xs text-gray-400">
{employee.userName}
</Text>
</div>
</div>
),
},
{
title: <HeaderCell title="Designation" />,
dataIndex: "designation",
key: "designation",
width: 320,
render: (designation: any) => (
<div>
<Text as="h6" className="mb-0.5 !text-sm font-medium">
{designation.role}
</Text>
<Text as="p" className="text-xs text-gray-400">
{designation.company}
</Text>
</div>
),
},
{
title: <HeaderCell title="Phone Number" />,
dataIndex: "phoneNumber",
key: "phoneNumber",
width: 200,
},
{
title: <HeaderCell title="Email" />,
dataIndex: "email",
key: "email",
width: 200,
},
{
title: <HeaderCell title="Status" />,
dataIndex: "status",
key: "status",
width: 120,
render: (value: string) => getStatusBadge(value),
},
{
title: <></>,
dataIndex: "action",
key: "action",
width: 120,
render: (_: string, row: any) => (
<div className="flex items-center gap-2">
<button
type="button"
className="text-primary underline"
onClick={() => alert(`Edit item #${row.id}`)}
>
Edit
</button>
<button type="button" className="underline">
View
</button>
</div>
),
},
];

export default function App() {
const [order, setOrder] = React.useState<string>("desc");
const [column, setColumn] = React.useState<string>("");
const [data, setData] = React.useState<typeof initialData>(initialData);
const onHeaderClick = (value: string) => ({
onClick: () => {
setColumn(value);
setOrder(order === "desc" ? "asc" : "desc");
if (order === "desc") {
// @ts-ignore
setData([...data.sort((a, b) => (a[value] > b[value] ? -1 : 1))]);
} else {
// @ts-ignore
setData([...data.sort((a, b) => (a[value] > b[value] ? 1 : -1))]);
}
},
});
const columns: any = React.useMemo(
() => getColumns(order, column, onHeaderClick),
[order, column, onHeaderClick]
);

return (
<Table
data={data}
columns={columns}
className="text-sm"
variant="elegant"
/>
);
}

Minimal

You can change the style of Table by changing property variant.

Id
Employee
Designation
Phone Number
Email
Status
1
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
2
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
3
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
4
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
5
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
6
John Doe
Jon Brown

@fredchaparro

Front-End Developer

REDQ

+880136987584jhondoe@aegonui.comActive
import React from "react";
import Table from "@components/table";
import HeaderCell from "@components/header-cell";
import { Checkbox, Avatar, Text, Badge } from "rizzui";

const initialData = [
{
id: "1",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/1.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "2",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/2.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "3",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/3.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "4",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/4.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "5",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/5.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
{
id: "6",
employee: {
name: "Jon Brown",
userName: "@fredchaparro",
avatar: "https://randomuser.me/api/portraits/men/6.jpg",
},
designation: {
role: "Front-End Developer",
company: "REDQ",
},
phoneNumber: "+880136987584",
email: "jhondoe@aegonui.com",
status: "Active",
},
];

function getStatusBadge(status: string) {
switch (status.toLowerCase()) {
case "pending":
return <Badge variant="flat">{status}</Badge>;
case "active":
return (
<Badge variant="flat" color="success">
{status}
</Badge>
);
case "warning":
return (
<Badge variant="flat" color="warning">
{status}
</Badge>
);
case "danger":
return (
<Badge variant="flat" color="danger">
{status}
</Badge>
);
default:
return null;
}
}

const getColumns = (
order: string,
column: string,
onHeaderClick: (value: string) => any
) => [
{
title: <></>,
dataIndex: "checked",
key: "checked",
width: 50,
render: () => (
<div className="inline-flex cursor-pointer">
<Checkbox variant="flat" />
</div>
),
},
{
title: (
<HeaderCell
title="Id"
sortable
ascending={order === "asc" && column === "id"}
/>
),
onHeaderCell: () => onHeaderClick("id"),
dataIndex: "id",
key: "id",
width: 50,
},
{
title: <HeaderCell title="Employee" />,
dataIndex: "employee",
key: "employee",
width: 250,
render: (employee: any) => (
<div className="flex items-center">
<Avatar name="John Doe" src={employee.avatar} />
<div className="ml-3 rtl:ml-0 rtl:mr-3">
<Text as="h6" className="mb-0.5 !text-sm font-medium">
{employee.name}
</Text>
<Text as="p" className="text-xs text-gray-400">
{employee.userName}
</Text>
</div>
</div>
),
},
{
title: <HeaderCell title="Designation" />,
dataIndex: "designation",
key: "designation",
width: 320,
render: (designation: any) => (
<div>
<Text as="h6" className="mb-0.5 !text-sm font-medium">
{designation.role}
</Text>
<Text as="p" className="text-xs text-gray-400">
{designation.company}
</Text>
</div>
),
},
{
title: <HeaderCell title="Phone Number" />,
dataIndex: "phoneNumber",
key: "phoneNumber",
width: 200,
},
{
title: <HeaderCell title="Email" />,
dataIndex: "email",
key: "email",
width: 200,
},
{
title: <HeaderCell title="Status" />,
dataIndex: "status",
key: "status",
width: 120,
render: (value: string) => getStatusBadge(value),
},
{
title: <></>,
dataIndex: "action",
key: "action",
width: 120,
render: (_: string, row: any) => (
<div className="flex items-center gap-2">
<button
type="button"
className="text-primary underline"
onClick={() => alert(`Edit item #${row.id}`)}
>
Edit
</button>
<button type="button" className="underline">
View
</button>
</div>
),
},
];

export default function App() {
const [order, setOrder] = React.useState<string>("desc");
const [column, setColumn] = React.useState<string>("");
const [data, setData] = React.useState<typeof initialData>(initialData);
const onHeaderClick = (value: string) => ({
onClick: () => {
setColumn(value);
setOrder(order === "desc" ? "asc" : "desc");
if (order === "desc") {
// @ts-ignore
setData([...data.sort((a, b) => (a[value] > b[value] ? -1 : 1))]);
} else {
// @ts-ignore
setData([...data.sort((a, b) => (a[value] > b[value] ? 1 : -1))]);
}
},
});
const columns: any = React.useMemo(
() => getColumns(order, column, onHeaderClick),
[order, column, onHeaderClick]
);

return (
<Table
data={data}
columns={columns}
className="text-sm"
variant="minimal"
/>
);
}

API Reference


Table Props

Here is the API documentation of the Table component.

PropsTypeDescriptionDefault
emptyTextReactNodeSet empty text, it will only appear when table has no data__
variantTableVariantsThe variants of the component are:"classic"
stripedbooleanAdd striping style__
classNamestringAdd custom classes for extra style__
idstring__
styleCSSProperties__
titlePanelRender<DefaultRecordType>__
captionReactNode__
datareadonly DefaultRecordType[]__
footerPanelRender<DefaultRecordType>__
summary((data: readonly DefaultRecordType[]) => ReactNode)__
prefixClsstring__
directionltr rtl__
expandedRowKeysKey[]__
defaultExpandedRowKeyskey[]__
expandedRowRenderExpandedRowRender<DefaultRecordType>__
expandRowByClickboolean__
expandIconRenderExpandIcon<DefaultRecordType>__
onExpand((expanded: boolean, record: DefaultRecordType) => void)__
onExpandedRowsChange((expandedKeys: Key[]) => void)__
defaultExpandAllRowsboolean__
indentSizenumber__
expandIconColumnIndexnumber__
expandedRowClassNameRowClassName<DefaultRecordType>__
childrenColumnNamestring__
columnsColumnsType<DefaultRecordType>__
rowKeystring GetRowKey<DefaultRecordType>__
tableLayoutfixed auto__
scrollTableScroll__
expandableExpandableConfig<DefaultRecordType>Config expand rows__
rowClassNamestring RowClassName<DefaultRecordType>__
showHeaderboolean__
componentsTableComponents<DefaultRecordType>__
onRowGetComponentProps<DefaultRecordType>__
onHeaderRowGetComponentProps<readonly ColumnType<DefaultRecordType>[]>__
internalHooksstring__
transformColumnsTableTransformColumns__
internalRefs{ body: MutableRefObject<HTMLDivElement>; }__
stickysticky tableSticky__

Table Variants

type TableVariants = "classic" | "modern" | "minimal" | "elegant";

Table Scroll

type TableScroll =
| { x?: string | number | true; y?: string | number }
| undefined;

Table Transform Columns

type TableTransformColumns = (
columns: ColumnsType<DefaultRecordType>
) => ColumnsType<DefaultRecordType>;