Row
One row of a list with a leading lane, a body, and an action lane
import { Row } from "@nyte-ai/ui";import { Row } from "@nyte-ai/ui/row";Both paths export the same component. Pick one per file.
One row of a list. Reach for it when a list needs its items to align down a column and share one hover, focus, and selection model.
Usage
- Size arrives from the list container, not from the row. Set
--nyte-row-height,--nyte-row-gap,--nyte-row-padding-inline, and--nyte-row-leading-sizeon the parent. There is no size or density prop. - Typography is inherited. The row declares no font family and no font size, so the surface owns
both.
Row.DescriptionandRow.Metastep down from whatever the surface set. - Put the click target on
Row.Primary, not on the row itself.Row.Actionsis a sibling of the primary, because a row whose whole shell is a button cannot contain one. interactivepaints the row's own fill. A surface that writes--_row-fillitself owns every state of it and leavesinteractiveoff.- Omit
Row.Bodywhen there is only a label. Use it to stack a description under the label.
Anatomy
<Row>
<Row.Backdrop />
<Row.Primary>
<Row.Leading />
<Row.Body>
<Row.Label />
<Row.Description />
</Row.Body>
<Row.Meta />
</Row.Primary>
<Row.Actions />
</Row>Examples
A clickable row
render on Row.Primary swaps the element. The row resets the user agent padding, border,
background, and font that a button or an a brings.
<Row interactive selected={id === currentId}>
<Row.Primary render={<button type="button" onClick={() => setCurrentId(id)} />}>
<Row.Leading>
<IconBubbleText size={16} />
</Row.Leading>
<Row.Label>{title}</Row.Label>
<Row.Meta>{updatedAt}</Row.Meta>
</Row.Primary>
</Row>A settings row
<Row>
<Row.Body>
<Row.Label>{setting.label}</Row.Label>
<Row.Description>{setting.owner}</Row.Description>
</Row.Body>
<Row.Actions>
<Switch.Root aria-label={setting.label} checked={setting.enabled} onCheckedChange={apply}>
<Switch.Thumb />
</Switch.Root>
</Row.Actions>
</Row>Actions on hover
revealActions hides the action lane until the row is hovered or holds focus. It sets
--_row-actions-opacity and --_row-actions-pointer-events, which a surface reads to reclaim the
room in the same frame rather than repeating the conditions.
<Row interactive revealActions>
<Row.Primary render={<button type="button" />}>
<Row.Label>{title}</Row.Label>
</Row.Primary>
<Row.Actions placement="overlay">
<button type="button" aria-label={`Stop ${title}`} />
</Row.Actions>
</Row>const styles = stylex.create({
label: { paddingInlineEnd: "calc(var(--_row-actions-opacity, 0) * 44px)" },
});placement="overlay" floats the lane over the row instead of taking space in it, so the whole row
stays clickable underneath. The surface reclaims the room itself.
A selection layer the surface animates
Row.Backdrop sits behind the row's content at z-index: -1. The row declares isolation: isolate
so the backdrop lands behind the row rather than behind the list.
<Row selected={selected}>
<Row.Backdrop render={<motion.span layoutId="selection" />} />
<Row.Primary render={<button type="button" />}>
<Row.Label>{title}</Row.Label>
</Row.Primary>
</Row>Sizing from the list
const styles = stylex.create({
list: {
"--nyte-row-height": "44px",
"--nyte-row-gap": "12px",
"--nyte-row-padding-inline": "12px",
"--nyte-row-leading-size": "16px",
},
});Props
Row
Renders a <div>. RowProps takes every <div> prop, with className and style replaced by
the styled versions, plus:
| Prop | Type | Default | Description |
|---|---|---|---|
interactive | boolean | false | Paints the row's own fill on hover, on focus within, and while selected. |
selected | boolean | false | Marks the row current. Sets data-selected. |
revealActions | boolean | false | Hides the action lane until the row is hovered or holds focus. |
render | ReactElement | ((props: HTMLProps) => ReactElement) | Replaces the element, or composes the row with another component. | |
className, style, xstyle | see Theming |
Row.Actions
Renders a <span>.
| Prop | Type | Default | Description |
|---|---|---|---|
placement | "inline" | "overlay" | "inline" | Takes space in the row, or floats over its trailing edge. |
RowActionsPlacement is the exported type for placement.
Parts
Every part renders a <span> and takes render, className, style, xstyle, and the props of
the element it renders.
| Part | Data slot | Description |
|---|---|---|
Row.Backdrop | row-backdrop | Sits behind the row's content, for a selection layer the surface animates. |
Row.Primary | row-primary | The click target, wrapping whichever parts should be clickable. |
Row.Leading | row-leading | A fixed lane, so labels align down the list whatever glyph each row carries. |
Row.Body | row-body | Stacks its children, so a label can carry a description under it. |
Row.Label | row-label | The row's title. Truncates with an ellipsis. |
Row.Description | row-description | A second line under the label. Truncates with an ellipsis. |
Row.Meta | row-meta | Trailing text such as a time or a count. Tabular figures. |
Row.Actions | row-actions | Actions, a switch, or a chevron. A sibling of the primary, never a child. |
CSS variables
The surface sets these. The row reads them.
| Variable | Default | Description |
|---|---|---|
--nyte-row-height | --nyte-control-height-md | Minimum height of the row. |
--nyte-row-gap | --nyte-control-padding-xs | Gap between the row's parts. |
--nyte-row-padding-inline | --nyte-control-padding-sm | Inline padding, and the overlay inset. |
--nyte-row-leading-size | auto | Width of the leading lane. |
--_row-fill | transparent | Background of the row. interactive sets it, so leave it off to own it. |
--_row-meta-color | --nyte-color-tertiary-foreground | Color of Row.Meta. |
revealActions sets the two below on the row, and Row.Actions reads them. A surface reads them
too, to move with the lane.
| Variable | Hidden | Hovered or focused within |
|---|---|---|
--_row-actions-opacity | 0 | 1 |
--_row-actions-pointer-events | none | auto |
See Tokens for the control and color variables these fall back to.
Accessibility
- The row is a
<div>with no role. Meaning comes from what you render inside it. Row.Primarytakes the focus ring on:focus-visible. The outline is inset by 2px, because a row sits flush in a scroll container where an outset ring would clip.Row.Backdropisaria-hidden. No other part is.selectedsetsdata-selectedand nothing else. Addaria-selectedoraria-currenton the element you render forRow.Primary.- An icon-only button inside
Row.Actionsneedsaria-label.revealActionshides the lane with opacity, so it stays in the tab order, and focus anywhere in the row brings it back.