JGuang

Item

Item · Astryx

Preview
npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0

Item

A single, flexible item primitive that unifies the "start content + label + description + end content" pattern across Astryx. Use it wherever you need a structured row: dropdown menus, selectors, contact lists, notifications, file browsers, and activity feeds.

Installation

npm install @astryxdesign/core@0.7.1 @astryxdesign/theme-neutral@0.7.1 @stylexjs/stylex@0.19.0

Requires React 19+, base CSS and a Theme provider. See Setup.

Item

A single, flexible item primitive that unifies the "start content + label + description + end content" pattern across Astryx. Use it wherever you need a structured row: dropdown menus, selectors, contact lists, notifications, file browsers, and activity feeds.

Usage guidance

  • Use named slots (startContent, label, description, endContent) for the common layout. These cover the 80% case.
  • Use density="compact" for menus and dense lists, "balanced" for standard rows, and "spacious" for roomier layouts.
  • Set labelLines and descriptionLines to control truncation when content length varies.
  • Use align="start" when start or end content is taller than a single line of text.
  • Give a swipe action a second home in the row (a menu or a button in endContent): the swipe is a touch accelerator, and a verb reachable only by swipe is unreachable by keyboard and by mouse.
  • Avoid: Don't nest interactive elements (buttons, links) inside an interactive Item; it creates confusing focus and click targets.
  • Avoid: Don't use Item for navigation between views; use proper navigation components instead.
  • Avoid: Don't add read/unread or inbox-specific behavior directly; compose a thin wrapper like PreviewItem instead.

Theming API

{
  "targets": [
    {
      "className": "astryx-item",
      "visualProps": [
        "density",
        "align"
      ]
    },
    {
      "className": "astryx-item-swipe-panel",
      "visualProps": [
        "side"
      ]
    },
    {
      "className": "astryx-item-swipe-action",
      "visualProps": [
        "variant"
      ]
    }
  ],
  "vars": [
    {
      "name": "--_item-label-color",
      "description": "Color of the label line. Unset by default (the label uses the primary text token); a parent sets it to recolor the label it renders, as the destructive dropdown/context menu item does.",
      "default": "var(--color-text-primary)",
      "private": true
    },
    {
      "name": "--_item-description-color",
      "description": "Companion to --_item-label-color for the secondary description line.",
      "default": "var(--color-text-secondary)",
      "private": true
    },
    {
      "name": "--_item-inset-inline",
      "description": "Inline inset of the row. Item derives its paddingInline from this variable, and List reads it to cancel the inset when edgeCompensation=\"inline\". Set paddingInline on `item` in a theme and both stay in sync.",
      "default": "var(--spacing-2) (var(--spacing-3) for density=\"spacious\")",
      "private": true
    }
  ],
  "derived": [
    {
      "property": "paddingInline",
      "vars": [
        "--_item-inset-inline"
      ]
    }
  ]
}

Item

A universal item primitive that unifies the "start content + label + description + end content" layout pattern. Use as a building block for list items, menu items, contact rows, notifications, and more.

PropTypeDefaultDescription
label *ReactNodePrimary text identifying this item. Accepts string (auto-truncated) or ReactNode (for rich content).
markerReactNodeMarker rendered before startContent as a direct flex child. Use for list bullets/counters that need custom baseline alignment.
startContentReactNodeContent rendered before the label/description area, such as an icon, avatar, or checkbox.
descriptionReactNodeSecondary text: subtitle, description, or supporting info.
endContentReactNodeContent rendered after the label/description area, such as badges, metadata, timestamps, or action buttons.
as'div' | 'li' | 'span' | ElementType'div'What the root renders as: an HTML element, or a component for a caller that needs the root to be something else. A menu row that navigates passes the application's link component here, so the row's root IS the anchor. Give a component only when the row carries a role, and only when no interactive node sits in startContent or endContent.
align'center' | 'start''center'Vertical alignment of start/end content slots.
density'compact' | 'balanced' | 'spacious''balanced'Spacing density. "compact" uses 4px block padding, "balanced" uses 8px, and "spacious" uses 12px block and inline padding.
labelLinesnumberMax lines before label truncates with ellipsis.
descriptionLinesnumberMax lines before description truncates with ellipsis.
layout'stacked' | 'inline''stacked'How the label and description sit together. stacked puts the description on its own line below the label; inline keeps both on one line, description ellipsizing first, so the row fits a fixed-height host.
onClick(event: MouseEvent) => voidClick handler. Makes the item clickable with button semantics.
interactiveRefRefObject<HTMLElement | null>Ref to a nested control (e.g. a checkbox in startContent) that owns the item's keyboard access and action. The row becomes an enlarged click/tap target that delegates surface clicks to it (useClickableContainer) and renders no invisible button/anchor, so the row adds no second tab stop (WCAG 4.1.2). Mutually exclusive with onClick/href; those are ignored when set.
hrefstringLink URL. Makes the item a link via an invisible anchor element. A row whose root is already a link component (see as) carries the address on that root instead, and no invisible anchor is rendered.
target'_blank' | '_self'Link target. Only used with href. target="_blank" automatically adds noopener noreferrer.
relstringLink relationship tokens. noopener noreferrer are merged automatically for target="_blank".
isHighlightedbooleanfalseHighlighted state (hover/keyboard focus appearance).
isSelectedbooleanfalseSelected state.
isDisabledbooleanfalseDisabled state.
swipeActions{leading?: ItemSwipeAction[]; trailing?: ItemSwipeAction[]}Swipe actions for touch: the verbs a sideways drag uncovers on each side, outermost last, each {id?, label, icon?, onActivate, isDisabled?, variant?: 'neutral' | 'accent' | 'destructive', hasRemoval?}. leading is uncovered by a drag toward the inline end, trailing toward the inline start. A mouse never starts the drag and a mostly vertical drag stays the scroller's. The gesture is a touch accelerator and never a row's only path to a verb: a verb reachable only by swipe is unreachable by keyboard and by mouse, so every entry must also be reachable through the row's own content. Served on a row whose role permits interactive descendants (a listitem, a row with no role) and not on an option, a menu item, or a row that is the enlarged target of a native radio. The element containing the rows clips in the inline axis with overflow-inline: clip — List does; any other host does it once. hasRemoval only says the row holds out after the action fires instead of springing back. The gesture and its panels are loaded on demand the first time a row has swipe actions, so a row without them ships none of it.
swipeBehavior'reveal' | 'commit''reveal'What a swipe does. reveal rests the row open with every entry a real button and fires the outermost on a long drag or a fling; commit slides the row out and fires the outermost on release, with nothing resting and a presentational panel. commit fits one entry per side.
refReact.Ref<HTMLDivElement>Ref forwarded to the root element.
xstyleStyleXStylesStyleX styles for layout customization. Must be a stylex.create() value.
data-testidstringTest selector for automated testing frameworks.

Anatomy

  • Marker: Optional list bullet/counter rendered before start content.
  • Start content: Leading visual: avatar, icon, image, or checkbox.
  • Label: Primary text identifying the item.
  • Description: Secondary supporting text below the label.
  • End content: End-aligned content: badges, timestamps, or action buttons.

Examples

  • Item:
  • Item — Basic: A basic item with a label, supporting description, and end-aligned timestamp. Use this for simple rows that need consistent text alignment and spacing.
  • Item — Document Tabs: Single-row, horizontally scrollable document switcher with compact selected rows, leading file icons, instant reveal-on-hover close actions with reserved geometry, stable separators, and an add control outside the scroll area. Use for editor tabs, workspace tabs, open documents, files, canvases, or panels.
  • Item — Start Content: Items with leading avatars and icons in the startContent slot. Keep start content small so the row stays compact and easy to scan.
  • Item — Metadata: Items with end-aligned metadata and badges. Use the endContent slot for counts, status, timestamps, and other secondary row information.

Complete example dependencies

Some examples import optional icons. The per-example install command in the examples list identifies exactly what that example needs. For all examples on this page:

npm install @heroicons/react@2.2.0

Source StyleX compilation

ItemDocumentTabs contain stylex.create and require a StyleX source build pipeline. Precompiled Core CSS alone does not compile these examples. See Styling before copying them.