UI

Page components

Look up the props and slots of the headings, cards, tables, row menus and forms every app page uses.

This page lists the components every admin and account page is made of, with their props and slots. It is for app developers and module authors who build those pages. Set up the module first: Overview.

The components add structure and spacing only. Colours and radius come from Nuxt UI. When to use which one is explained in the UX patterns; this page does not repeat those rules.

How they are registered

The components are auto-imported by name, with no prefix. None is a global component, so each page only loads the ones it uses.

To pick a component at runtime, call resolveComponent('PageHeading') with a literal name. Nuxt resolves it at build time. Do not register the component with global: true: a global component is bundled into the app entry and slows the first render of every page.

Every built-in string is a prop, and its default is translated. See the patterns strings.

Page frame

The heading, tabs and toolbar at the top of a page. The admin area's shell is on App shell.

ComponentPropsSlotsUse
PageHeadingtitle?, description?, breadcrumb?: string | BreadcrumbItem[]title, badge, description, default (meta row), actionsThe title block of an app page.
PageTabsitems: (NavigationMenuItem & { value? })[], v-model?noneTabs under a heading, for sections the page owns.
PageSectionSwitcheritems: NavigationMenuItem[], label?noneA button that opens a menu of every section, for narrow screens. The account area uses it.
PageToolbarnonedefault (search and filters), rightThe row of search and filter controls above a table.

breadcrumb. A string is a plain label above the title. An array renders breadcrumbs, such as [{ label: 'Users', to: '/admin/users' }, { label: 'Ada' }].

PageTabs modes. When the items have to, each tab is a route (link mode). With v-model, the tab whose value matches is active (state mode). On narrow screens the strip scrolls sideways and hides icons.

PageSectionSwitcher label. label names the button for screen readers. The current section is appended to it.

Cards

The framed blocks a page is made of.

ComponentPropsSlotsUse
SectionCardtitle?, description?, icon?, loading?, flush?header, actions, default, footerA framed block of a page. flush removes the body padding.
TableCardtitle?, description?, loading?, refreshing?default (the UTable), header, actions, footerThe frame a table sits in. footer holds TablePagination.
StatCardlabel, value?, hint?, icon?, to?, loading?, empty?default (replaces value)A number with a label. to links the card to the list it counts.
ListCardtitle, description?, loading?, isEmpty?, empty?, to?, toLabel?default (<li> rows), actionsA short divided list with a "View all" link.
DescriptionListitems: { key?, label, value? }[], empty?, loading?, align?one slot per keyLabel and value rows. A missing value shows "Not set".

TableCard loading. loading shows skeleton rows. refreshing keeps the rows on screen and dims them while new ones load. When to pass which is on Pages.

No table wrapper. Write <TableCard><UTable :ui="tableUi()" /></TableCard> yourself. A wrapper component would lose the slot types of UTable.

Table rows

The cells and controls inside a list.

ComponentPropsSlotsUse
TableIdentitytitle, description?, avatar?: AvatarPropsbadgesThe first cell of a row: a name, a muted second line and an optional avatar.
StatusBadgestatus, label?, colors?: Record<string, StatusColor>, size?, icon?noneA status as a subtle badge, coloured by statusColor.
RowMenuitems: DropdownMenuItem[] | DropdownMenuItem[][], subject?, variant?: 'ghost' | 'outline', size?, label?noneThe ⋯ menu of a row or heading.
TablePaginationtotal, v-model:page, v-model:page-size, pageSizes?default ({ range }, replaces the range text)The footer of a paginated list: "21–40 of 132", rows per page and pages.

StatusBadge. colors recolours single statuses, such as { archived: 'warning' }. label defaults to the status, so pass a translated one. Without a status or label it renders nothing. The colours are listed under statusColor.

RowMenu. A click on the menu does not reach the row. Its accessible name is "Actions for {subject}", or label. Use variant="outline" in a heading.

TablePagination. pageSizes defaults to [20, 50, 100]. The pages hide while everything fits on one page. A new page size goes back to page 1.

Forms and dialogs

The pieces of create, edit and confirm flows. How they fit together is on Forms and actions.

ComponentPropsSlotsUse
FormRowevery UFormField prop (a ui is merged)every UFormField slotOne horizontal row of an inline settings form: label and hint left, control right.
FormSlideovertitle, description?, formId, submitLabel, cancelLabel?, loading?, disabled?default (the form), footer({ cancel })A slideover for create and edit forms. Emits close.
ConfirmDialogtitle?, description?, confirmText?, cancelText?, destructive?, dismissible?noneThe modal behind useConfirmDialog. Emits close(boolean).

FormRow. The label column takes a third of the row, at most 16rem. Rows stack below the sm breakpoint. Each row holds one control, which gets the row's id. Sizing rules are on Pages.

FormSlideover footer. By default it shows Cancel and a submit button wired to form="<formId>". The footer slot replaces both. It receives cancel, which closes the slideover with false.

ConfirmDialog. Open it through useConfirmDialog rather than directly.

Empty states and the page root

UI has no empty-state component and no page wrapper:

  • An empty state is Nuxt UI's UEmpty, with variant="naked" inside a card.
  • A page root is <div class="flex flex-col gap-4">.

A complete detail page built from these components is on Pages.

Next steps

Copyright © 2026