List Item
- Stable
- WCAG 2.2 evidence
- RTL
One row of a list: optional leading icon, avatar or checkbox, a title with an optional subtitle, and an
optional trailing badge, switch or chevron. Use it for rows of similar items; use a table for comparing values. Presentational: no state and no "use client", so it renders in React Server Components. Without href or onPress the row is
static text. With href the title is a native link and with onPress a native button, in both cases stretched over the whole
row, so there is one target named by the title; the row shows a hover fill and the focus ring inside its edge (WCAG 2.1.1,
2.4.7, 2.4.11, 2.5.8). Icons are decorative (1.1.1); nothing is conveyed by colour (1.4.1); text wraps (1.4.10, 1.4.12). Put the rows in a list: <ul> with one <li> per row, or role="list" on a container. Consumer duties: the title wording,
names for any switch or checkbox passed in, and locale-aware formatting of dates and numbers in the text.
import { ListItem } from "@nexera-ui/react";- 13
- examples
- 10
- props
- 2
- live controls
- 1
- platform
- 10
- WCAG criteria
- 21
- blocks use it
Try every prop. Copy the code.
Change the props and the code updates. Check light and dark, LTR and RTL, and phone width.
import { ListItem } from "@nexera-ui/react";
<ListItem />Examples 12
The same examples as Storybook, rendered live. Open Code to copy one.
Leading icon
Leading=Icon: the icon slot in a 36 px tile.
import { ListItem } from "@nexera-ui/react";
import { LuFileText } from "react-icons/lu";
<ListItem title="Employment contract" subtitle="PDF, 240 KB" icon={<LuFileText />} />;
Leading avatar
Leading=Avatar: pass a decorative Avatar (the title names the person).
import { Avatar, ListItem } from "@nexera-ui/react";
<ListItem
title="Ayesha Khan"
subtitle="Senior product designer"
leading={<Avatar size="lg" initials="AK" isDecorative />}
/>;
Leading checkbox
Leading=Checkbox: a named Checkbox in the leading slot, on a static row.
import { useState } from "react";
import { Checkbox, ListItem } from "@nexera-ui/react";
function SelectableRow() {
const [selected, setSelected] = useState(true);
return (
<ListItem
title="Ayesha Khan"
subtitle="Senior product designer"
leading={
<Checkbox aria-label="Select Ayesha Khan" isSelected={selected} onChange={setSelected} />
}
/>
);
}
export function LeadingCheckbox() {
return <SelectableRow />;
}
Trailing chevron
Trailing=Chevron: a link row (href) shows the chevron, which mirrors in right-to-left layouts.
import { ListItem } from "@nexera-ui/react";
import { LuFileText } from "react-icons/lu";
<ListItem title="Ayesha Khan" subtitle="Senior product designer" href="#" icon={<LuFileText />} />;
Trailing switch
Trailing=Switch: a named Switch in the trailing slot, on a static row (a switch cannot sit inside a link row).
import { useState } from "react";
import { ListItem, Switch } from "@nexera-ui/react";
function SwitchRow() {
const [on, setOn] = useState(true);
return (
<ListItem
title="Email notifications"
subtitle="Leave approvals and payslips"
trailing={<Switch aria-label="Email notifications" isSelected={on} onChange={setOn} />}
/>
);
}
export function TrailingSwitch() {
return <SwitchRow />;
}
Trailing badge
Trailing=Badge: a Badge in the trailing slot.
import { Avatar, Badge, ListItem } from "@nexera-ui/react";
<ListItem
title="Ayesha Khan"
subtitle="Senior product designer"
href="#"
leading={<Avatar size="lg" initials="AK" isDecorative />}
trailing={<Badge tone="success" label="Active" />}
/>;
Button row
A button row (onPress): the title is a native button stretched over the row.
import { useState } from "react";
import { ListItem } from "@nexera-ui/react";
import { LuFileText } from "react-icons/lu";
function ButtonRowDemo() {
const [count, setCount] = useState(0);
return (
<div className="flex flex-col gap-2">
<ListItem
title="Request leave"
subtitle="Opens the leave form"
icon={<LuFileText />}
onPress={() => {
setCount((value) => value + 1);
}}
/>
<p className="m-0 text-body-small text-secondary" aria-live="polite">
Pressed {count} times
</p>
</div>
);
}
export function ButtonRow() {
return <ButtonRowDemo />;
}
Disabled
isDisabled: the text dims, the row is aria-disabled and stops being a link.
import { ListItem } from "@nexera-ui/react";
import { LuFileText } from "react-icons/lu";
<ListItem
title="Ayesha Khan"
subtitle="Senior product designer"
href="#"
isDisabled
icon={<LuFileText />}
/>;
In a list
Rows in a list: <ul> with one <li> per row.
import { Avatar, ListItem } from "@nexera-ui/react";
export function InAList() {
return (
<ul className="m-0 flex list-none flex-col overflow-hidden rounded-lg border border-solid border-default p-0">
{[
["Ayesha Khan", "Senior product designer", "AK"],
["Bilal Ahmed", "Engineering manager", "BA"],
["Sana Iqbal", "People operations", "SI"],
].map(([name, role, initials]) => (
<li key={name}>
<ListItem
href="#"
title={name ?? ""}
subtitle={role}
leading={<Avatar size="lg" initials={initials ?? ""} isDecorative />}
/>
</li>
))}
</ul>
);
}
Long content
Long and translated text wraps; the trailing badge drops below the text when the row is too narrow for both.
import { Badge, ListItem } from "@nexera-ui/react";
import { LuFileText } from "react-icons/lu";
<ListItem
title="Mitarbeiterhandbuch fuer die Personalabteilung einschliesslich aller Anhaenge"
subtitle="Zuletzt aktualisiert am 2. Oktober 2026 von der Rechtsabteilung"
icon={<LuFileText />}
trailing={<Badge tone="warning" label="Genehmigung ausstehend" />}
/>;
Right to left
Right-to-left: the leading part sits at the start (right) and the chevron points left.
import { Avatar, ListItem } from "@nexera-ui/react";
<ListItem
title="عائشة خان"
subtitle="مصممة منتجات أولى"
href="#"
leading={<Avatar size="lg" initials="ع خ" isDecorative />}
/>;
Narrow container
A 14 rem container: the text wraps and the trailing part moves under it.
import { Avatar, Badge, ListItem } from "@nexera-ui/react";
<div className="max-w-56">
<ListItem
title="Ayesha Khan"
subtitle="Senior product designer"
leading={<Avatar size="lg" initials="AK" isDecorative />}
trailing={<Badge tone="success" label="Active" />}
/>
</div>;
Props 10
Press "Try it" on a card to load that prop into the playground.
10 props shown
hrefNexerastringNot set: the row is not a link.
Destination. The title becomes a native link stretched over the whole row (one target; hover fill, focus ring on the row)
and the chevron is shown. Renders in Server Components.
Not with onPress.
onPressNexera() => voidNot set: the row is not a button.
Not with href.
Called when the row is pressed (click, Enter or Space). The title becomes a native <button> stretched over the whole row.
Function props only work from Client Components; in Server Components use href.
targetNexerastringOnly with href.
Link target, for example _blank.
relNexerastringOnly with href.
Link relation, for example noopener.
title*NexeraReactNodeMain text. On a link or button row it is the link text, so it is the accessible name of the row. Wraps instead of truncating.
subtitleNexeraReactNodeSecond line, shown when provided.
iconNexeraReactNodeIcon in a 36 px tile before the text. 18 px, decorative.
leadingNexeraReactNodeControl or picture before the text: pass <Avatar size="lg" isDecorative />
(40 px; decorative because the title names the person) or a <Checkbox aria-label="Select Ayesha Khan" />. Replaces the
plan's leading enumeration, because a slot can carry the actual content. Shown after icon when both are set.
trailingNexeraReactNodeContent at the end of the row: pass a <Badge /> or a
<Switch aria-label="..." />. A link or button row shows the Figma chevron (Trailing=Chevron) when trailing is not
set. A switch or checkbox cannot sit inside a link or button row (nested controls): leave href and onPress unset then.
isDisabledNexerabooleanThe row is unavailable: its text dims, a link or button row stops being one, and aria-disabled is set. Not in Figma
(derived).
* Required. React Aria props shown are the ones most apps use; the component accepts the rest of its React Aria props too.
Accessible by default.
Built on React Aria, and covered by the WCAG 2.2 evidence generated on every build.
WCAG 2.2 evidence
5 direct · 5 supporting- 1.1.1Non-text ContentLevel A · tested directly
- 1.3.1Info and RelationshipsLevel A · tested directly
- 1.4.4Resize TextLevel AA · supporting test
- 1.4.12Text SpacingLevel AA · supporting test
- 2.1.1KeyboardLevel A · tested directly
- 2.4.4Link Purpose (In Context)Level A · tested directly
- 2.4.7Focus VisibleLevel AA · supporting test
- 2.4.11Focus Not Obscured (Minimum)Level AA · supporting test
- 2.5.8Target Size (Minimum)Level AA · supporting test
- 4.1.2Name, Role, ValueLevel A · tested directly
Fits any width.
Nexera components respond to the space they are given. Drag the corner of the frame, or pick a width.
Styling hooks
Pass className to add Tailwind classes (merged last). State is exposed as data attributes, so you can style it with variants like data-pressed:.
<ListItem className="shadow-sm" />Used in blocks
- Choose a workspaceSign in and account
- Invite your teamOnboarding
- Sidebar app shellApp shells and navigation
- Mobile app shellApp shells and navigation
- Filter barLists, tables and records
- People directoryLists, tables and records
- Record details drawerLists, tables and records
- Activity feedLists, tables and records
- Add a personForms and data entry
- SecuritySettings and preferences
- Team members and rolesSettings and preferences
- Notification centreMessaging and collaboration
- Order summaryCommerce and payments
- Team mapMaps and places
- Office finderMaps and places
- People nearbyMaps and places
- Document previewMedia and content
- Action sheetMobile patterns
- Colour sheetMobile patterns
- Tab bar appMobile patterns
- Pull to refresh feedMobile patterns
Related components
- AccordionItemOne collapsible section of an FAQ or settings page.
- AreaChartA stacked area chart: layers piled up over time with the title, range switch, actions and legend of the card.
- AvailabilityRowOne person's availability across a window of the day: an avatar with initials and the name, and a timeline with the busy periods drawn as bars.
- AvatarA person or organisation shown as a photo, initials or an icon.
- AvatarGroupA row of overlapping avatars with a "+N" chip for the rest.
- AvatarLabelAn avatar with a name and an optional subtitle beside it, for a person in a list, a header or a mention.
- BadgeShort status or category label: `Tone` x `Variant` x `Size`, with an optional dot, leading icon and remove button.
- BadgeGroupA pill that pairs a small badge with a short message, for an announcement or a status line.