Visual Customization
Customize logos, colors, typography, layout, icons, and components.
Global Configuration#
Edit brief/config/visuals.ts to customize Brief's appearance.
Branding#
logo.lightRequiredstring- Logo shown in light mode. Required when
logois set; otherwise Brief displays the site name. Put the image inpublic/and use its public path.
logo.darkRequiredstring- Logo shown in dark mode. Required when
logois set; can use the same image aslogo.light.
logo.hrefDefaultundefinedstring- Link destination when readers click the logo. If omitted, the logo links to
/.
Colors#
Built-in palettes include blue, cyan, violet, zinc, and slate. Brief selects shades for light and dark mode automatically.
tokens.colors.accentDefault"blue"string- Palette for links, active controls, and highlights.
tokens.colors.baseDefault"zinc"string- Palette for neutral backgrounds and borders.
tokens.colors.textDefaulttokens.colors.basestring- Palette for text and neutral icons. Defaults to
tokens.colors.base.
tokens.colors.positiveDefault"green"string- Palette for positive states.
tokens.colors.negativeDefault"red"string- Palette for negative states.
colors.<name>DefaultBUILT_IN_COLOR_SCALES[name]ColorScale- Custom palette, referenced by name in tokens and content. Existing names use
BUILT_IN_COLOR_SCALESfrom@brief/ui/palette; new names default toundefined. Supply CSS colors for shades50,100through900,925, and950.
Background#
tokens.canvas.lightDefault"var(--color-base-50)"string- Page background CSS color in light mode. Supply both canvas colors when overriding.
tokens.canvas.darkDefault"var(--color-base-950)"string- Page background CSS color in dark mode.
backgroundDefaultundefinedComponent- React component rendered behind the page content. Keep it decorative, without interactive controls.
Typography#
Import bundled fonts from @brief/ui/fonts.
tokens.typography.<role>DefaultundefinedTextStyle- Fonts, sizes, weights, and spacing for
body,h1throughh4,code,ui,uiCompact,uiSmall,button, orshortcut. Each role accepts settings such asfamily,size, andweight. Omitted overrides use Brief's role defaults: Inter for body and interface text, Roboto Mono for code. Headings inherit the body font.
Borders and Shadows#
tokens.radiusDefault"medium""none" | "small" | "medium" | "large"- Corner rounding.
tokens.borderWidthDefault"medium""none" | "thin" | "medium" | "thick"- Border thickness.
tokens.shadowDefault"small""none" | "small" | "medium" | "large"- Shadow depth.
Navigation#
layout.sidebar.placementDefault"content""content" | "page"- Place the sidebar alongside the content or at the page edge.
layout.sidebar.variantDefault"tracker-line""simple" | "tracker-line" | "tracker-dot" | "tracker-background" | "threads"- Sidebar item decoration and active-page indicator.
layout.toc.variantDefault"simple""simple" | "tracker-line" | "tracker-dot" | "tracker-background" | "threads"- Table-of-contents item decoration and active-section indicator.
layout.topBar.desktopDefault"gradient-blur""gradient-blur" | "opaque" | "transparent-blur" | "none"- Desktop top bar appearance.
nonemoves its controls into the sidebar.
layout.topBar.mobileDefault"gradient-blur""gradient-blur" | "opaque" | "transparent-blur"- Mobile top bar appearance.
Component-Specific Styles#
components.button.variantDefault"outline""outline" | "soft"- Default button appearance.
components.callout.variantDefault"quote""quote" | "card" | "quote-card"- Default callout presentation.
components.divider.variantDefault"solid""solid" | "gradient" | "dotted"Divider appearance.
Solid and gradient dividers use border widths of 1px, 1px, 1.5px, and 2px for
tokens.borderWidthvalues ofnone,thin,medium, andthick, respectively. Browsers snap border widths to device pixels. Dotted dividers use a fixed 2px pattern.
components.overlay.backdropDefault"blurred""blurred" | "opaque"- Backdrop behind overlays.
components.card.frameDefault"none""none" | "debossed" | "embossed"- Frame around cards on desktop.
components.image.frameDefault"none""none" | "debossed" | "embossed"- Frame around images on desktop.
components.code.frameDefault"none""none" | "debossed" | "embossed"- Frame around code blocks and terminals on desktop.
Icons#
There are two sets of icons in the application:
- Interface icons are used for icons baked into Brief's layout like the theme toggle or the generic copy icon across all components.
- Content icons can be used by in-page components like Icon, Badge, and Callout.
Interface Icons#
Customize interfaceIcons to set the interface icons. Make your own bundle of icons or choose from one of the default bundles.
Content Icons#
Content icons are SVG components that forward their SVG props and use currentColor.
Register content icons in the icons map in brief/config/visuals.ts. Each icon's key can then be referenced and used in authors' pages.
You can then start using it in certain components across all pages.
Individual Page Customization#
Pages have individual settings that can be customized via their frontmatter.
content_widthDefault"medium""small" | "medium" | "large"- Width of the page content.
tocDefaulttrueboolean- Set to
falseto hide the table of contents. Useful for pages with wide custom components.
Custom Components#
For a rendered component with authored attributes, use these registration fields:
componentRequiredComponent- React component renderer that receives the validated attributes as props.
schemaRequiredZodSchema- Validates authored attributes and supplies defaults.
searchDefaultundefined(input: ComponentBuildInput<Props>) => ComponentSearchResult<Record<never, never>>- Supplies text generated by the component for use in search. Return
{ text }for a label derived from its attributes, orfalseto exclude the component and its children from search entirely.
markdownDefaultundefined(input: ComponentBuildInput<Props>, children: readonly Node[]) => readonly Node[]- Converts the component to portable Markdown nodes for agent-facing
.mdpages.childrencontains its already-converted child nodes.
You can then start using the registered component: