DesignList
Interactive list component with selectable items, supporting multiple sizes and visual variants. Uses React Context to pass size/variant to child items. Perfect for menus, option lists, and selection interfaces.
Component
Import
tsx
import { DesignList, DesignListItem } from "@/components/ui/design-list";
Sizes
small, medium (default), large
Variants
default (surface-200), filled (surface-100)
Features
selectable checkbox, animated right content
A11y
role=list/listitem, aria-selected, keyboard nav

DesignList Props

Container component. Passes size and variant to children via Context.

Props
PropTypeDefaultDescription
size"small" | "medium" | "large""medium"Size of list items: affects padding, font sizes
variant"default" | "filled""default"Visual style. default=surface-200+elevation, filled=surface-100+elevation
children*ReactNode-DesignListItem children
classNamestring-Additional CSS classes on the container div

DesignListItem Props

Individual list item. Inherits size/variant from parent DesignList context.

Props
PropTypeDefaultDescription
title*ReactNode-Primary text content
descriptionReactNode-Secondary descriptive text below title
leftContentReactNode-Content on the left side (icon, avatar). Replaced by checkbox when selectable=true
rightContentReactNode-Content on the right side (icon, badge, chevron)
selectedbooleanfalseSelected/active state. Shows highlighted background (or checkbox state when selectable)
selectablebooleanfalseEnable built-in circular checkbox indicator on the left
disabledbooleanfalseDisabled state: opacity-50, no pointer events
animateRightContentbooleanfalseSlide animation on rightContent during hover
onClick() => void-Click handler
size"small" | "medium" | "large"-Override size from parent context
classNamestring-Additional CSS classes

Design Specifications

Size and variant visual details

Props
PropTypeDefaultDescription
ContainerAll sizesp-1.5Padding: 6px, border-radius: 18px, item-radius: 12px
SmallSizep-3Item padding: 12px, title: 13px, description: 12px
MediumSizep-4Item padding: 16px, title: 14px, description: 13px
LargeSizep-5Item padding: 20px, title: 16px, description: 14px
Default variantColors-Container: surface-200 + elevation. Hover/Selected: surface-300
Filled variantColors-Container: surface-100 + elevation. Hover/Selected: surface-200
Selectable checkboxStyle-24px circle, selected=primary/10 bg + check icon, unselected=border-secondary
Common Patterns

Basic List with Chevrons

Menu-style list with navigation arrows
<DesignList variant="default" className="max-w-sm">
  <DesignListItem
    title="Download Video"
    description="High quality MP4"
    rightContent={<ChevronRight className="size-4" />}
  />
  <DesignListItem
    title="Export Data"
    description="Export as CSV or JSON"
    rightContent={<ChevronRight className="size-4" />}
  />
</DesignList>

Single Selection

Click to select one item at a time
const [selected, setSelected] = useState<string | null>(null);

<DesignList>
  {items.map((item) => (
    <DesignListItem
      key={item.id}
      title={item.name}
      description={item.desc}
      selected={selected === item.id}
      onClick={() => setSelected(item.id)}
      rightContent={
        selected === item.id
          ? <Check className="size-4 text-[var(--color-brand)]" />
          : null
      }
    />
  ))}
</DesignList>

Multi-Select with Checkboxes

Toggle multiple items using built-in circular checkbox
const [items, setItems] = useState<Record<string, boolean>>({
  "opt-1": true,
  "opt-2": false,
  "opt-3": true,
});

<DesignList variant="filled">
  {Object.entries(items).map(([id, checked]) => (
    <DesignListItem
      key={id}
      title={`Option ${id}`}
      description="Click to toggle"
      selectable
      selected={checked}
      onClick={() => setItems(prev => ({ ...prev, [id]: !prev[id] }))}
    />
  ))}
</DesignList>

Simple Title-Only List

Compact list without descriptions
<DesignList size="small">
  <DesignListItem
    title="720p HD"
    rightContent={<span className="text-xs">1.2 MB</span>}
  />
  <DesignListItem
    title="1080p Full HD"
    rightContent={<span className="text-xs">3.5 MB</span>}
  />
  <DesignListItem
    title="4K Ultra HD"
    rightContent={<span className="text-xs">12.8 MB</span>}
  />
</DesignList>
When to Use
1

Settings menu or option picker

Use default variant with rightContent chevrons. size="medium" for standard menus.

<DesignList variant="default">
  <DesignListItem
    title="Account Settings"
    description="Manage your profile"
    rightContent={<ChevronRight className="size-4" />}
    onClick={() => router.push("/settings")}
  />
</DesignList>
2

Multi-select filter or checkbox list

Use selectable prop with filled variant for checkbox-style selection.

<DesignList variant="filled">
  <DesignListItem
    title="Twitter"
    selectable
    selected={platforms.twitter}
    onClick={() => toggle("twitter")}
  />
</DesignList>
3

Download quality selector

Use size="small" for compact lists with title-only items.

<DesignList size="small">
  <DesignListItem
    title="720p"
    rightContent={<span className="text-xs">1.2 MB</span>}
    selected={quality === "720p"}
    onClick={() => setQuality("720p")}
  />
</DesignList>
Do

Use variant="filled" with selectable for checkbox-style lists

<DesignList variant="filled">
  <DesignListItem selectable selected={true} title="Option A" />
</DesignList>

Use size="small" for compact/dense UIs like dropdowns

<DesignList size="small" className="max-w-xs">
  <DesignListItem title="Option 1" />
</DesignList>

Pass rightContent for action indicators (chevrons, icons, badges)

<DesignListItem
  title="View Details"
  rightContent={<ChevronRight className="size-4" />}
/>
Don't

Don't use leftContent together with selectable (checkbox replaces it)

// ❌ Bad - leftContent is ignored when selectable=true
<DesignListItem
  selectable
  leftContent={<Avatar />}
  title="Option"
/>

// βœ… Good - use only one
<DesignListItem selectable title="Option" />
<DesignListItem leftContent={<Avatar />} title="User" />

Don't forget onClick handler for interactive lists

// ❌ Bad - selected but no way to change it
<DesignListItem title="Option" selected={true} />

// βœ… Good - interactive with click handler
<DesignListItem
  title="Option"
  selected={isSelected}
  onClick={() => setSelected(true)}
/>

Don't manually set size on items when DesignList already has it (uses Context)

// ❌ Bad - redundant size prop
<DesignList size="small">
  <DesignListItem size="small" title="Item" />
</DesignList>

// βœ… Good - size inherited from parent
<DesignList size="small">
  <DesignListItem title="Item" />
</DesignList>

Visual Examples

Interactive examples showing all variants

Size: Small

Compact for dense UIs

Small ItemCompact size for dense UIs
Another ItemSame compact size
<DesignList size="small">
  <DesignListItem title="Small Item" description="Compact" />
</DesignList>

Size: Medium (Default)

Standard for most use cases

Medium ItemStandard size for most use cases
Another ItemSame standard size
<DesignList size="medium">
  <DesignListItem title="Medium Item" description="Standard" />
</DesignList>

Size: Large

Spacious for emphasis

Large ItemSpacious size for emphasis
Another ItemSame spacious size
<DesignList size="large">
  <DesignListItem title="Large Item" description="Spacious" />
</DesignList>

Variant: Filled

surface-100 background

Download OptionHigh quality MP4
Another OptionStandard quality
<DesignList variant="filled">
  <DesignListItem title="Option" rightContent={<ChevronRight />} />
</DesignList>

Single Selection

Click to select one item

Option 1Description for option-1
Option 2Description for option-2
Option 3Description for option-3
<DesignListItem
  selected={selectedItem === id}
  onClick={() => setSelectedItem(id)}
  rightContent={selected ? <Check /> : null}
/>

Selectable Checkbox

Multi-select with circular checkbox

Option 1Description for item-1
Option 2Description for item-2
Option 3Description for item-3
<DesignListItem
  selectable
  selected={isChecked}
  onClick={() => toggle(id)}
/>

With Icons

Right-side icon indicators

Download VideoSave to your device
Export DataExport as CSV or JSON
SettingsConfigure preferences
<DesignListItem
  title="Download"
  rightContent={<Download className="size-4" />}
/>

Disabled State

Items can be disabled

Available OptionThis option is selectable
Unavailable OptionThis option is disabled
Another AvailableThis option is also selectable
<DesignListItem
  title="Unavailable"
  disabled
/>