ATOM

Item

A single selectable row with optional leading/trailing slots. Lists, menus, and pickers.

Preview

Variants: defaultoutlinemuted (default: default)

Sizes: defaultsmxs (default: default)

Editorial

<!-- F12c editorial — non-derivable only. Review: Karen. -->

## Ejemplos

Selectable list row:

```tsx import { Item, ItemMedia, ItemContent, ItemTitle, ItemDescription, ItemActions, } from '@/components/atoms/Item';

<Item variant="outline" size="default" href="/docs"> <ItemMedia variant="icon">{/* icon */}</ItemMedia> <ItemContent> <ItemTitle>Docs</ItemTitle> <ItemDescription>Guides and API</ItemDescription> </ItemContent> <ItemActions>→</ItemActions> </Item> ```

## Accesibilidad

- With `href`, root renders `<a>`; otherwise `<div>` — add keyboard handlers/role if clickable without href. - Prefer real links for navigation so open-in-new-tab and middle-click work.

## Cuándo no usar

- Form options in a closed list → `Select` / `Radio`. - Dense data grids → `Table`.

## Criterio de uso

- Usa Item para filas con una jerarquía clara de media, título, descripción y acción; mantén el contenido secundario breve. - Si la fila navega, usa `href` para conservar semántica, foco, historial y abrir en nueva pestaña. - Usa `variant` y `size` para expresar densidad y agrupación, no para convertir cada fila en una tarjeta visual independiente.

## Gotchas

- Un Item clickeable sin `href` necesita teclado, role y estados equivalentes; es preferible un enlace real cuando el destino es navegación. - Los slots deben conservar orden lógico para tecnologías asistivas: título antes de metadatos y acción con nombre claro.

Uso

import {
  Item, ItemMedia, ItemContent, ItemTitle, ItemDescription, ItemActions,
} from '@/components/atoms/Item';

<Item variant="outline" size="default" href="/docs">
  <ItemMedia variant="icon">{/* icon */}</ItemMedia>
  <ItemContent>
    <ItemTitle>Docs</ItemTitle>
    <ItemDescription>Guides and API</ItemDescription>
  </ItemContent>
  <ItemActions>→</ItemActions>
</Item>

Props

PropTipoDefaultRango / opcionesWhatHow
variantselectdefault`default`, `outline`, `muted`Surface emphasis of the row.default lists; outline for bordered menus; muted for secondary rows. Default: default.
sizeselectdefault`default`, `sm`, `xs`Vertical density of the item.default in main lists; sm/xs in sidebars and dense pickers. Default: default.

Gotchas

  • react

    With href, root renders <a>; otherwise <div>. Compose ItemMedia/Content/Title/Description/Actions; group with ItemGroup.

  • a11y

    If clickable without href, add keyboard handlers and role; prefer href for navigation.

Anatomía CSS

<div class="item-separator">

</div>
ClasePropósito
item-separatorroot

Tokens resueltos

Valores finales tras seguir la cadena de tokens. Derivados del source: si un token cambia, esta tabla cambia sola.

VariantePropValorToken
allbg#e5e5e5border
outlinebordernone(unparsed)
allfg#525252muted.foreground
allhover-bg#f5f5f5accent
mutedbg#f5f5f5muted
mutedhover-bg#f5f5f5accent
allbordernone(unparsed)

Animaciones

PropiedadDuraciónEasing
background-colorvar(--duration-100)var(--easing-in-out)

CSS mínimo funcional

Autocontenido: sin imports ni tokens. Para previews y prototipos — en producción se consume el CSS del DS (@atom-uikit/css/components.css</code>, <code>@atom-uikit/tokens/tokens.css).

/* -------------------------------------------------------------------------
   Item

   Versatile content row: media + title + description + actions.
   For lists, settings, notifications, etc.

   Variants: default, outline, muted
   Sizes:    default, sm, xs
   Parts:    .item, .item__media, .item__content, .item__title,
             .item__description, .item__actions, .item-group,
             .item-separator
   ------------------------------------------------------------------------- */

/* ---- Item ---- */

.item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  font-family: 'inter tight', -apple-system, blinkmacsystemfont, 'segoe ui', roboto, helvetica, arial, sans-serif, ui-sans-serif, system-ui, sans-serif;
  text-decoration: none;
  color: inherit;
  transition: background-color 100ms cubic-bezier(0.4, 0, 0.2, 1);
}

.item:hover {
  background-color: #f5f5f5;
}

/* ---- Variants ---- */

.item--outline {
  border: 1px solid #e5e5e5;
  border-radius: 12px;
}

.item--muted {
  background-color: #f5f5f5;
  border-radius: 12px;
}

.item--muted:hover {
  background-color: #f5f5f5;
}

/* ---- Sizes ---- */

.item--sm {
  gap: 8px;
  padding: 8px 12px;
}

.item--xs {
  gap: 8px;
  padding: 4px 8px;
}

/* ---- Media ---- */

.item__media {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  color: #525252;
}

.item__media--icon {
  width: 40px;
  height: 40px;
  border-radius: 12px;
  background-color: #f5f5f5;
  padding: 8px;
}

.item--sm .item__media--icon {
  width: 32px;
  height: 32px;
  padding: 8px;
}

.item__media--icon svg {
  width: 100%;
  height: 100%;
}

.item__media--image {
  width: 48px;
  height: 48px;
  border-radius: 8px;
  overflow: hidden;
}

.item__media--image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ---- Content ---- */

.item__content {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* ---- Title ---- */

.item__title {
  font-size: 12.8px;
  font-weight: 500;
  line-height: 1.45;
  color: #0a0a0a;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- Description ---- */

.item__description {
  font-size: 10.24px;
  line-height: 1.4;
  color: #525252;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ---- Actions ---- */

.item__actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-shrink: 0;
}

/* ---- Group ---- */

.item-group {
  display: flex;
  flex-direction: column;
}

.item-group--outline {
  border: 1px solid #e5e5e5;
  border-radius: 12px;
  overflow: hidden;
}

.item-group--outline > .item {
  border: none;
  border-radius: 0;
}

/* ---- Separator ---- */

.item-separator {
  height: 1px;
  background-color: #e5e5e5;
}

/* ---- Reduced motion ---- */

@media (prefers-reduced-motion: reduce) {
  .item {
    transition-duration: 0ms;
  }
}

Codigo fuente

components-react
components/atoms/Item.tsx
import { type ReactNode, type HTMLAttributes } from 'react';

function cn(...classes: (string | false | undefined | null)[]) {
  return classes.filter(Boolean).join(' ');
}

/* ---- Item ---- */

export type ItemProps = {
  variant?: 'default' | 'outline' | 'muted';
  size?: 'default' | 'sm' | 'xs';
  href?: string;
  children: ReactNode;
  className?: string;
} & HTMLAttributes<HTMLElement>;

export function Item({ variant = 'default', size = 'default', href, children, className, ...props }: ItemProps) {
  const classes = cn(
    'item',
    variant !== 'default' && `item--${variant}`,
    size !== 'default' && `item--${size}`,
    className,
  );

  if (href) {
    return <a href={href} className={classes} {...(props as any)}>{children}</a>;
  }

  return <div className={classes} {...props}>{children}</div>;
}

/* ---- Media ---- */

export type ItemMediaProps = {
  variant?: 'default' | 'icon' | 'image';
  children: ReactNode;
  className?: string;
};

export function ItemMedia({ variant = 'default', children, className }: ItemMediaProps) {
  return (
    <div className={cn('item__media', variant !== 'default' && `item__media--${variant}`, className)}>
      {children}
    </div>
  );
}

/* ---- Content ---- */

export function ItemContent({ children, className }: { children: ReactNode; className?: string }) {
  return <div className={cn('item__content', className)}>{children}</div>;
}

/* ---- Title ---- */

export function ItemTitle({ children, className }: { children: ReactNode; className?: string }) {
  return <p className={cn('item__title', className)}>{children}</p>;
}

/* ---- Description ---- */

export function ItemDescription({ children, className }: { children: ReactNode; className?: string }) {
  return <p className={cn('item__description', className)}>{children}</p>;
}

/* ---- Actions ---- */

export function ItemActions({ children, className }: { children: ReactNode; className?: string }) {
  return <div className={cn('item__actions', className)}>{children}</div>;
}

/* ---- Group ---- */

export type ItemGroupProps = {
  variant?: 'default' | 'outline';
  children: ReactNode;
  className?: string;
};

export function ItemGroup({ variant = 'default', children, className }: ItemGroupProps) {
  return (
    <div className={cn('item-group', variant === 'outline' && 'item-group--outline', className)}>
      {children}
    </div>
  );
}

/* ---- Separator ---- */

export function ItemSeparator({ className }: { className?: string }) {
  return <div className={cn('item-separator', className)} />;
}

Webflow

Webflowitem

Pega en el Designer como application/json, luego convierte a Component (Atom / Item) y publica. Formato interno no documentado de Webflow — regenerable, no dependencia de runtime.

Setup del sitio (una vez)

Custom Code → Head:

<link rel="stylesheet" href="https://atom-web-ds.vercel.app/v1/tokens.css">
<link rel="stylesheet" href="https://atom-web-ds.vercel.app/v1/components.css">

Unsupported (no silencioso)

  • selector on .item--sm .item__media--iconcompound/descendant selector — moved to head Custom Code (Designer styles are single-class)
  • selector on .item__media--icon svgcompound/descendant selector — moved to head Custom Code (Designer styles are single-class)
  • selector on .item__media--image imgcompound/descendant selector — moved to head Custom Code (Designer styles are single-class)
  • selector on .item-group--outline > .itemcompound/descendant selector — moved to head Custom Code (Designer styles are single-class)
  • @media on (prefers-reduced-motion: reduce)not a Designer breakpoint — moved to head Custom Code block

Tras pegar: Create component → nombre Atom / Item → Publish.

Componentes relacionados

On this page

Detalles

Publicado14 de mayo de 2026
Categorialayout
Lectura...
Visitas...
Ayuda?Slack

Componente

Item

Source

components-react / cssDisponible via MCP: atom_uikit_source("item")
Abrir en Storybook