Navigation
Every component, with its variants, sizes and states. Change the appearance here and every sample follows.
Tabs
Parts of one screen. The tab is in the URL, and the arrow keys move along the row.
Used in the demo at /settings
States
<!-- Links: the tab is in the URL. shared/ui/tabs.mjs moves between them. -->
<div class="or-tabs" role="tablist" aria-label="Settings">
<a class="or-tabs__tab" role="tab" href="settings.html?tab=general" aria-selected="true" tabindex="0">General</a>
<a class="or-tabs__tab" role="tab" href="settings.html?tab=billing" aria-selected="false" tabindex="-1">Billing</a>
</div>
<div className="or-tabs" role="tablist" aria-label={t('settings.title')} onKeyDown={onKeyDown}>
{SETTINGS_TABS.map((name) => (
<Link key={name} className="or-tabs__tab" role="tab" to={`?tab=${name}`}
aria-selected={name === tab} tabIndex={name === tab ? 0 : -1}>
{t(`settings.tabs.${name}`)}
</Link>
))}
</div>
<div class="or-tabs" role="tablist" :aria-label="t('settings.title')" @keydown="onKeyDown">
<RouterLink v-for="name in SETTINGS_TABS" :key="name" class="or-tabs__tab" role="tab"
:to="{ query: { tab: name } }" :aria-selected="name === tab" :tabindex="name === tab ? 0 : -1">
{{ t(`settings.tabs.${name}`) }}
</RouterLink>
</div>
<div className="or-tabs" role="tablist" aria-label={t('settings.title')} onKeyDown={onKeyDown}>
{SETTINGS_TABS.map((name) => (
<Link key={name} className="or-tabs__tab" role="tab" href={`/settings?tab=${name}`}
aria-selected={name === tab} tabIndex={name === tab ? 0 : -1}>
{t(`settings.tabs.${name}`)}
</Link>
))}
</div>
<div class="or-tabs" role="tablist" :aria-label="t('settings.title')" @keydown="onKeyDown">
<NuxtLink v-for="name in SETTINGS_TABS" :key="name" class="or-tabs__tab" role="tab"
:to="{ path: localePath('/settings'), query: { tab: name } }" :aria-selected="name === tab" :tabindex="name === tab ? 0 : -1">
{{ t(`settings.tabs.${name}`) }}
</NuxtLink>
</div>Pagination
Where the reader is in a long list, and the rows per page.
Used in the demo at /orders
States
Showing 1–25 of 287
Showing 126–150 of 287
Showing 276–287 of 287
<!-- Rendered by page-orders.js from shared/ui/table.mjs pageWindow(). -->
<div class="or-pager" data-or-pager></div>
<Pager page={orders.data} onPage={(page) => table.patch({ page })} onPerPage={(perPage) => table.patch({ perPage })} />
<Pager :page="orders.data.value" @page="(page) => table.patch({ page })" @per-page="(perPage) => table.patch({ perPage })" />
{/* Links rather than buttons: every page is a URL the server renders. */}
<Link className="or-pager__page" href={hrefFor(path, query, { page: page + 1 }, keep)} aria-label={t('table.nextPage')}>
<Icon name="chevron-right" size={16} />
</Link>
<TablePager :page="orders.data.value" @page="(page) => table.patch({ page })" @per-page="(perPage) => table.patch({ perPage })" />Bulk action bar
Appears with the first selected row, in the flow rather than over the table.
Used in the demo at /orders
Variants
<div class="or-bulkbar" role="region" aria-live="polite" aria-label="3 selected">
<span class="or-bulkbar__count">3 selected</span>
<button type="button" class="or-btn or-btn--sm">Mark as shipped</button>
</div>
<BulkBar count={selection.selected.size} onClear={selection.clear}>
<button type="button" className="or-btn or-btn--sm" onClick={() => bulk.mutate({ status: 'shipped', fulfilment: 'fulfilled' })}>{t('orders.bulkMarkShipped')}</button>
</BulkBar>
<BulkBar :count="selection.selected.value.size" @clear="selection.clear">
<button type="button" class="or-btn or-btn--sm" @click="bulk.mutate({ status: 'shipped', fulfilment: 'fulfilled' })">{{ t('orders.bulkMarkShipped') }}</button>
</BulkBar>
{/* The selection is client state; the action is a server action. */}
<BulkBar>
<BulkActions />
</BulkBar>
<TableBulkBar :count="selection.selected.value.size" @clear="selection.clear">
<button type="button" class="or-btn or-btn--sm" @click="bulk.mutate({ status: 'shipped', fulfilment: 'fulfilled' })">{{ t('orders.bulkMarkShipped') }}</button>
</TableBulkBar>