Skip to main contentSkip to docs navigation

Structured containers for related content, with flush, plain, numbered, and horizontal layout variants.

Overview

<List> renders a structured container for related content, with consistent spacing, borders, and typography through Chassis's design token system. Beyond plain items, it supports interactive elements, custom content, and composition with other components.

Basic usage

<List> and <ListItem> build an unordered list, establishing the spacing, borders, and typography the rest of this doc builds on.

  • Cras justo odio
  • Dapibus ac facilisis in
  • Morbi leo risus
  • Porta ac consectetur ac
  • Vestibulum at eros
JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List>
      <ListItem>Cras justo odio</ListItem>
      <ListItem>Dapibus ac facilisis in</ListItem>
      <ListItem>Morbi leo risus</ListItem>
      <ListItem>Porta ac consectetur ac</ListItem>
      <ListItem>Vestibulum at eros</ListItem>
    </List>
  )
}

Data-driven usage

Pass an items array to render the list from data instead of composing <ListItem> children. Each item accepts label, href, color, active, and disabled.

JSX
import { List } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List
      items={[
        { label: 'Dashboard', href: '#', active: true },
        { label: 'Profile', href: '#' },
        { label: 'Settings', href: '#' },
        { label: 'Billing', href: '#', disabled: true }
      ]}
    />
  )
}

Each item's color remaps it to one of the context colors below.

  • Default item
  • Primary item
  • Success item
  • Danger item
  • Warning item
JSX
import { List } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List
      items={[
        { label: 'Default item' },
        { label: 'Primary item', color: 'primary' },
        { label: 'Success item', color: 'success' },
        { label: 'Danger item', color: 'danger' },
        { label: 'Warning item', color: 'warning' }
      ]}
    />
  )
}

Active items

Add the active boolean prop to a <ListItem> to mark it as the current selection. An active item gets an aria-current="true" attribute automatically.

  • Cras justo odio
  • Dapibus ac facilisis in
  • Morbi leo risus
  • Porta ac consectetur ac
  • Vestibulum at eros
JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List>
      <ListItem active>Cras justo odio</ListItem>
      <ListItem>Dapibus ac facilisis in</ListItem>
      <ListItem>Morbi leo risus</ListItem>
      <ListItem>Porta ac consectetur ac</ListItem>
      <ListItem>Vestibulum at eros</ListItem>
    </List>
  )
}

Disabled items

Add the disabled boolean prop to a <ListItem> to render it disabled. A disabled item gets an aria-disabled="true" attribute automatically.

The disabled state only changes the visual appearance. For interactive elements like links, additional JavaScript is needed to fully disable interaction behavior.

  • Cras justo odio
  • Dapibus ac facilisis in
  • Morbi leo risus
  • Porta ac consectetur ac
  • Vestibulum at eros
JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List>
      <ListItem disabled>Cras justo odio</ListItem>
      <ListItem>Dapibus ac facilisis in</ListItem>
      <ListItem>Morbi leo risus</ListItem>
      <ListItem>Porta ac consectetur ac</ListItem>
      <ListItem>Vestibulum at eros</ListItem>
    </List>
  )
}

Set href or component="button" to create actionable list items with hover, disabled, and active states. href renders an <a>, as it does on every component that takes one. This applies the .list-action modifier class, separating interactive states from standard read-only items. Use href when the action navigates to a new location, and component="button" when it triggers an in-page behavior — a native <button>'s disabled attribute both visually styles the element and prevents interaction, while an <a> only gets the visual .disabled styling and needs additional JavaScript to fully prevent interaction.

Because <a>/<button> elements aren't valid children of a <ul>/<ol>, <List> automatically renders its root as a <div> instead whenever an item is interactive (an interactive data-driven item, or a <ListItem> child that renders an <a> or <button>, through href, component or its asChild element) — pass component explicitly if you need to override that.

JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List>
      <ListItem href="#" active>
        Cras justo odio
      </ListItem>
      <ListItem href="#">Dapibus ac facilisis in</ListItem>
      <ListItem href="#">Morbi leo risus</ListItem>
      <ListItem href="#">Porta ac consectetur ac</ListItem>
      <ListItem href="#" disabled>
        Vestibulum at eros
      </ListItem>
    </List>
  )
}

The same markup with component="button" instead:

JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List>
      <ListItem component="button" active>
        Cras justo odio
      </ListItem>
      <ListItem component="button">Dapibus ac facilisis in</ListItem>
      <ListItem component="button">Morbi leo risus</ListItem>
      <ListItem component="button">Porta ac consectetur ac</ListItem>
      <ListItem component="button" disabled>
        Vestibulum at eros
      </ListItem>
    </List>
  )
}

Layout variations

Flush list

Add the flush boolean prop to remove outer borders and rounded corners, rendering list items edge-to-edge in a parent container (e.g., a card).

  • Cras justo odio
  • Dapibus ac facilisis in
  • Morbi leo risus
  • Porta ac consectetur ac
  • Vestibulum at eros
JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List flush>
      <ListItem>Cras justo odio</ListItem>
      <ListItem>Dapibus ac facilisis in</ListItem>
      <ListItem>Morbi leo risus</ListItem>
      <ListItem>Porta ac consectetur ac</ListItem>
      <ListItem>Vestibulum at eros</ListItem>
    </List>
  )
}

Plain layout

Add the plain boolean prop for a minimal list that removes outer borders, rounded corners, and horizontal padding — a compact fit for content areas like search results or content feeds.

  • Cras justo odio
  • Dapibus ac facilisis in
  • Morbi leo risus
  • Porta ac consectetur ac
  • Vestibulum at eros
JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List plain>
      <ListItem>Cras justo odio</ListItem>
      <ListItem>Dapibus ac facilisis in</ListItem>
      <ListItem>Morbi leo risus</ListItem>
      <ListItem>Porta ac consectetur ac</ListItem>
      <ListItem>Vestibulum at eros</ListItem>
    </List>
  )
}

Both flush and plain remove outer borders and rounded corners. plain also removes horizontal padding, for a more compact appearance.

Numbered lists

Add the numbered boolean prop to sequentially number list items via CSS counters rather than browser defaults. Pair it with component="ol" for semantic correctness.

  1. A list item
  2. A list item
  3. A list item
JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List component="ol" numbered>
      <ListItem>A list item</ListItem>
      <ListItem>A list item</ListItem>
      <ListItem>A list item</ListItem>
    </List>
  )
}

Horizontal layout

Add layout="horizontal" to switch a list from column to row layout across all breakpoints. Adjacent items share a single border edge, and outer corners stay rounded while inner corners are squared off.

Responsive variants use container queries — each layout="{breakpoint}:horizontal" value activates at or above the specified container width. Wrap the list in a .contains-inline container to establish the container context.

layout="horizontal" cannot be combined with flush — the flush variant removes the inline borders that separate items in the horizontal layout.

  • Cras justo odio
  • Dapibus ac facilisis in
  • Morbi leo risus
  • Cras justo odio
  • Dapibus ac facilisis in
  • Morbi leo risus
  • Cras justo odio
  • Dapibus ac facilisis in
  • Morbi leo risus
  • Cras justo odio
  • Dapibus ac facilisis in
  • Morbi leo risus
JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <div className="contains-inline">
      <List className="mb-md" layout="horizontal">
        <ListItem>Cras justo odio</ListItem>
        <ListItem>Dapibus ac facilisis in</ListItem>
        <ListItem>Morbi leo risus</ListItem>
      </List>
      <List className="mb-md" layout="sm:horizontal">
        <ListItem>Cras justo odio</ListItem>
        <ListItem>Dapibus ac facilisis in</ListItem>
        <ListItem>Morbi leo risus</ListItem>
      </List>
      <List className="mb-md" layout="md:horizontal">
        <ListItem>Cras justo odio</ListItem>
        <ListItem>Dapibus ac facilisis in</ListItem>
        <ListItem>Morbi leo risus</ListItem>
      </List>
      <List layout="lg:horizontal">
        <ListItem>Cras justo odio</ListItem>
        <ListItem>Dapibus ac facilisis in</ListItem>
        <ListItem>Morbi leo risus</ListItem>
      </List>
    </div>
  )
}

Apply the .flex-fill or .flex-grow-1 utility classes to list items to stretch them across the full list width — .flex-fill shares the available width equally, while .flex-grow-1 grows from each item's natural content width.

  • Cras justo odio
  • Dapibus ac facilisis in
  • Vestibulum at eros
JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List layout="horizontal">
      <ListItem className="flex-fill">Cras justo odio</ListItem>
      <ListItem className="flex-fill">Dapibus ac facilisis in</ListItem>
      <ListItem className="flex-fill">Vestibulum at eros</ListItem>
    </List>
  )
}

Contextual classes

Use the color prop to style list items with a stateful background and color.

  • Dapibus ac facilisis in
  • A simple primary list item
  • A simple secondary list item
  • A simple success list item
  • A simple danger list item
  • A simple warning list item
  • A simple info list item
JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List>
      <ListItem>Dapibus ac facilisis in</ListItem>
      {(['primary', 'secondary', 'success', 'danger', 'warning', 'info'] as const).map((color) => (
        <ListItem color={color} key={color}>
          A simple {color} list item
        </ListItem>
      ))}
    </List>
  )
}

The same color prop works on <a>/<button> list items, adding hover styles not present on plain items, alongside active to mark a current selection among them.

JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List>
      <ListItem href="#">Dapibus ac facilisis in</ListItem>
      {(['primary', 'secondary', 'success', 'danger', 'warning', 'info'] as const).map((color) => (
        <ListItem href="#" color={color} key={color}>
          A simple {color} list action
        </ListItem>
      ))}
    </List>
  )
}

Context color alone provides only a visual indication, which isn't conveyed to assistive technology users. Make sure information denoted by the color is either obvious from the content itself (e.g. the visible text), or included through alternative means, such as additional text hidden with the .visually-hidden class.

Context styles

<List> also accepts color together with a variant of solid, outline, or smooth to color the whole list container based on the design system's color palette.

  • Cras justo odio
  • Dapibus ac facilisis in
  • Vestibulum at eros
  • Cras justo odio
  • Dapibus ac facilisis in
  • Vestibulum at eros
  • Cras justo odio
  • Dapibus ac facilisis in
  • Vestibulum at eros
  • Cras justo odio
  • Dapibus ac facilisis in
  • Vestibulum at eros
JSX
import { Grid, List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <Grid columns={{ base: 1, md: 2 }} gap="lg">
      <div>
        <List color="primary">
          <ListItem>Cras justo odio</ListItem>
          <ListItem>Dapibus ac facilisis in</ListItem>
          <ListItem>Vestibulum at eros</ListItem>
        </List>
      </div>
      <div>
        <List color="primary" variant="solid" flush className="rounded">
          <ListItem>Cras justo odio</ListItem>
          <ListItem>Dapibus ac facilisis in</ListItem>
          <ListItem>Vestibulum at eros</ListItem>
        </List>
      </div>
      <div>
        <List color="primary" variant="smooth" flush className="rounded">
          <ListItem>Cras justo odio</ListItem>
          <ListItem>Dapibus ac facilisis in</ListItem>
          <ListItem>Vestibulum at eros</ListItem>
        </List>
      </div>
      <div>
        <List color="primary" variant="outline">
          <ListItem>Cras justo odio</ListItem>
          <ListItem>Dapibus ac facilisis in</ListItem>
          <ListItem>Vestibulum at eros</ListItem>
        </List>
      </div>
    </Grid>
  )
}

With badges

Add badges to a list item to show unread counts, activity, and more.

  • Cras justo odio14
  • Dapibus ac facilisis in2
  • Morbi leo risus1
JSX
import { Badge, List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List>
      <ListItem className="d-flex justify-content-between align-items-center">
        Cras justo odio
        <Badge color="primary" className="rounded-full">
          14
        </Badge>
      </ListItem>
      <ListItem className="d-flex justify-content-between align-items-center">
        Dapibus ac facilisis in
        <Badge color="primary" className="rounded-full">
          2
        </Badge>
      </ListItem>
      <ListItem className="d-flex justify-content-between align-items-center">
        Morbi leo risus
        <Badge color="primary" className="rounded-full">
          1
        </Badge>
      </ListItem>
    </List>
  )
}

Custom content

A list item accepts nearly any content, including for linked items, with the help of flexbox utilities.

JSX
import { List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List>
      <ListItem href="#" active>
        <div className="d-flex w-100 justify-content-between">
          <h5 className="mb-xs">List item heading</h5>
          <small>3 days ago</small>
        </div>
        <p className="mb-xs">
          Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius
          blandit.
        </p>
        <small>Donec id elit non mi porta.</small>
      </ListItem>
      <ListItem href="#">
        <div className="d-flex w-100 justify-content-between">
          <h5 className="mb-xs">List item heading</h5>
          <small className="fg-subtle">3 days ago</small>
        </div>
        <p className="mb-xs">
          Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius
          blandit.
        </p>
        <small className="fg-subtle">Donec id elit non mi porta.</small>
      </ListItem>
      <ListItem href="#">
        <div className="d-flex w-100 justify-content-between">
          <h5 className="mb-xs">List item heading</h5>
          <small className="fg-subtle">3 days ago</small>
        </div>
        <p className="mb-xs">
          Donec id elit non mi porta gravida at eget metus. Maecenas sed diam eget risus varius
          blandit.
        </p>
        <small className="fg-subtle">Donec id elit non mi porta.</small>
      </ListItem>
    </List>
  )
}

Checkboxes and radios

Place a checkbox or radio within a list item and customize it as needed.

JSX
import { Checkbox, List, ListItem } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List>
      <ListItem>
        <Checkbox label="Cras justo odio" />
      </ListItem>
      <ListItem>
        <Checkbox label="Dapibus ac facilisis in" defaultSelected />
      </ListItem>
      <ListItem>
        <Checkbox label="Morbi leo risus" defaultSelected />
      </ListItem>
      <ListItem>
        <Checkbox label="orta ac consectetur ac" />
      </ListItem>
      <ListItem>
        <Checkbox label="Vestibulum at eros" />
      </ListItem>
    </List>
  )
}

Since <Checkbox> always renders a <label> as its root element, the .list-item class applies directly to it too, for a large hit area. Because a bare <label> isn't a valid <ul> child either, pass component="div" to <List> here — the same rule covered in Links and buttons above.

JSX
import { Checkbox, List } from '@chassis-ui/react'

export const Example = () => {
  return (
    <List component="div">
      <Checkbox className="list-item" label="Cras justo odio" />
      <Checkbox className="list-item" label="Dapibus ac facilisis in" defaultSelected />
      <Checkbox className="list-item" label="Morbi leo risus" defaultSelected />
      <Checkbox className="list-item" label="orta ac consectetur ac" />
      <Checkbox className="list-item" label="Vestibulum at eros" />
    </List>
  )
}

API

List

PropTypeDefault
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the component.
color?ContextColor—
Sets the color of the component to one of Chassis context colors.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component. Defaults to 'ul', unless an item (a data-driven item with href, or a <ListItem> child rendering an <a>/<button> through component or asChild) is interactive — a bare <a>/<button> isn't a valid direct child of <ul>/<ol>, so the default switches to 'div' instead. Pass component explicitly to opt out of this.
flush?boolean—
Remove outer borders and rounded corners to render list items edge-to-edge in a parent component (e.g., <Card>).
items?ListItemDef[]—
Array of item definitions for data-driven rendering. When provided, children are ignored.
layout?"horizontal" | "sm:horizontal" | "md:horizontal" | "lg:horizontal" | "xl:horizontal" | "2xl:horizontal"—
Specify a layout type.
numbered?boolean—
Number list items sequentially using CSS counters. Pair with component="ol" for semantic correctness.
plain?boolean—
Remove outer borders, rounded corners, and horizontal padding for a minimal, edge-to-edge appearance.
ref?any—
variant?ContextStyle—
Applies a .solid, .outline, or .smooth context style. Only meaningful together with color.

ListItem

PropTypeDefault
active?boolean—
Toggle the active state for the component.
asChild?boolean—
Render the single child element in place of this component's own element, with this component's classes, props and ref merged onto it: <Button asChild><Link href="/login">Log in</Link></Button>. The alternative to component for React Server Components — an element can be passed from the server to this package's client components, a component reference (component={Link}) can't.
className?string—
A string of all className you want applied to the component.
color?ContextColor—
Sets the color of the component to one of Chassis context colors.
component?ElementType—
Component used for the root node. Either a string to use a HTML element or a component.
disabled?boolean—
Toggle the disabled state for the component.
href?string—
The href attribute specifies the URL of the page the link goes to. Renders an <a> in place of the <li>, unless component or asChild chose the element. Inside a List, the list renders a <div> around it in place of the <ul>.
ref?any—

ListItemDef

Shape of each entry in List's items array (data-driven rendering).

PropTypeDefault
active?boolean—
Marks the item as active.
color?ContextColor—
Sets the color of the item.
disabled?boolean—
Marks the item as disabled.
href?string—
Makes the item a link.
id?string | number—
Stable key for the rendered item. Falls back to the item's index in items.
labelReactNode—
Item label content.