Theming
Theming is server-driven (htmx + Alpine in production). The framework only owns the CSS contract — two attributes on <html> (or any container):
data-bf-theme—light,dark, orautodata-bf-primary—default,mint,crimson,orchid,ember, orcustom
Built-in primaries
Each preset is its own stylesheet — load only the one in use. The default is bundled into bf.core.css; loading a preset sheet (eg bf.theme.mint.css) declares [data-bf-primary="mint"], then the host page sets the attribute.
Note: these tiles only switch their own subtree because data-bf-primary is set on the wrapper. The shipped preset stylesheets must be loaded via <link> for the variables to apply at runtime — data-bf-primary="default" always works since it ships in core.
Custom (host page picks any color)
Load bf.theme.custom.css once, then bind --bf-custom-primary from your form. The 11-stop ramp is derived in CSS — no JS needed.
<html data-bf-primary="custom" style="--bf-custom-primary: #ec4899">
Light / dark
Rounding
The whole framework's radii multiply by --bf-radius-scale. Pick a named preset (square = 0, sharp = 0.5, default = 1, soft = 1.5, round = 2.25) or set the scale directly.
Custom value:
Switching presets affects everything that uses a radius token — buttons, inputs, cards, modals, badges, sidebar items. Try a preset, then revisit the other example pages and watch the framework re-shape itself.
Server-rendered switcher (htmx + Alpine)
<!-- 1. attribute on <html> is rendered by the server from the user's settings -->
<html lang="en" data-bf-theme="dark" data-bf-primary="mint">
<!-- 2. user picks a new color in a settings form; the form posts to /me/theme -->
<form
hx-post="/me/theme"
hx-trigger="change"
hx-swap="none"
x-data="{ primary: 'mint' }"
>
<input type="radio" name="primary" value="default" x-model="primary"> Default
<input type="radio" name="primary" value="mint" x-model="primary"> Mint
<input type="radio" name="primary" value="crimson" x-model="primary"> Crimson
</form>
<!-- 3. server response sets the attribute via hx-swap-oob or returns
an updated <html> root via boost -->