ui-style
The central app-wide styling contract for Boundary. boundary-ui-style
owns the shared CSS and JavaScript bundles that every module — user-facing
pages, pilot pages, and the auto-generated admin UI — consumes. Feature modules
do not hardcode CSS file lists; they ask for a named bundle and layout
namespaces handle the rest.
The result: forms, tables, and badges look identical across the framework, and theme changes propagate through design tokens instead of per-component overrides.
Bundles
Three curated bundles cover every page type in a Boundary application:
| Bundle key | Use for | Included |
|---|---|---|
|
Public pages, authentication screens, marketing pages, error pages |
Boundary tokens, Pico, app.css, Alpine, HTMX |
|
User / profile / audit pilot pages — authenticated areas with forms and tables |
|
|
Admin CRUD pages generated by |
|
API — boundary.ui-style
Each bundle exposes a CSS list, a JS list, and a combined accessor:
boundary.ui-style/base-css
boundary.ui-style/pilot-css
boundary.ui-style/admin-pilot-css
boundary.ui-style/base-js
boundary.ui-style/pilot-js
boundary.ui-style/admin-pilot-js
(boundary.ui-style/bundle :base) ; => CSS list for :base
(boundary.ui-style/js-bundle :admin-pilot) ; => JS list for :admin-pilot
Layout namespaces call these to resolve asset lists at render time. Feature namespaces never do.
Usage
Pick a layout entry point in boundary.shared.ui.core.layout and the
right bundle loads automatically:
(ns my.module.core.ui
(:require [boundary.shared.ui.core.layout :as layout]))
(defn page [opts]
(layout/pilot-page-layout
"My Page"
[:div "Content"]
opts))
The three layout entry points map one-to-one to the bundles:
-
layout/page-layout→:base -
layout/pilot-page-layout→:pilot -
layout/admin-pilot-page-layout→:admin-pilot
Assets
All assets live under libs/ui-style/resources/public/:
-
Design tokens —
boundary-tokens.css,tokens-openprops.css -
Shared CSS —
app.css,admin.css,pico.min.css,vendor/open-props/* -
Tailwind source —
resources/tailwind/admin-pilot.css -
Compiled Tailwind output —
resources/public/css/daisy-admin.css -
Shared JS —
theme.js,alpine.min.js,htmx.min.js,forms.js,keyboard.js
Theming via tokens
Theme changes happen in token files, never in component CSS. Override CSS
custom properties in boundary-tokens.css or tokens-openprops.css and
every shared component picks them up — forms, tables, badges, admin UI.
One-off component colors are a violation and will drift out of sync.
Build
The Tailwind admin bundle is compiled from the monorepo root:
npm run build:css:admin
This reads resources/tailwind/admin-pilot.css and writes
resources/public/css/daisy-admin.css, which :admin-pilot serves.
Module migration checklist
When onboarding a new module or converting an existing module UI:
-
Use shared layout entry points (
layout/page-layout,layout/pilot-page-layout,layout/admin-pilot-page-layout) — not custom HTML wrappers. -
Pick one bundle key based on page type:
:base,:pilot, or:admin-pilot. -
Do not define module-local
:css [...]stacks in feature namespaces; let layout resolve bundles viaboundary.ui-style. -
Render forms with shared form classes and token variables only — no hardcoded per-page colors.
-
Render tables with shared table classes so sort, hover, row states, and spacing stay consistent.
-
Use shared badge classes (including fixed-width variants) for role / status / action / result labels.
-
If theme adjustments are needed, edit token files — not component one-offs.
Gotchas
-
No ad-hoc CSS lists in feature namespaces — if you find yourself writing
:css ["foo.css" "bar.css"]in a module, stop. Add what you need to a shared bundle or pick a different bundle key. -
Tokens, not component colors — hardcoded hex codes in component CSS break theming. Always go through a CSS custom property.
-
Admin bundle must be rebuilt on Tailwind source changes —
daisy-admin.cssis generated, not hand-edited. Edits disappear on the nextnpm run build:css:admin. -
Bundle choice is a layout decision, not a feature decision — the layout namespace selects the bundle; modules just pick the layout.
Testing
clojure -M:test:db/h2 :ui-style
Tests verify that bundle keys resolve to the expected asset lists and that the public API stays stable — modules rely on these names.