Skip to content

List

Stacks rows of the same shape vertically. Use it for navigation, settings, search results: anything that repeats.

tsx
import { List, ListItem } from 'neba';

<List>
  <ListItem startIcon={<GlobeIcon />} description="Deployed 4 minutes ago" onClick={open} selected>
    production
  </ListItem>
  <ListItem startIcon={<GlobeIcon />} description="Deployed 2 hours ago" onClick={open}>
    staging
  </ListItem>
</List>;

Props

List

PropTypeDefaultDescription
variantshared'solid' | 'outline' | 'text''outline'Weight of the surface. The sheet is never dyed, as on Box. Reach for text inside a Card: the card is already a sheet
sizeshared'xs' | 'sm' | 'md' | 'lg' | 'xl''md'The rows' type scale and padding. An axis of the list, not of any one row
colorshared'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'Semantic colour role. Arbitrary colour values are not accepted
densityshared'default' | 'compact''default'Padding only: never the height, never the type scale
elevationshared0 | 1 | 2 | 30Drop shadow depth. 0 means no shadow at all
dividersbooleanfalseSeparates the rows with a hairline instead of space. It changes more than it sounds like: the rules have to reach both edges, so the list gives up its inner padding and the rows give up their corners
renderuseRender.RenderPropRenders something other than a ul: render={<ol />} when the order is the point
childrenReactNodeThe ListItems

size and density are set on List only. They reach every ListItem through a context, so there is no need to repeat them per row.

ListItem

PropTypeDefaultDescription
startIconReactNodeContent before the label: an icon, an avatar, a status dot
endIconReactNodeContent after the label, inside the pressable area
descriptionReactNodeA second line under the label
actionReactNodeA control pinned to the end of the row. Deliberately outside the pressable area: a button inside a button is markup the browser rewrites on parse
onClick(event) => voidPassing it is what turns the row into a real button
hrefstringPassing it is what turns the row into a real link
selectedbooleanfalseThe chosen row: the open page, the current filter. A link gets aria-current="page" and a button aria-current="true"
disabledbooleanfalseUnavailable. Drops the colour family for neutral grey
childrenReactNodeThe label

Examples

dividers

dividers draws a rule between rows. The rules have to reach both edges of the sheet, so the list's inner padding and the rows' rounded corners go with them: rows become ruled lines rather than floating tiles.

variant

Use variant="text" inside a Card. The card is already a sheet, so the borders do not double up.

onClick · href · action

onClick or href makes the whole row a <button> or an <a> respectively. action is a separate control slot outside that pressable area: for a row that navigates when pressed but also carries a switch of its own.

Accessibility

  • List sets role="list" explicitly, because Tailwind's reset removes the bullets from <ul> and Safari drops the list semantics with them.
  • A ListItem shell is always an <li>, with a <button> or an <a> inside it depending on onClick and href.
  • selected puts aria-current="page" on a link and aria-current="true" on a button. Not aria-pressed: a selected row is not a toggle.

Released under the MIT License