Item

Item is a flexible row for lists of accounts, organizations, and settings in Mosaic. It's composed from parts via dot syntax (Item.Root, Item.Media, Item.Content, Item.Title, …). Item.Root renders as a <div> by default; pass it a render prop to make a row an interactive link or button, which adds hover and cursor affordances.

Set size once on Item.Root and the row scales as a unit: it fixes the row's height and gap, and Item.Media picks the matching column width up from context rather than taking a size of its own.

Example

T
Test Organization
Member

Interactive

T
Test Organization
Member

Sizes

T
Test Organization
T
Test Organization

Group

C
Cameron Walker
cameron@clerk.com

cameron.walker@gmail.com
C
Clerk
C
Clerk


Add account

Scrolling

Item.Group is the canonical scroll surface in Mosaic: cap its height, spread the scroll-area atoms onto it, and it fades its content at whichever edge still has something to reveal.

import { scrollAreaRoot, scrollAreaViewport } from '@clerk/ui/mosaic/components/scroll-area';
import * as stylex from '@stylexjs/stylex';

<div
  {...stylex.props(scrollAreaRoot)}
  style={{ height: 260 }}
>
  <Item.Group {...stylex.props(...scrollAreaViewport())}>{organizations}</Item.Group>
</div>;

The atoms aren't specific to Item — they go on anything that scrolls, and they carry the edge fades, the scrollbar, the gutter, and the theming tokens with them. See Scroll Area for the full surface: the gutter argument, what happens when there is nothing to scroll, the token table, and how to replace the fade entirely.

Usage

import { Avatar } from '@clerk/ui/mosaic/components/avatar';
import { Item } from '@clerk/ui/mosaic/components/item';

<Item.Group>
  <Item.Root render={({ children, ...props }) => <a {...props} href='/org'>{children}</a>}>
    <Item.Media>
      <Avatar.Root shape='square' size='fit'>
        <Avatar.Image src={org.imageUrl} alt='' />
        <Avatar.Fallback>{org.name[0]}</Avatar.Fallback>
      </Avatar.Root>
    </Item.Media>
    <Item.Content>
      <Item.Title>Test Organization</Item.Title>
      <Item.Description>Member</Item.Description>
    </Item.Content>
    <Item.Actions>
      <Button variant='outline' size='sm'>Manage</Button>
    </Item.Actions>
  </Item.Root>
</Item.Group>;

Media sizes itself from the row, so give it a child that fills its column — an Avatar.Root with size='fit', or an icon at width='100%'. An action row that has no secondary text uses Item.Label in place of Item.Title:

<Item.Root size='xs' render={({ children, ...props }) => <button type='button' {...props}>{children}</button>}>
  <Item.Media>
    <SignOutIcon width='100%' />
  </Item.Media>
  <Item.Content>
    <Item.Label>Sign out of all accounts</Item.Label>
  </Item.Content>
</Item.Root>;

Parts

PartClassDescription
Item.Rootcl-itemRoot row. Renders a <div>, or a custom element via render.
Item.Mediacl-item-mediaSquare leading column: icon, image, or avatar. Sized by the root's size.
Item.Contentcl-item-contentVertical stack that grows to fill the row between media and actions.
Item.Titlecl-item-titlePrimary label. Truncates to a single line.
Item.Descriptioncl-item-descriptionSecondary text beneath the title. Truncates to a single line.
Item.Labelcl-item-labelSole label on an action row, in place of a title. Dimmed until hovered.
Item.Actionscl-item-actionsTrailing controls (buttons, badges).
Item.Groupcl-item-groupVertical wrapper around a set of rows (layout only, no role).
Item.Separatorcl-item-separatorThin divider (<hr>) between rows.

Every part accepts a render prop for element polymorphism and forwards a ref.

Styling

The root reflects its state as data-* attributes on .cl-item, so consumers can scope overrides without touching StyleX's hashed atoms:

PropAttributeValuesDefault
sizedata-sizexs | mdmd
renderdata-interactivepresent when a render is provided

size fixes the row's height and gap. Item.Media reflects the same value as data-size and takes its width from it, so the two stay in step without being set twice:

/* Re-theme interactive rows */
.cl-item[data-interactive] {
  background-color: var(--cl-color-card);
}

/* Widen the media column on compact rows */
.cl-item-media[data-size='xs'] {
  width: 1.5rem;
}

Item.Media is a square that centers its child. Because the column is sized by the row, give it a child that fills it — an Avatar.Root with size='fit', or an icon at width='100%' — rather than a fixed pixel size that won't track size. Colors, radii, and spacing all resolve from the Mosaic tokens (--cl-color-*, --cl-radius-*, --cl-spacing).