MD3
Expressive
MATERIAL DESIGN 3 EXPRESSIVE

Lists

Lists are continuous, vertical indexes of text or images. Expressive Lists feature shape morphing animations, multi-action support, and built-in drag-and-drop sorting.

Lists are used to group related content or actions into a single column. The MD3 Expressive List features dynamic corner rounding (shape morphing) based on interaction states and native drag-and-drop capabilities.

Introduction

Expressive Lists are designed to feel tactile and fluid. In the expressive variant, items transition their corner shapes from standard roundness (CornerExtraSmall - 4px) to dynamic bubbles (CornerMedium/CornerLarge - 12px/16px) upon hover, focus, and drag interaction.

Anatomy

  • Container: The list wrapper (either standard or segmented with gap).
  • Leading Slot: Supports icons, avatars, images, video previews, or selection indicators (checkboxes/radio buttons).
  • Content Area: Contains an optional overline, main headline, and supporting text (1 or 2 lines).
  • Trailing Slot: Contains action elements like text, switches, buttons, or a drag handle.
  • Divider: A separating line that can be full-width or inset starting after leading elements.

Variants

Basic Lists

Baseline and Expressive variants showing standard or segmented styles.

Loading demo...

Selection Modes

Single-select (radio buttons) or multi-select (checkboxes) lists. Clicking anywhere on the item or the indicator toggles selection state.

Loading demo...

Drag & Drop Reordering

Integrated sorting powered by @dnd-kit. Activating reorderable enables list items to be dragged and reordered with fluid spring animations.

Loading demo...

Rich Media & Multi-Action

List items can hold complex elements like video previews (top-aligned) and support Multi-Action mode where the container and the trailing action have separate focus areas.

Loading demo...

Features

Expressive Motion

Expressive Lists utilize physics-based spring animations for fluid state transitions. When a user hovers, focuses, or drags a list item, its corners dynamically expand from 4px (extra small shape) to 12px or 16px (medium/large shape). This shape morphing is governed by:

  • Spatial Spring: Manages the corner radius shape morphing and size changes (FAST_SPATIAL_SPRING tier) for instant tactile feedback.
  • Effects Spring: Controls color background transitions and state overlay opacities (DEFAULT_EFFECTS_SPRING tier).

Responsive Scaling & Adaptation

List layouts adapt dynamically across screen size classes to preserve comfortable reading line lengths:

  • Compact Window Sizes (under 600dp): List containers extend edge-to-edge. Selecting an item navigates to a full-screen detailed view.
  • Medium & Expanded Window Sizes (600dp - 1200dp+): Lists can adapt margins, scale down padding, or transition into a side-by-side list-detail view or a multi-column grid.
  • Line Length: Primary and supporting text is optimized for quick scanning, keeping the line length between 40 to 60 characters for maximum readability.

Usage

Basic Usage

import { List, ListItem, ListDivider } from "@bug-on/m3-expressive";

<List variant="expressive">
  <ListItem
    value="item1"
    headline="Inbox"
    supportingText="Check your emails"
    leadingType="icon"
    leadingContent={<span className="material-symbols-rounded">inbox</span>}
    interactive
  />
  <ListDivider inset insetType="icon" />
  <ListItem
    value="item2"
    headline="Trash"
    supportingText="Deleted items"
    leadingType="icon"
    leadingContent={<span className="material-symbols-rounded">delete</span>}
    interactive
  />
</List>

Reorderable List

import { List, ListItem } from "@bug-on/m3-expressive";
import { useState } from "react";

const [items, setItems] = useState([
  { id: "1", title: "Item 1" },
  { id: "2", title: "Item 2" },
]);

<List
  variant="expressive"
  listStyle="segmented"
  reorderable
  items={items}
  onReorder={setItems}
>
  {items.map((item) => (
    <ListItem
      key={item.id}
      value={item.id}
      headline={item.title}
      dragHandle
    />
  ))}
</List>

Best Practices

Do

  • Align supporting visuals (such as icons, avatars, or images) consistently at the leading edge to maintain scannability.
  • Use segmented gaps (listStyle="segmented") and filled container items to clearly define contained lists.
  • Keep label text brief and limit supporting description text to 1 to 3 lines, allowing it to truncate based on screen size.
  • Provide descriptive aria-labels for interactive elements like custom trailing actions or drag handles.
  • Adjust container margins on large screens (e.g. tablet or desktop) to prevent overly long line lengths and maintain comfortable reading.

Don't

  • Don't vary the placement of visual elements (e.g. shifting icons from leading to middle) within the same list.
  • Don't use a high-emphasis design for repetitive secondary actions in multi-action lists.
  • Don't pair checkboxes with single-select lists, or radio buttons with multi-select lists.
  • Don't rely solely on background color changes to indicate selection states. Always pair color shifts with supporting visual cues (e.g. checkboxes, radio buttons, or selection checkmarks).

Design Tokens

Corner Radius

The Expressive List component implements MD3 Expressive shape morphing across state layers.

StateCSS TokenValueCorner Level
Resting--md-sys-shape-corner-extra-small4pxExtra Small
Hovered--md-sys-shape-corner-medium12pxMedium
Focused / Pressed--md-sys-shape-corner-large16pxLarge
Selected / Dragged--md-sys-shape-corner-large16pxLarge
Disabled--md-sys-shape-corner-extra-small4pxExtra Small

Container Heights

Heights align strictly with the MD3 vertical spacing specs:

ComplexityLayout / ConfigurationTarget Height
One-lineLabel text only, with/without leading icons56px
Two-lineLabel + 1 line of supporting text72px
Three-lineLabel + 2 lines of supporting text / overline88px

Motion & Springs

Transitions use organic spring physics to communicate state shifts.

TransitionSpring TokenTier
Shape/Size (Morphing)FAST_SPATIAL_SPRINGFast
Color/Opacity (State overlays)DEFAULT_EFFECTS_SPRINGDefault

Accessibility

  • Keyboard Navigation (Vertical): Press ArrowUp / ArrowDown to cycle focus through interactive items. Focus automatically wraps around.
  • Keyboard Navigation (Horizontal): In multi-action mode, press ArrowLeft / ArrowRight to transition focus between the primary item body and secondary trailing actions. Focus automatically skips disabled controls.
  • Initial Focus: When tabbed, focus lands on the first item. If the list has an active selected item, focus lands on the selected item first.
  • ARIA Roles: Automatically assigns role="listbox" and aria-selected for selection lists, and role="list" for actions.
  • Visual Cues: Selection is indicated by both a color background change and a checkbox/radio control to support users with low vision (WCAG 2.1 compliance).
  • Disabled State: Correctly assigns aria-disabled="true" and removes focus via tabIndex={-1}.

API Reference

List

PropTypeDefaultDescription
variant"baseline" | "expressive""baseline"Design scheme variant.
listStyle"standard" | "segmented""standard"Segmented list has 2px gap.
selectionMode"none" | "single-action" | "multi-action" | "single-select" | "multi-select""none"Changes interaction roles and keyboard routing.
valuestring | string[]Controlled selection value.
defaultValuestring | string[]Uncontrolled selection value initial state.
onChange(value: string | string[]) => voidFired when selection state changes.
reorderablebooleanfalseEnables drag-and-drop.
itemsunknown[]Array of items data to reorder.
onReorder(newItems: unknown[]) => voidCallback returned sorted array.
outerRadiusnumber16Custom outer corner radius (px) for leading/trailing list items in expressive variant.
innerRadiusnumber4Custom inner corner radius (px) for contiguous list items in expressive variant.

ListItem

PropTypeDefaultDescription
valuestringRequiredUnique identifier for selection and sorting.
headlineReactNodeRequiredPrincipal list item text.
supportingTextReactNodeSupplementary description.
supportingTextLines1 | 21Max lines for supporting description.
overlineReactNodeSmall text appearing above headline.
leadingType"none" | "icon" | "avatar" | "image" | "video" | "checkbox" | "radio" | "custom""none"Leading layout configuration.
leadingSrcstringImage or video source link.
leadingAltstringAlternative label for leading image.
leadingContentReactNodeContent used for icon/avatar or custom.
trailingType"none" | "icon" | "icon-button" | "text" | "checkbox" | "radio" | "switch" | "custom""none"Trailing layout configuration.
trailingTextstringTrailing status text.
trailingContentReactNodeCustom element or switch overrides.
disabledbooleanfalseDisables interaction and reduces opacity.
selectedbooleanManual selected state override.
hrefstringRenders item as a link <a>.
onClick(event: React.MouseEvent<HTMLElement>) => voidEvent callback.
interactivebooleanfalseForces interactive state (ripples & hover overlays) when no event or link is provided.
dragHandlebooleanfalseRestricts drag activation to handle button instead of full container.
position"solo" | "leading" | "middle" | "trailing"Overrides the list item position for corner radius calculations.

ListDivider

PropTypeDefaultDescription
insetbooleanfalseIndents divider line after leading slot elements.
insetType"icon" | "avatar" | "custom""avatar"Sets indentation amount (56px for icon, 72px for avatar).