Theme appearance and component layout
WiseWig separates brand appearance from component layout. A theme can change the visual identity of every built-in and conforming custom component without changing page content, section order, or layout slots.
Ownership boundary
| Theme appearance owns | Component layout owns | Content owns |
|---|---|---|
| Semantic color roles | Element choice and semantic role | Headings and body copy |
| Font families | Grid and flex geometry | Images, video, and downloads |
| Type scale, weights, and line heights | Order, alignment, and placement | Links and calls to action |
| Control, card, and media shape | Responsive breakpoints | Cards, form values, and business details |
| Surface and action treatment | Approved layout variants | Schema-validated user choices |
A theme does not target Hero, CardGrid, or Contact with unrelated one-off values. Components request shared semantic roles such as display text, heading text, canvas, surface, muted surface, primary action, border, or inverse surface. The selected theme supplies the actual values.
Spacing is component-owned when it affects layout or content fit. Shape is appearance-owned because it changes visual treatment without moving or losing content. A future token should be placed by the same rule: if changing it can alter structure, order, placement, or migration compatibility, it belongs to layout; if it only changes how a known semantic role looks, it belongs to appearance.
Appearance contract
ThemeAppearance contains three required groups:
colors: canvas, surface, muted surface, text, muted text, accent, on-accent, border, inverse, and on-inverse roles;typography: heading/body families, display/heading/title/body/small sizes, tight/body line heights, and heading/strong/body weights;shape: control, card, and media radii.
The roles are required so a conforming component never has to guess a foreground color, invent a font size, or hard-code a brand value. Theme code is developer-owned and versioned with the site.
import {
themeAppearanceVariables,
type ThemeDefinition,
} from "@wise-wig/contracts";
const theme: ThemeDefinition = {
id: "agency-brand",
version: "1.0.0",
appearance: {
colors: {
canvas: "#ffffff",
surface: "#ffffff",
surfaceMuted: "#f4f4f5",
text: "#18181b",
textMuted: "#52525b",
accent: "#6d5dfc",
onAccent: "#ffffff",
border: "#d4d4d8",
inverse: "#18181b",
onInverse: "#ffffff",
},
typography: {
families: {
heading: "Georgia, serif",
body: "Inter, sans-serif",
},
sizes: {
display: "clamp(3rem, 7vw, 5rem)",
heading: "clamp(2.25rem, 5vw, 3.25rem)",
title: "1.25rem",
body: "1rem",
small: ".875rem",
},
lineHeights: { tight: "1.05", body: "1.6" },
weights: { heading: 700, strong: 650, body: 400 },
},
shape: {
control: ".5rem",
card: ".75rem",
media: "1rem",
},
},
layout: {
slots: [
{ id: "hero.primary", component: "hero", required: true },
],
},
};
const style = themeAppearanceVariables(theme.appearance);
Apply the returned CSS custom-property record to the Astro document shell. Plain CSS, CSS Modules, and Tailwind can all consume the same variables. Tailwind is a build-time convenience, not part of the runtime contract.
Component conformance
A component renderer:
- owns accessible semantic markup and the approved geometry for each layout variant;
- consumes only semantic appearance variables for public visual treatment;
- does not persist arbitrary class names, styles, or HTML in the content document;
- keeps editor chrome styles separate from site-theme styles;
- renders the same structure in published, preview, and edit modes.
For example, a hero may choose a two-column split and mark its h1 as display text. It must not choose Georgia, #30271f, or 84px. A card grid chooses its responsive columns and card placement, while the theme supplies card surface, border, radius, title size, and text colors.
Switching behavior
An appearance-only switch requires no content migration. The same typed document and stable slot IDs render against a different semantic token set and can preview immediately.
A layout switch may add, remove, or change slots and therefore goes through the migration report and explicit decision flow. Combining an appearance and layout release in one theme version is allowed, but layout compatibility is still evaluated independently from appearance.