List item
Show one row with a title and description and an action or value beside it. Built on it: List field.
Anna Petrova
anna@work
Ivan Sidorov
ivan@work
Verified
The account passed the check.
<script setup lang="ts">import { BadgeCheck } from '@lucide/vue'import { UiCard, UiList, UiListItem, UiAvatar, UiButton, UiBadge } from 'grani'</script> <template> <UiCard :padded="false" class="w-full max-w-md"> <UiList> <UiListItem title="Anna Petrova" description="anna@work"> <template #media><UiAvatar name="Anna Petrova" /></template> <template #actions><UiButton variant="ghost">Edit</UiButton></template> </UiListItem> <UiListItem title="Ivan Sidorov" description="ivan@work"> <template #media><UiAvatar name="Ivan Sidorov" /></template> <template #actions><UiButton variant="ghost">Edit</UiButton></template> </UiListItem> <UiListItem title="Verified" description="The account passed the check."> <template #media><BadgeCheck aria-hidden="true" /></template> <template #actions><UiBadge tone="success" label="Done" /></template> </UiListItem> </UiList> </UiCard></template>
Also called list row, setting row, cell.
Usage
<UiListItem>…</UiListItem> With GraniResolver in the Vite config, a template needs no import: set it up once.
API
| Name · type | Default | Description |
|---|---|---|
| State | ||
| loadingboolean | A command or link row is running: a spinner in place of the glyph, clicks refused, focus kept. | |
| errorstring | With as="label": an error in place of the description, read with the control and marking it invalid. | |
| Behavior | ||
| titlestring | The primary line of text. | |
| descriptionstring | Supporting text below the title. | |
| highlightstring | Letters of the title to mark, in any case: the query of a search over the rows. The first match is marked. | |
| litboolean | A moment of brand color: the row just came, or a refused repeat points at it. Set it, clear it after a second. | |
| aslabel | button | div | The root element: label for a field, button for a command; a plain row is a div. | |
| tostring | A route or URL. Makes the whole row a link; actions then hold no controls. A disabled one is a disabled button, not a link; javascript: and data: are refused, as on UiLink. | |
| target_blank | _self | With to: _blank or _self decides the tab; unset, a new tab for an absolute address only. | |
| relstring | With to: replaces the default noreferrer (nofollow, sponsored); noopener stays on a new tab. | |
| stepboolean | With as="button": the row goes one level in, a step of a drawer; a chevron at the end. | |
| Look | ||
| variantsoft | outline | plain | muted | plain for a row among rows, outline for a standalone row, muted for a filled surface.
On a notice in a UiList, soft fills the row with its tone's pale plate as well; plain keeps the surface. Alone the notice is its card either way. | |
| sizesm | md | md for pages, sm for drawers and dense lists. Unset: the host's (a sidebar says sm), else md. Rows keep their own scale, 44 at sm and 56 at md; the app's size (createGrani({ size })) does not move them. | |
| tonebrand | success | warning | danger | info | Meaning. On a plain row a notice: alone a white card whose start edge is in the tone, in a UiList a row with the tone's edge, read as a status. On a command or link row the ink alone: danger for an irreversible action, brand for the one that makes something new (“Add …”). | |
| Form and access | ||
| disabledboolean | A command or link row that cannot be taken now: no rights, nothing to do. | |
| requiredboolean | With as="label": an asterisk after the title and aria-required on the control. | |
Anything else lands on the root element: native attributes, aria-*, data-testid.
When to use another component
| When you need | Take |
|---|---|
| A field with its label above its control | Field |
| An action on its own | Button |
| A list of names that grows from its last row | List field |
| A message about a request | A toast through Toaster |
| Why a list is empty | No data |