React Registry
A lightweight, fully typed React component for building powerful data tables β with sorting, filtering, and user-friendly UI out of the box.
β¨ Features
-
β Column sorting β click a column header to sort
-
β Per-column filtering β click the filter icon in any header to filter that column
-
β Fully typed β TypeScript support included
-
β Zero dependencies β no heavy UI libraries
-
β Easy to customize β clean, modular code
-
β Two usage modes:
-
Registryβ smart component (ready to use) -
Tableβ compound UI components (full control) -
β Utility hooks:
useTableSort,useTableFilterfor custom logic
π Quick Start
Install:
npm install @bulak/react-registry
Baβ¦
React Registry
A lightweight, fully typed React component for building powerful data tables β with sorting, filtering, and user-friendly UI out of the box.
β¨ Features
-
β Column sorting β click a column header to sort
-
β Per-column filtering β click the filter icon in any header to filter that column
-
β Fully typed β TypeScript support included
-
β Zero dependencies β no heavy UI libraries
-
β Easy to customize β clean, modular code
-
β Two usage modes:
-
Registryβ smart component (ready to use) -
Tableβ compound UI components (full control) -
β Utility hooks:
useTableSort,useTableFilterfor custom logic
π Quick Start
Install:
npm install @bulak/react-registry
Basic usage (Registry):
import { Registry, RegistryHeader } from '@bulak/react-registry';
const DATA = [
{ id: 1, fullName: 'Harry Potter', employeeNumber: 1, age: 18 },
];
const HEADERS: RegistryHeader<(typeof DATA)[number]>[] = [
{ key: 'fullName', width: 'calc(50% - 26px)', label: 'Full name' },
{ key: 'employeeNumber', width: 'calc(50% - 26px)', label: 'Employee number' },
{ key: 'age', width: '50px', label: 'Age' },
];
export function App() {
return (
<Registry
data={DATA}
headers={HEADERS}
variant="bordered"
sortable={true}
filterable={true}
/>
);
}
π‘ For full control, use the Table compound component and utility hooks (see docs).
π¦ Whatβs Included
Components:
- Registry β smart table with built-in sorting & filtering
- Table β low-level compound component (Table.Header, Table.Body, Table.Row, etc.)
- Dropdown β utility for popups (Dropdown.Popup, Dropdown.Toggle, etc.)
Hooks:
- useTableFilter - manage sorting state
- useTableSort - manage filtering logic
Advanced Usage
Custom header rendering (with sort indicators)
Override the default header to add a popup component and display sort direction symbols:
import { Registry, RegistryHeader, SortDirection, Table } from '@bulak/react-registry';
import { DATA, HEADERS } from './constants';
import { useCallback, useRef, useState } from 'react';
import { ColumnPopup } from './column-popup';
import s from './styles.module.scss';
const getSortSymbol = (sortDir: SortDirection) => {
switch (sortDir) {
case 'asc':
return 'β';
case 'desc':
return 'β';
}
return '';
};
const getStatusSymbol = (status: string) => (status === 'active' ? 'β
' : 'β');
export function App() {
return (
<Registry
data={DATA}
headers={HEADERS}
variant={'bordered'}
layoutMode={'grid'}
sortable={true}
filterable={true}
className={s.customRegistry}
renderHeaderCell={{
Component: ({ header, setFilter, setSort, ...props }) => {
const ref = useRef<HTMLDivElement>(null);
const [opened, setOpened] = useState(false);
const toggle = useCallback(() => setOpened((prev) => !prev), []);
const filter = (value: string) =>
setFilter(header.key, value);
const sort = (sortDirection: SortDirection) =>
setSort(header.key, sortDirection);
return (
<Table.HeaderCell
index={props.index}
width={header.width}
onClick={toggle}
>
<div ref={ref}>
{props.children}
{getSortSymbol(props.sortDirection)}
</div>
{/* CUSTOM POPUP (see: Dropdown.Popup) */}
<ColumnPopup
{...props}
onFilter={filter}
onSort={sort}
onClose={toggle}
anchorRef={ref}
opened={opened}
/>
</Table.HeaderCell>
);
},
}}
renderCell={{
Content: (props) => {
if (props.columnKey === 'status')
return (
<div className={s.status}>
<div>{props.value}</div>
{getStatusSymbol(props.value)}
</div>
);
return props.value;
},
}}
/>
);
};
π‘renderHeaderCell gives you full control over header rendering while keeping sorting logic managed by Registry.
Fully custom table with compound components
Build your own table layout using low-level components:
import { Table, useTableSort } from '@bulak/react-registry';
import { DATA, HEADERS } from './constants';
import s from './styles.module.scss';
export function App() {
const { setSort, sortedData } = useTableSort(DATA);
return (
<Table variant={'striped'}>
<Table.Header className={s.header}>
<Table.HeaderCell index={-1} width={'70px'} className={s.indexCell}>
index
</Table.HeaderCell>
{HEADERS.map(({ key, width }, colIndex) => (
<Table.HeaderCell
key={key}
width={width}
index={colIndex}
onClick={() => setSort(key)}
>
{key}
</Table.HeaderCell>
))}
</Table.Header>
<Table.Body>
{sortedData.map((row, rowIndex) => (
<Table.Row key={row.id} index={rowIndex} className={s.row}>
<Table.Cell
rowIndex={rowIndex}
colIndex={-1}
className={s.indexCell}
>
{rowIndex}
</Table.Cell>
{HEADERS.map(({ key }, colIndex) => (
<Table.Cell
key={key}
colIndex={colIndex}
rowIndex={rowIndex}
>
{row[key as keyof typeof row]}
</Table.Cell>
))}
</Table.Row>
))}
</Table.Body>
</Table>
);
}
π Live Demo
See it in action: https://react-registry-azure.vercel.app/
π License
MIT Β© Kiyamov Bulat
π Support the Project
If React Registry saves you time, consider supporting its development!
You can send a one-time payment in USDT TRC20 and TON (The Open Network):
USDT TRC20 Address:
TC5a9vJtjYhpTq4wA4tAdHn4qnMskxfNq4
QR Code:
TON Address:
UQDorrj6m414colWjOAxhT9qAsuSG_dWrR-7YxujVwDUSGSZ
QR Code:
After payment, feel free to email me with your transaction hash β Iβll prioritize your feature requests or help with integration.
Thank you for your support! π