Skip to content
Component installs need the registry setup
VegaStack Design

View Tabs

A table's saved views as a tab row — shared views, then the reader's own, a lock on locked views, a create menu, and one Select on narrow screens.

Status
stable
Since
0.25.71
Accessibility pattern
tablist with roving focus; a named Select when narrow

Last updated

Install

Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for View Tabs before installation. Retain the digest printed by this command.

pnpm exec vegastack-design verify view-tabs

Install with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.

pnpm dlx shadcn@4.21.0 add @vegastack/view-tabs

Run the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.

The same command installs the registry items it composes: @vegastack/button, @vegastack/dropdown-menu, @vegastack/select, @vegastack/tabs, @vegastack/tooltip, @vegastack/use-overflow.

Usage

import { ViewTabs } from "@/components/ui/view-tabs";

<ViewTabs
  views={[
    { id: "all", name: "All requests", kind: "grid", scope: "shared" },
    { id: "status", name: "By status", kind: "board", scope: "locked" },
    { id: "mine", name: "My follow-ups", kind: "grid", scope: "personal" },
  ]}
  value={view}
  onValueChange={setView}
  onCreate={(kind) => openCreateView(kind)}
  getViewActions={(view) => (
    <DropdownMenuItem onClick={() => rename(view)}>Rename</DropdownMenuItem>
  )}
/>;

ViewTabs is the row of saved views over a table or a list. Shared views come first (a locked view carries a lock), then a divider and the reader's own under Mine. Each tab shows the view's kind — a grid or a board — and its name. onCreate adds a + menu with two items, Grid view and Board view, and is called with the kind alone: the host's own create step names the view and decides who sees it (an "Only visible to me" switch), so the menu never asks shared or personal. getViewActions puts the open view's items (rename, duplicate, delete) in a ⋯ menu after the tabs. A long name ends in an ellipsis; when it is cut, the full name shows in a tooltip on hover and keyboard focus, and the tab still reads the whole name to a screen reader. The narrow select's list wraps a long name instead.

It is built on Tabs variant="line", which scrolls and keeps the active tab in view. Below @3xl of its own container the row becomes one Select with the same two groups. For a list/grid layout switch over the same data, use ViewToggle instead.

Scope

BehaviourWhere it lives
Which views exist, their order and who may change themHost
Saving a changed view ("Save for everyone", "Reset")Host
Rename, duplicate, deleteHost — through getViewActions
Naming a new view, shared or only visible to the makerHost — after onCreate(kind)

Examples

Narrow containers

API Reference

PropTypeDefaultDescription
onValueChange*(id: string) => void—Called with the id of the view the reader opens.
value*string—The open view's id.
views*readonly ViewTabsView[]—Every view the reader can open, in the host's order within each group.
aria-labelstring"Views"Accessible name of the tab row.
classNamestring—Extra classes for the root.
getViewActions((view: ViewTabsView) => React.ReactNode)—The open view's menu items (DropdownMenuItems: rename, duplicate, delete…), shown in a ⋯ menu after the tabs. Return null for none.
labelsPartial<ViewTabsLabels>EnglishThe component's words.
onCreate((kind: ViewTabsView["kind"]) => void)—Offer the + menu: a grid view or a board view. Called with the kind picked; the host's own create step names the view and decides whether it is shared or the reader's alone. Omit it when the reader can't create views.
refReact.Ref<HTMLDivElement>—Ref to the root.

Data attributes and CSS variables on ViewTabs

AttributeValues
data-slot"view-tabs" | "view-tabs-actions" | "view-tabs-create" | "view-tabs-divider" | "view-tabs-list" | "view-tabs-mine"

View

PropTypeDefaultDescription
id*string—Stable id — the value.
kind*"board" | "grid"—A table (grid) or a board.
name*string—The view's name.
scope*"locked" | "personal" | "shared"—shared and locked views are everyone's; personal ones are the reader's alone.

Accessibility

  • The tab row is a tablist named by aria-label (default "Views"): one tab stop, arrows move, Enter or Space opens a view. A locked view is read as "By status, locked".
  • The + button is named "New view"; the ⋯ button after the open view's name ("All requests options").
  • Narrow, the row is one Select with the same name and the same Shared and Mine groups.
KeyAction
← →Move between views.
Enter / SpaceOpen the focused view.
TabLeave the row for the + and ⋯ buttons.
ContractStates tested
Behaviourdefault, with-personal, locked, create-menu, actions-menu, narrow
Accessibilitykeyboard, labeled, roving-tabindex
Visualdefault, active, locked, narrow

Do / Don't

Do
Keep a view's personal changes in the host and offer Save for everyone where the reader may change shared views.
Don't
Use ViewTabs to switch a list between rows and cards — that is ViewToggle.

On this page