Getting started
Pick your setup. Every route uses the same tokens, so a brand file made in the builder works in all of them.
Get the packages
npm packages are coming soon. Until then, install from the GitHub repository: clone it, run one command to pack the packages, then add the packed files to your project.
Terminal
git clone https://github.com/Zammi1/brandcloud.git
cd brandcloud
pnpm install
pnpm packs # builds every package and packs it into ./packsThe commands below assume your project folder sits next to the cloned repository. Change the paths if it does not.
Astro
The Astro components ship as .astro source. They render to HTML and CSS and send no JavaScript, except the small scripts in the navbar menu and the enquiry form.
Terminal
pnpm add ../brandcloud/packs/brandcloud-astro-0.9.0.tgz ../brandcloud/packs/brandcloud-tokens-0.9.0.tgz ../brandcloud/packs/brandcloud-motion-0.9.0.tgz astrosrc/layouts/Layout.astro
---
import "@brandcloud/tokens/css";
import "@brandcloud/tokens/themes.css"; // every brand and mode, or one brand file
import "@brandcloud/motion/motion.css"; // optional: motion tokens and utilities
---
<html lang="en-GB" data-brand="harbour" data-theme="light" data-button-appearance="depth">
<body><slot /></body>
</html>src/pages/index.astro
---
import Layout from "../layouts/Layout.astro";
import Hero from "@brandcloud/astro/components/Hero.astro";
import Button from "@brandcloud/astro/components/Button.astro";
---
<Layout>
<Hero variant="editorial" copy={{ heading: "Your headline", primary: { label: "Book a visit", href: "/book/" } }} />
<Button href="/prices/" tone="ink">See prices</Button>
</Layout>- Import components one by one from
@brandcloud/astro/components/Name.astro, so only their CSS reaches the page. - Component styles sit in
@layer components. Keep your own element rules (h1,a) in@layer base, and declare the layer order once before any stylesheet:@layer tokens, theme, base, components, brand-motion, utilities; data-button-appearance="depth"on<html>makes the depth button the default. Without it buttons are solid.- Fonts are not bundled. Load them yourself (this site self-hosts Bricolage Grotesque and Hanken Grotesk from Fontsource) and keep their licence.
React and Next
The React primitives are built on Base UI, styled only with the tokens. Include the stylesheet once near the root.
Terminal
pnpm add ../brandcloud/packs/brandcloud-ui-0.9.0.tgz ../brandcloud/packs/brandcloud-tokens-0.9.0.tgz react react-dommain.tsx (Vite)
import "@brandcloud/tokens/css";
import "@brandcloud/tokens/themes.css";
import "@brandcloud/ui/styles.css";
import { Button } from "@brandcloud/ui/button";
export function Save() {
return <Button loading={false}>Save changes</Button>;
}app/layout.tsx (Next App Router)
import "@brandcloud/tokens/css";
import "@brandcloud/tokens/themes.css";
import "@brandcloud/ui/styles.css";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en-GB" data-brand="harbour" data-theme="light">
<body>{children}</body>
</html>
);
}- Interactive components (dialog, drawer, menu, popover, tooltip and the rest) carry
"use client"in the build, so you can import them from a Server Component page.Cardalso has areact-serverentry. - Import leaf paths such as
@brandcloud/ui/buttonto keep bundles small, or the root for everything. - For motion in React, wrap the app in
BrandMotionConfigfrom@brandcloud/motion/react. It follows the OS reduced-motion setting and<html data-motion="reduce">.
Tailwind v4
The Tailwind layer is @theme inline, so utilities read the tokens where they are used and re-theme with data-brand or data-theme on any element.
app.css
@import "tailwindcss";
@import "@brandcloud/tokens/css";
@import "@brandcloud/tokens/themes.css";
@import "@brandcloud/tokens/tailwind.css";
@import "@brandcloud/motion/tokens.css";
@import "@brandcloud/motion/tailwind.css";| Tokens | Utilities |
|---|---|
| Colour roles | bg-canvas, text-text-muted, border-border, bg-action-ink,bg-whatsapp |
| Shadows | shadow-action-depth, hover:shadow-action-depth-hover, shadow-popover |
| Type | font-display, font-body, text-display, text-h1, text-lead |
| Layout | py-section, h-action-md, max-w-content-max, rounded-control |
| Gradients | bg-action-depth, bg-level-sky to bg-level-obsidian |
| Motion | ease-brand-enter, duration-brand-fast, transition-spring-snappy,animate-brand-enter |
The shadcn bridge
Already using shadcn/ui? Import the bridge last and stock components take on the brand without edits.
app.css
@import "tailwindcss";
@import "@brandcloud/tokens/css";
@import "@brandcloud/tokens/themes.css";
@import "@brandcloud/tokens/tailwind.css";
@import "@brandcloud/tokens/shadcn.css"; /* last */--background becomes canvas, --primary becomes accent, --muted becomes surface-muted,--destructive becomes danger, --ring becomes focus and --radius becomes radius-control, along with the card, popover, chart and sidebar variables. They are re-declared on every [data-brand] and [data-theme] element, so nested brands work too.
With the bridge loaded, Tailwind's bg-accent follows shadcn's meaning (the hover surface). Use bg-primary for the brand colour.
Add your brand
Export the JSON from the brand builder, or make one from the command line in a clone of the repository:
Terminal
node packages/tokens/scripts/make-brand.mjs --name acme --label "Acme Roofing" \
--accent "#0f766e" --ink "#111827" --paper "#fbfaf7" \
--font-body "'Hanken Grotesk Variable', Arial, sans-serif" \
--font-display "'Fraunces Variable', Georgia, serif"
# or: --input brief.json (same keys), --dry-run, --report report.json, --appearance solid|depthIt prints a pass or fail line for every required contrast pair and refuses to write a brand that fails. More in Theming.