Agents (llms.txt)

List Item

A row primitive with leading icon, title, subtitle, and trailing slot

Alice Chen
alice@demo.mercury.com
Money Mover
Anthony Buteo
anthony@demo.mercury.com
Read Only
Jane Black
jane@demo.mercury.com
Admin
import { ChevronRight } from '@untitledui-pro/icons/solid';

import { Avatar } from '@/components/avatar';
import { Badge } from '@/components/badge';
import { List, ListItem } from '@/components/list-item';
import { Surface } from '@/components/surface';

export default function ListItemPreview() {
  return (
    <Surface elevation="default">
      <List>
        <ListItem interactive>
          <ListItem.Leading>
            <Avatar size="sm">
              <Avatar.Fallback>AC</Avatar.Fallback>
            </Avatar>
          </ListItem.Leading>
          <ListItem.Content>
            <ListItem.Title>Alice Chen</ListItem.Title>
            <ListItem.Subtitle>alice@demo.mercury.com</ListItem.Subtitle>
          </ListItem.Content>
          <ListItem.Trailing>
            <Badge size="xs">Money Mover</Badge>
            <ChevronRight className="size-4" />
          </ListItem.Trailing>
        </ListItem>

        <ListItem interactive>
          <ListItem.Leading>
            <Avatar size="sm">
              <Avatar.Fallback>AB</Avatar.Fallback>
            </Avatar>
          </ListItem.Leading>
          <ListItem.Content>
            <ListItem.Title>Anthony Buteo</ListItem.Title>
            <ListItem.Subtitle>anthony@demo.mercury.com</ListItem.Subtitle>
          </ListItem.Content>
          <ListItem.Trailing>
            <Badge size="xs" variant="neutral">
              Read Only
            </Badge>
            <ChevronRight className="size-4" />
          </ListItem.Trailing>
        </ListItem>

        <ListItem interactive active>
          <ListItem.Leading>
            <Avatar size="sm">
              <Avatar.Fallback>JB</Avatar.Fallback>
            </Avatar>
          </ListItem.Leading>
          <ListItem.Content>
            <ListItem.Title>Jane Black</ListItem.Title>
            <ListItem.Subtitle>jane@demo.mercury.com</ListItem.Subtitle>
          </ListItem.Content>
          <ListItem.Trailing>
            <Badge size="xs">Admin</Badge>
            <ChevronRight className="size-4" />
          </ListItem.Trailing>
        </ListItem>
      </List>
    </Surface>
  );
}

Dependencies

Source Code

import type { VariantProps } from 'cva';

import { Slot } from '@/components/slot';
import { cn, cva } from '@/lib/utils/classnames';

const listItemStyle = cva({
  base: [
    'group relative flex items-center text-left',
    'transition duration-(--duration-hover) ease-(--ease)',
  ],
  variants: {
    interactive: {
      true: 'focus-visible:ring-(length:--ring-width) cursor-pointer rounded-lg ring-ring hover:bg-foreground/4 focus-visible:outline-none active:scale-(--press-scale) motion-reduce:active:scale-100',
      false: '',
    },
    active: {
      true: 'bg-foreground/6',
      false: '',
    },
    divided: {
      true: 'border-(--color-divider) border-b last:border-b-0',
      false: '',
    },
    size: {
      sm: 'min-h-9 gap-2 px-2 py-1 text-sm',
      md: 'min-h-11 gap-3 px-3 py-1.5 text-base',
      lg: 'min-h-12 gap-3 px-3 py-2 text-base',
    },
  },
  defaultVariants: {
    interactive: false,
    active: false,
    divided: false,
    size: 'md',
  },
});

interface ListItemProps
  extends React.ComponentPropsWithRef<'div'>,
    VariantProps<typeof listItemStyle> {
  asChild?: boolean;
}

const ListItem = ({
  ref,
  className,
  interactive,
  active,
  divided,
  size,
  asChild,
  ...rest
}: ListItemProps) => {
  const Comp = asChild ? Slot : 'div';
  return (
    <Comp
      ref={ref}
      data-active={active ? '' : undefined}
      data-divided={divided ? '' : undefined}
      className={cn(
        listItemStyle({ interactive, active, divided, size }),
        className
      )}
      {...rest}
    />
  );
};

const ListItemLeading = ({
  ref,
  className,
  ...rest
}: React.ComponentPropsWithRef<'div'>) => (
  <div
    ref={ref}
    aria-hidden
    className={cn(
      'flex shrink-0 items-center justify-center text-foreground-secondary',
      className
    )}
    {...rest}
  />
);

const ListItemContent = ({
  ref,
  className,
  ...rest
}: React.ComponentPropsWithRef<'div'>) => (
  <div
    ref={ref}
    className={cn('flex min-w-0 flex-1 flex-col justify-center', className)}
    {...rest}
  />
);

const ListItemTitle = ({
  ref,
  className,
  ...rest
}: React.ComponentPropsWithRef<'div'>) => (
  <div
    ref={ref}
    className={cn(
      'truncate font-medium text-foreground leading-tight',
      className
    )}
    {...rest}
  />
);

const ListItemSubtitle = ({
  ref,
  className,
  ...rest
}: React.ComponentPropsWithRef<'div'>) => (
  <div
    ref={ref}
    className={cn(
      'truncate text-foreground-secondary text-sm leading-tight',
      className
    )}
    {...rest}
  />
);

const ListItemTrailing = ({
  ref,
  className,
  ...rest
}: React.ComponentPropsWithRef<'div'>) => (
  <div
    ref={ref}
    className={cn(
      'ml-auto flex shrink-0 items-center gap-2 text-foreground-secondary',
      className
    )}
    {...rest}
  />
);

const List = ({
  ref,
  className,
  ...rest
}: React.ComponentPropsWithRef<'div'>) => (
  <div
    ref={ref}
    className={cn(
      'flex flex-col gap-0.5 has-[[data-divided]]:gap-0',
      className
    )}
    {...rest}
  />
);

const CompoundListItem = Object.assign(ListItem, {
  Leading: ListItemLeading,
  Content: ListItemContent,
  Title: ListItemTitle,
  Subtitle: ListItemSubtitle,
  Trailing: ListItemTrailing,
});

export type { ListItemProps };
export { CompoundListItem as ListItem, List, listItemStyle };

Server component. No 'use client' — list row layout compound; forwards props, no hooks or own handlers.

ListItem is the row primitive used everywhere in dashboards: account lists, team rosters, transactions, integrations. It has a leading slot for an avatar/icon, a content slot for title and subtitle, and a trailing slot for amounts, badges, or chevrons.

Anatomy


          <List>
  <ListItem interactive>
    <ListItem.Leading>{icon}</ListItem.Leading>
    <ListItem.Content>
      <ListItem.Title>{title}</ListItem.Title>
      <ListItem.Subtitle>{subtitle}</ListItem.Subtitle>
    </ListItem.Content>
    <ListItem.Trailing>{trailing}</ListItem.Trailing>
  </ListItem>
</List>
        

API Reference

ListItem

Extends the div element.

Prop Default Type
interactive - boolean
active - boolean
divided - boolean
size "md" "sm""md""lg"
asChild - boolean

List

Extends the div element. Plain wrapper with role="list".

ListItem.Leading / Content / Title / Subtitle / Trailing

All extend the div element.

Examples

Default

Alice Chen
alice@demo.mercury.com
Money Mover
Anthony Buteo
anthony@demo.mercury.com
Read Only
Jane Black
jane@demo.mercury.com
Admin
import { ChevronRight } from '@untitledui-pro/icons/solid';

import { Avatar } from '@/components/avatar';
import { Badge } from '@/components/badge';
import { List, ListItem } from '@/components/list-item';
import { Surface } from '@/components/surface';

export default function ListItemPreview() {
  return (
    <Surface elevation="default">
      <List>
        <ListItem interactive>
          <ListItem.Leading>
            <Avatar size="sm">
              <Avatar.Fallback>AC</Avatar.Fallback>
            </Avatar>
          </ListItem.Leading>
          <ListItem.Content>
            <ListItem.Title>Alice Chen</ListItem.Title>
            <ListItem.Subtitle>alice@demo.mercury.com</ListItem.Subtitle>
          </ListItem.Content>
          <ListItem.Trailing>
            <Badge size="xs">Money Mover</Badge>
            <ChevronRight className="size-4" />
          </ListItem.Trailing>
        </ListItem>

        <ListItem interactive>
          <ListItem.Leading>
            <Avatar size="sm">
              <Avatar.Fallback>AB</Avatar.Fallback>
            </Avatar>
          </ListItem.Leading>
          <ListItem.Content>
            <ListItem.Title>Anthony Buteo</ListItem.Title>
            <ListItem.Subtitle>anthony@demo.mercury.com</ListItem.Subtitle>
          </ListItem.Content>
          <ListItem.Trailing>
            <Badge size="xs" variant="neutral">
              Read Only
            </Badge>
            <ChevronRight className="size-4" />
          </ListItem.Trailing>
        </ListItem>

        <ListItem interactive active>
          <ListItem.Leading>
            <Avatar size="sm">
              <Avatar.Fallback>JB</Avatar.Fallback>
            </Avatar>
          </ListItem.Leading>
          <ListItem.Content>
            <ListItem.Title>Jane Black</ListItem.Title>
            <ListItem.Subtitle>jane@demo.mercury.com</ListItem.Subtitle>
          </ListItem.Content>
          <ListItem.Trailing>
            <Badge size="xs">Admin</Badge>
            <ChevronRight className="size-4" />
          </ListItem.Trailing>
        </ListItem>
      </List>
    </Surface>
  );
}

Previous

Kbd

Next

Listbox