Styling and formatting

Let your frontend own tokens, fonts, and color mode while using board-language formatting helpers.

Your frontend should own its design tokens, font loading, component styles, and light/dark-mode behavior. The SDK does not ship UI components or require Cavuno’s hosted-board theme. This is the same ownership model used by open-code systems such as shadcn: theme decisions live in the consuming application.

Use Cavuno’s formatting helpers for board-owned vocabulary, dates, locations, salaries, and custom fields. Use theme helpers only when you deliberately want to mirror an existing hosted board or smooth a migration away from it.

Own the visual system in your application

Define semantic variables in your global CSS or design-system package:

css
:root {
--brand: oklch(0.58 0.18 255);
--surface: oklch(1 0 0);
--text: oklch(0.2 0 0);
}
.dark {
--surface: oklch(0.16 0 0);
--text: oklch(0.96 0 0);
}

Load fonts through the framework’s preferred mechanism and let the application’s theme provider own color-mode state. That keeps the custom job board consistent with the rest of your product and avoids a remote board setting unexpectedly replacing application-wide design decisions.

Format a job card in the board language

ts
import {
cardLocationLabel,
formatPublishedRelativeDate,
formatSalaryRange,
uiCopy,
} from '@cavuno/board/format';
import type { PublicBoard, PublicJobCard } from '@cavuno/board';
export function presentJobCard(board: PublicBoard, job: PublicJobCard) {
const copy = uiCopy(board.language, board.labels);
return {
title: job.title,
location: cardLocationLabel(board.language, job),
published: formatPublishedRelativeDate(board.language, job.publishedAt),
salary: formatSalaryRange(
board.language,
job.salaryMin,
job.salaryMax,
job.salaryTimeframe,
job.salaryCurrency,
),
applyLabel: copy.apply.applyButtonText,
};
}

Formatting helpers require the board language so a non-English board does not silently format board-owned data in English. Omit nullable output rather than printing placeholders such as “Invalid date”.

Render custom fields from definitions

Jobs store custom-field values by definition key. Use context.customFields with resolveCustomFieldDisplay to resolve labels, option keys, and display order. Never render a stored select key as if it were the visitor-facing label.

Optional: mirror a hosted board

If you are migrating from Cavuno’s hosted frontend and intentionally want the custom application to start from the hosted theme, the compatibility helpers return safe CSS and font metadata:

ts
import {
boardThemeToCss,
googleFontsUrl,
themeMode,
} from '@cavuno/board/theme';
const context = await board.context();
const hostedTheme = {
css: boardThemeToCss(context.theme),
fontUrl: googleFontsUrl(context.theme),
mode: themeMode(context.theme),
};

Treat this as migration input. Copy the resulting decisions into your application’s token and font systems when ready. Do not build a permanent client effect that repeatedly overwrites your product’s theme from remote context unless multi-board theme mirroring is an explicit product requirement.

Verify styling and formatting

  1. Confirm the application looks correct when context.theme is null; hosted theme data is optional.
  2. Switch the application’s own light/dark setting and confirm it does not depend on a Cavuno request.
  3. Change the board language and verify dates, locations, salary units, and SDK interface copy update together.
  4. Render select custom fields and confirm visitors see configured labels rather than stored keys.
  5. If using compatibility helpers, test invalid colors, missing fonts, contrast, focus states, and the migration fallback.

Next, use Localization to keep requests, canonical slugs, document language, and formatting aligned.