<!-- Generated by scripts/gen-docs.mts from the JSDoc in registry/. Do not edit; run `pnpm run docs`. -->

# Item

One row of a list: leading media, a title with a description, and trailing actions. With `href` the whole row is one link, named by its title, with one tab stop, and the actions stay their own. Put rows in an `ItemGroup`, which makes them a list.

```tsx
import { Item } from "@/components/ouro/item/item";
```

## Example

```tsx
<Item
  href="/recipes/short-ribs"
  media={<img src={photo} alt="" />}
  mediaSize="md"
  title="Braised short ribs"
  description="Four hours, mostly hands-off"
/>
<Item title="Passkey on iPhone" description="Added May 2" actions={<Button variant="plain">Remove</Button>} stackBelow="sm" />
```

## Use instead when

- Use `Card` instead for a larger tile with a cover image and a body, and `Row` for a plain horizontal layout with no list semantics.

## Props

The props the modes share. Type: `ItemProps`.

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `actions` | `ReactNode` |  | Trailing content at the end of the row: buttons, a switch, a badge or a timestamp. With `href`, controls here stay their own tab stops, above the link. |
| `as` | `"div" \| "article" \| "li"` | `"div"` | The element to render. `ItemGroup` already wraps each Item in an `<li>`. |
| `className` | `string` |  | Layout only: margins, grid placement (`mt-2`). Appearance classes warn in development; use `variant`. |
| `description` | `ReactNode` |  | A short line under the title. Pass `<Text lines={2}>` to clamp a long one. With `href`, it also describes the link (`aria-describedby`), so a screen reader that lands on the row hears its title and then this line: a result's byline and snippet, a recipe's time. |
| `media` | `ReactNode` |  | Leading media: an `<img>` (cropped square), an `Avatar`, or an icon with `mediaSize="icon"`. Give an image `alt=""` when the title already names it. |
| `mediaAbove` | `"sm" \| "md" \| "always"` |  | Below this breakpoint the media leaves the row and runs full width above the text, at 4:3, as a recipe list shows its photos on a phone; above it, it sits beside the text at `mediaSize`. `always` keeps it above at every width. |
| `mediaSize` | `"sm" \| "md" \| "lg" \| "icon"` | `"sm"` | The media's size: `icon` puts an icon in a muted 40px tile (and hides it from screen readers); `sm` is 40px, `md` 64px, `lg` 112px for a recipe photo. |
| `ref` | `Ref<HTMLElement>` |  | Reaches the rendered element. |
| `size` | `"sm" \| "md"` | `"md"` | Row height: `md` has 12px above and below, `sm` 8px for dense lists. |
| `stackBelow` | `"sm" \| "md"` |  | Below this breakpoint the actions drop under the text, lined up with the title, as in a settings row on a phone. Without it they stay at the end at every width. |
| `title` (required) | `ReactNode` |  | What the row is: a name, a recipe title, a setting. It is the link's text with `href`. |
| `variant` | `"outline" \| "plain"` | `"plain"` | `plain` has no frame, for rows in an `ItemGroup`; `outline` is a bordered, padded box for a row on its own. |

## Modes

`ItemProps` is a union: pass the props of exactly one mode. Mixing them is a type error.

### With 

Not in this mode (typed `never`):

- `external`: Only with `href`.
- `href`: Not without `href`. Add `href` to make the whole row a link.
- `linkRef`: Only with `href`.

### With `href` and `external` and `linkRef`

| Prop | Type | Description |
| --- | --- | --- |
| `external` | `boolean` | Opens the link in a new tab, safely, and tells screen readers so. |
| `href` (required) | `string` | Makes the whole row one link, with one tab stop, named by its title. Internal paths go through `OuroProvider`'s `linkComponent`, as with `Link`. Controls anywhere in the row (a link in the description, a button in the media or the actions) stay their own tab stops and take their own clicks and taps. On a touch screen the row is at least 44px tall. |
| `linkRef` | `Ref<HTMLAnchorElement>` | A ref to the link's `<a>`, to move focus to it. |

## Native attributes

Also accepts the attributes in React's `HTMLAttributes` (`id`, `aria-*`, event handlers), passed to the rendered element, except those named on this page.

## Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

- `action`: Not a prop. Ouro UI uses `actions`, for one control or several: `<Item actions={<Button>…</Button>}>`.
- `asChild`: Not a prop. With `href` the whole row is a link: `<Item href="/recipes/1" title="…">`.
- `avatar`: Not a prop. Ouro UI uses `media`: `<Item media={<Avatar … />}>`.
- `icon`: Not a prop. Ouro UI uses `media`: `<Item media={<Icon />} mediaSize="icon">`.
- `image`: Not a prop. Ouro UI uses `media`: `<Item media={<img src="…" alt="" />}>`.
- `label`: Not a prop. Ouro UI uses `title`: `<Item title="Braised short ribs">`.
- `subtitle`: Not a prop. Ouro UI uses `description`: `<Item description="Four hours">`.
- `thumbnail`: Not a prop. Ouro UI uses `media`: `<Item media={<img src="…" alt="" />}>`.
- `to`: Not a prop. Ouro UI uses `href`, for router links too: `<Item href="/recipes/1" title="…">`.

## `className` is for layout only

Pass margins, width and grid placement (`mt-4`, `w-full`, `col-span-2`). Your classes always win over Ouro UI's: Item merges `className` last with `cn` (tailwind-merge), so a class that conflicts with its own replaces it.[^layout-classes]

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (`hover:`, `sm:`) and any `!` are removed, it starts with `bg-`, `text-`, `border-`, `rounded-`, `shadow-`, `font-`, `ring-`, `from-`, `via-`, `to-`, `fill-` or `stroke-`, or is `border`, `rounded`, `shadow` or `ring`, or has a `dark:` variant. Text wrapping, overflow and table layout classes (`text-wrap`, `text-ellipsis`, `border-collapse`) are layout and do not warn.

Alignment classes (`text-center`) warn too: set alignment on a parent element.

[^layout-classes]: test:registry/ouro/components/ouro/item/item.test.tsx::Item > passes attributes and a ref through, and lets layout classes win verify:testExists(registry/ouro/components/ouro/item/item.test.tsx::Item > passes attributes and a ref through, and lets layout classes win)
