Skip to main content

Navigation

FamilyBar

The slim strip above a site's own header that links every site of a family, the same links in the same order on each, with the site being shown marked aria-current="true", in the text colour, underlined in the primary colour as Navbar marks the current page. A labelled <nav> of plain links: the server HTML is the whole bar, so a page that never hydrates shows it as is. On a narrow screen the row scrolls inside itself, never the page, and fades at the side that hides more links, so a name cut at the edge reads as more to come. In browsers that support it the fade and the current site's link in view need no script. Once hydrated, the row fades in any browser and brings the current site's link into view when it is out of view. Links render through OuroProvider's linkComponent, so a link to the site's own path stays in its router.

On this site

This site's own pages use FamilyBar too. Open one with X-ray pointing it out: The Nautilus's story · The home page

Install

Once per app, with Tailwind CSS v4 and an @/* path alias (Ouro HX is built on Base UI, so --base base; skip -t in an existing app):

npx shadcn@latest init --base base --preset nova --yes --no-monorepo
npx shadcn@latest add ourostack/ouro-ui/ouro-base#v1.3.10

Then the component. From v0.8.0 it installs only the helpers it imports and never touches your stylesheet (Installing):

npx shadcn@latest add ourostack/ouro-ui/family-bar#v1.3.10

Or, with the @ouro namespace set up:

npx shadcn@latest add @ouro/ouro-base @ouro/family-bar

Its tests, stories and Playwright spec are optional. They need Vitest 4.1.11 or later, and from v0.8.0 never change a version your app has (Testing):

npx shadcn@latest add ourostack/ouro-ui/family-bar#v1.3.10 ourostack/ouro-ui/family-bar-tests#v1.3.10
import { FamilyBar } from "@/components/ouro/family-bar/family-bar";

Paths use shadcn's default @/ alias; the CLI rewrites them to yours.

Example

<FamilyBar
  label="Sites"
  links={[
    { id: "home", label: "Lantern", href: "https://example.com/" },
    { id: "docs", label: "Docs", href: "https://docs.example.com/" },
    { id: "blog", label: "Blog", href: "https://blog.example.com/" },
  ]}
  current="docs"
/>

Use instead when

  • Use Navbar instead for a site's own pages, under the FamilyBar, and FamilyFooter for the same links at the foot of the page.

Props

Type: FamilyBarProps.

brand
Type: ReactNode
The family's mark or name, before the links. It stays in place while the links scroll.
className
Type: string
Layout only: position (sticky top-0), grid placement. Appearance classes warn in development.
current
Type: string
The id of the site being shown. Its link gets aria-current="true", the text colour and a primary underline, so the mark is not colour alone.
label
Type: string
Default: "Sites"
Names the navigation for screen readers. It is not shown.
links (required)
Type: readonly FamilyLink[]
The family's sites, in order. Give every site the same list in the same order, so the bar reads the same on each.
ref
Type: Ref<HTMLElement>
Reaches the rendered element.

Don't use

These are not props. Passing one fails the type check with the fix in the error, and in development a console message names the fix.

  • children: Not rendered. The bar is links and brand.
  • currentPath: Not a prop. FamilyBar marks a site by its id, not by a path: <FamilyBar current="docs">.
  • items: Not a prop. FamilyBar takes links: <FamilyBar links={[{ id: "docs", label: "Docs", href: "/" }]} />.

className is for layout only

Pass margins, width and grid placement (mt-4, w-full, col-span-2).

Appearance comes from props, not classes. In development, a class that sets appearance logs one warning per component instance, naming the prop to use instead. A class sets appearance when, after its variants (hover:, sm:) and any ! are removed, it starts with bg-, text-, border-, rounded-, shadow-, font-, ring-, from-, via-, to-, fill- or stroke-, or is border, rounded, shadow or ring, or has a dark: variant. Text wrapping, overflow and table layout classes (text-wrap, text-ellipsis, border-collapse) are layout and do not warn.

Alignment classes (text-center) warn too: set alignment on a parent element.

Types

One site of a family, in a FamilyBar and a FamilyFooter.

interface FamilyLink {
  /** Names the site for `current`: "docs". It is not shown. */
  id: string;
  /** The site's name, the link's text: "Docs". */
  label: string;
  /** Where the link goes: the site's home page, "https://docs.example.com/". */
  href: string;
}