Data

Data grid

Records people work in: sort, search and filter, select rows for bulk actions, open a row's menu or details, page through or scroll ten thousand, and size, pin and hide columns. A grid with one Tab stop and the arrow keys between cells; a narrow one shows cards.

Live example

Import

Each family is its own entry point, so a page loads only what it uses.

tsx
import { Badge } from "@nibapp/ui/components/badge";import { Button } from "@nibapp/ui/components/button";import { DataGrid } from "@nibapp/ui/components/data-grid";import { MenuItem, MenuSeparator } from "@nibapp/ui/components/menu";

Props

Each component's own props and variants, read from its source. What it also takes from an element or a Base UI part is named below its table.

Badge

Small, calm label: subtle tint + matching foreground. Never loud.

PropTypeDefaultDescription
variant"neutral" | "outline" | "success" | "warning" | "danger" | "info""neutral"
neutral
Quiet gray — metadata, counts, model names.
outline
Hairline only — for dense lists where fills get noisy.
info
Neutral wash + fg-muted ink, like every info surface; its `Info` icon is what says "info".
size"sm" | "md""md"
dotbooleanfalse

Leading status dot. Pair with text — the dot alone never carries meaning.

iconReactNode | false—

Leading icon. The info variant defaults to lucide `Info`: info is neutral, not the accent, so the icon is what tells it apart from a plain neutral badge. Pass your own icon to replace it, or `false` to hide it. A `dot` takes the icon's place.

Also takes .

Button

PropTypeDefaultDescription
variant"primary" | "secondary" | "ghost" | "quiet" | "danger" | "danger-ghost" | "link""secondary"
primary
Neutral ink: the main call to action. Actions are ink, never the accent.
secondary
Quiet surface with a hairline — the default for most actions.
ghost
No chrome until hovered — toolbars, inline actions.
quiet
Words that are also an action, in the text's own weight and laid out from the start, so they line up with the text around them: `xs` in a line (a header's crumbs, a title that renames), `sm` a toolbar's picker, `md` a row in a list or a popover ("Open settings", a sidebar's link).
danger
Destructive confirmation.
danger-ghost
Destructive but low emphasis.
link
Inline text action.
size"xs" | "sm" | "md" | "lg""md"
blockboolean—
truncateboolean—

The button may shrink below its label's width; the label then truncates with an ellipsis.

wrapboolean—

The label wraps onto more lines and the button grows, its `leading` icon on the first line: for words that are an action and may run long in another language (a tip). One line keeps the size.

loadingbooleanfalse

Shows a spinner, keeps the button's width, and blocks interaction.

leadingReactNode—

Icon rendered before the label.

trailingReactNode—

Icon or hint (e.g. <Kbd>) rendered after the label.

disabledReasonstring | undefined—

Disables the button and says why: the reason is its tooltip and its accessible description, and the button stays focusable (`aria-disabled`) so a keyboard reaches it.

Also takes .

DataGrid

Rows of records people work in: sort by any column (Shift adds a key), search, filter by a column's values, figures or dates, select rows for bulk actions, open a row's menu or details, page through or scroll a long list that draws only what's in view, and show, size and pin columns. A `grid` with one stop in the Tab order and the arrow keys between cells; sort, selection and results are announced. It owns its state or lets the caller own any part (`state`, `onStateChange`), and with `server` shows rows a server sorted, filtered and paged. Below `cardsBelow` px it shows each row as a card. For a few figures in a page, DataTable.

PropTypeDefaultDescription
rows (required)readonly Row[]—

The rows: all of them, or with `server`, the page the server sent for the current state.

columns (required)readonly DataGridColumn<Row>[]—
rowKey (required)(row: Row) => string—
rowHeader (required)string—

The column that names each row: its cells are row headers, and selection and menus say its value.

label (required)string—

What the grid holds ("Members"): its name for assistive technology.

size"sm" | "md" | "lg""md"

Row height and text: `sm` inside a pane, `md` a page's list, `lg` a roomy page. Default `md`.

statePartial<DataGridState>—

The parts of the state the caller owns; the grid owns the rest.

defaultStatePartial<DataGridState>—

Where the parts the grid owns start.

onStateChange(state: DataGridState) => void—

Every change, as the whole new state.

serverDataGridServer—

The caller sorts, searches, filters and pages (a server): the grid shows `rows` as they come.

searchboolean—

The search field. Default: when a column is searchable.

pageSizesreadonly number[] | falseDEFAULT_PAGE_SIZES

Rows a page to choose from (the first is the default), or `false` for one long list. Default 25, 50, 100.

selectableboolean | ((row: Row) => boolean)false

Rows can be selected (all of them, or those the function allows), with a bar for `bulkActions`.

bulkActions(bulk: DataGridBulk<Row>) => ReactNode—

The bar's actions for the selected rows.

rowActions(row: Row) => ReactNode—

A row's menu items (`MenuItem`s): its ⋯ button, and a right-click on it.

details(row: Row) => ReactNode—

A row's details, opened under it by its chevron.

onRowActivate(row: Row) => void—

Opening a row (Enter on it, or a click on its row header's link you render).

loadingbooleanfalse

The rows are on their way: placeholders when there are none yet, else the rows dimmed.

error{ readonly message: ReactNode; readonly retry?: () => void }—

The rows couldn't be loaded: why, and how to try again.

emptyReactNode—

What an empty grid says (no rows at all; a search or filter with no match has its own words).

toolbarReactNode—

Controls at the toolbar's end (an "Invite" button).

columnMenubooleantrue

The toolbar's Columns menu, to show and hide columns. Default `true`.

heightnumber | string—

The grid's height, which bounds its scroll: the header stays in view and a long list draws only what's in view. Default: as tall as its rows, or `min(70vh, 40rem)` for a long list.

virtualizeboolean—

Draw only the rows in view. Default: when more than 200 rows show at once.

cardsBelownumber640

Below this width (px, the grid's own) rows show as cards. Default 640.

classNamestring—

MenuItem

PropTypeDefaultDescription
variant"default" | "destructive""default"
destructive
Irreversible or data-losing actions. Tinted only on highlight so menus stay calm.
insetboolean—

Reserve the leading indicator column so plain items align with checkbox/radio items.

childrenReactNode—

Also takes the props of Base UI's Menu.Item, except children, and .

MenuSeparator

Also takes the props of Base UI's Menu.Separator.