The frame of a whole website block: its own look (an accent from one brand colour, plus font, material and density) scoped to the site root, an EN / TR switch and inner pages — all from server-rendered blocks. Links like ?page=pricing, ?page=home#faq and ?lang=tr inside the shell switch in place; a page change scrolls to the top, moves focus to the page’s h1, marks matching links aria-current="page" and follows back/forward. Overlays opened inside keep the site’s theme.
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { SiteShell, SiteShellLocale, SiteShellPage, Navbar, Hero, PageIntro, sitePageHref } from "@vamos-ui/react/blocks";
export default function Site() {
return (
<SiteShell accent="#B4532A" font="editorial" material="solid" density="comfortable" pages={["home", "shop"]}>
<SiteShellLocale code="en">
<Navbar
items={[{ label: "Shop", href: sitePageHref("shop") }, { label: "FAQ", href: sitePageHref("home", "faq") }]}
locales={[{ code: "en", href: "?lang=en" }, { code: "tr", href: "?lang=tr" }]}
…
/>
<SiteShellPage id="home"><Hero … /></SiteShellPage>
<SiteShellPage id="shop"><PageIntro title="Shop" … /></SiteShellPage>
</SiteShellLocale>
<SiteShellLocale code="tr">…</SiteShellLocale>
</SiteShell>
);
}Every language and page is rendered on the server; the shell only shows one. For a real multi-route site, route per page and locale and keep SiteShell for the look (or use ThemeScope).
Plain #anchor links keep working on the current page. Links to another page's section use sitePageHref("home", "faq").
Examples
Accent from one colour
siteAccent() is the same OKLCH maths as `vamos-ui brand`: the fill keeps the brand colour where it can, text on it is white or dark ink, and accent ink is darkened (light) or lightened (dark) until it reaches 4.5:1.
Clay · #B4532A
Accent ink for links and highlights
Mustard · #CA8A04
Accent ink for links and highlights
Ink blue · #2B4C7E
Accent ink for links and highlights
EN / TR switch
Each SiteShellLocale renders only while active and carries its own lang attribute. Keep one locale per page for money, dates and times (12- or 24-hour, never both).
Book an appointment
General practice for the whole family. Same-week appointments, Monday to Saturday.
Very dark brand colour on a dark site
Colours too dark for dark surfaces get a lighter dark-mode fill; light sections inside get the brand fill back.
Quarterly review
Your numbers, closed by the 5th
Fixed monthly fee. No hourly billing.
Light section, brand fill
API
SiteShell
| Prop | Type | Default |
|---|---|---|
accentA preset name (lime, ocean, ember, rose, graphite, or your own like brand) → data-accent. A colour (#hex, rgb(), oklch()) → the four accent variables on the root, contrast-checked. | string | — |
accentDarkExplicit dark-mode fill for a colour accent; derived when the colour is too dark. | string | — |
font→ data-font (editorial, grotesk, corporate, system or your own). | string | — |
material→ data-material. Websites usually want solid. | "glass" | "solid" | — |
density→ data-density. | "comfortable" | "compact" | "spacious" | — |
themeForce a mode for the whole site. Default: inherit. | "light" | "dark" | — |
dirDirection (also for Radix parts). | "ltr" | "rtl" | — |
locales / defaultLocaleLocale codes; the default is left out of the URL. | string[] / string | ["en", "tr"] / first |
locale / onLocaleChangeControlled locale. | string / (locale) => void | — |
pages / defaultPagePage ids; the default page has a clean URL. | string[] / string | ["home"] / first |
page / onPageChangeControlled page. | string / (page) => void | — |
routingWhere the page lives: ?page=, #page= or nowhere (previews, docs). The locale uses ?lang= unless memory. | "search" | "hash" | "memory" | "search" |
pageParam / localeParamURL keys. | string | "page" / "lang" |
classNameMerged onto the root (vb-scope font-sans text-fg). Add the scene colour and min height here. | string | — |
SiteShellPage
| Prop | Type | Default |
|---|---|---|
idPage id from pages; rendered only while current. | string | — |
titledocument.title after navigating to this page. | string | — |
SiteShellLocale
| Prop | Type | Default |
|---|---|---|
codeLocale code; rendered only while current, inside a lang wrapper. | string | — |
SiteShellLink
| Prop | Type | Default |
|---|---|---|
page / anchorTarget page and optional in-page anchor; aria-current when it is the current page. | string | — |
useSiteShell()
| Prop | Type | Default |
|---|---|---|
returnsFor client components inside the shell. | { page, locale, pages, locales, navigate(to), hrefFor(page, anchor?) } | — |
Helpers (server-safe)
| Prop | Type | Default |
|---|---|---|
sitePageHref(page, anchor?)"?page=shop", "?page=home#faq" — for Navbar, Footer and CTA hrefs in server components. | string | — |
siteLocaleHref(code)"?lang=tr". | string | — |
siteAccent(colour, { dark? })base, fg, inkLight, inkDark, dark?, measured contrast and warnings. Throws on a non-colour. | SiteAccentPalette | — |
siteAccentCss(palette, key)The scoped stylesheet under [data-site-accent="key"] (the shell renders it for you). | string | — |