Boundary Boundary alpha
Docs Why Boundary Libraries Blog Home GitHub Get Started →

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

:base

Public pages, authentication screens, marketing pages, error pages

Boundary tokens, Pico, app.css, Alpine, HTMX

:pilot

User / profile / audit pilot pages — authenticated areas with forms and tables

:base + pilot forms.js, keyboard navigation, theme.js

:admin-pilot

Admin CRUD pages generated by boundary-admin

:pilot + daisy-admin.css (Tailwind output), admin.css

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 tokensboundary-tokens.css, tokens-openprops.css

  • Shared CSSapp.css, admin.css, pico.min.css, vendor/open-props/*

  • Tailwind sourceresources/tailwind/admin-pilot.css

  • Compiled Tailwind outputresources/public/css/daisy-admin.css

  • Shared JStheme.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:

  1. Use shared layout entry points (layout/page-layout, layout/pilot-page-layout, layout/admin-pilot-page-layout) — not custom HTML wrappers.

  2. Pick one bundle key based on page type: :base, :pilot, or :admin-pilot.

  3. Do not define module-local :css [...] stacks in feature namespaces; let layout resolve bundles via boundary.ui-style.

  4. Render forms with shared form classes and token variables only — no hardcoded per-page colors.

  5. Render tables with shared table classes so sort, hover, row states, and spacing stay consistent.

  6. Use shared badge classes (including fixed-width variants) for role / status / action / result labels.

  7. 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 changesdaisy-admin.css is generated, not hand-edited. Edits disappear on the next npm 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.