Writing a Bridge

Copy Markdown

A bridge is a plain CSS file that maps your host application's design-system tokens onto Aurora UIX's --auix-* variables. The library ships one bridge for daisyUI (auix-bridge-daisyui.css); this guide explains how to write one for any other design system.

What a bridge does

Aurora UIX components are styled exclusively via --auix-* custom properties defined in auix-variables.css. A bridge overrides a subset of those properties at :root level, pointing them at equivalent tokens from the host framework. When the host's theme changes — by switching a daisyUI theme, toggling dark mode, or updating a Tailwind @theme value — the --auix-* vars resolve to the new values automatically, and every Aurora UIX component follows.

/* Minimal bridge structure */
@layer auix.bridge {
  :root, :host {
    --auix-color-bg-default: var(--my-framework-background);
    --auix-color-text-primary: var(--my-framework-on-background);
    /* … */
  }
}

When you need one

The default auix-bridge-daisyui.css covers Phoenix apps using Tailwind v4 + daisyUI. Write a custom bridge if you use:

  • A different UI library (Shoelace, Material, Radix)
  • A hand-crafted design token set (e.g., --color-brand-* from your style guide)
  • Bootstrap CSS variables
  • Any system that exposes theme values as CSS custom properties

Finding the right variables

Aurora UIX side — open assets/css/auix-variables.css (generated by mix auix.gen.stylesheet). Every --auix-* property declared there is a candidate for bridging. Properties in --auix-color-* categories are the most impactful; dimension variables (--auix-border-radius-*, --auix-border-width-*) help align shape and density.

Host framework side — inspect your app's CSS in the browser DevTools or read the framework's theming docs to find the token names it exposes at :root.

Example: custom design token set

Suppose your design system defines these tokens:

:root {
  --ds-surface: #ffffff;
  --ds-on-surface: #1a1a1a;
  --ds-primary: #0056d2;
  --ds-on-primary: #ffffff;
  --ds-danger: #cc0000;
  --ds-radius-sm: 4px;
  --ds-radius-md: 8px;
}

A bridge mapping the most visible --auix-* variables:

/* my-bridge.css
   Import AFTER auix-variables.css and BEFORE auix-rules.css. */

@layer auix.bridge {
  :root, :host {
    --auix-color-bg-default:     var(--ds-surface);
    --auix-color-text-primary:   var(--ds-on-surface);
    --auix-color-text-secondary: var(--ds-on-surface);
    --auix-color-text-label:     var(--ds-on-surface);
    --auix-color-text-on-accent: var(--ds-on-primary);

    --auix-color-border-focus:   var(--ds-primary);
    --auix-color-focus-ring:     var(--ds-primary);

    --auix-color-error:          var(--ds-danger);
    --auix-color-error-text:     var(--ds-danger);
    --auix-color-error-ring:     var(--ds-danger);

    --auix-border-radius-default: var(--ds-radius-md);
    --auix-border-radius-small:   var(--ds-radius-sm);
  }
}

You don't have to bridge every variable. Anything left unmapped falls back to Aurora UIX's own defaults from auix-variables.css.

Import order

Place the bridge between the two Aurora UIX imports in app.css:

@import "auix-variables.css";   /* Aurora UIX defaults — must come first */
@import "my-bridge.css";        /* your overrides */
:root { /* any extra one-off tweaks */ }
@import "auix-rules.css";       /* component rules — must come last */

No mix task is needed. Drop the file anywhere that your bundler (esbuild) can resolve it — assets/css/ is the conventional location.

Tips

  • Always wrap in @layer auix.bridge { … }. Aurora UIX uses CSS cascade layers (auix.variables → auix.bridge → auix.rules). Without the layer wrapper, the bridge's plain :root selector (specificity 0,1,0) loses to the themes' [data-theme-name="…"] selectors (specificity 0,2,0), so your overrides are silently ignored. Anything written outside all layers (in your own app.css) still wins over everything, so host one-off tweaks work as expected.
  • Bridge only what differs. Fewer overrides mean less to maintain when either side updates its token names.
  • Use var(…, fallback). If a host token might not always be defined, provide a sensible fallback: var(--ds-radius-md, 0.5rem).
  • Check dark mode. If your design system uses attribute or class selectors for dark mode (e.g., [data-theme="dark"], .dark), scope your dark overrides the same way your design system does inside the @layer auix.bridge block.
  • Keep the file in version control. The bridge is part of your application's styling, not a generated artefact.