DOCUMENTATION Docs Powered by Fuzor Docs

UI brands

A brand gives Fuzor Web Components and their parts another tag prefix. A product can write <acme-select> and <acme-select-item> with the same behavior as <fuzor-select> and <fuzor-select-item>. The canonical tags continue to work in the same document. CSS and styling drivers still control the presentation.

This page describes the current repository implementation, including the compiler option added after the runtime API. The package version alone does not establish which changes have been published to npm.

Define a brand at runtime

In browser code:

import { defineBrand } from "fuzor/ui/client";
import { registerSelect } from "fuzor/ui/components/select";

defineBrand("acme");
registerSelect();
<acme-select name="plan" value="basic">
  <acme-select-trigger>
    <acme-select-value placeholder="Choose a plan"></acme-select-value>
  </acme-select-trigger>
  <acme-select-content>
    <acme-select-item value="basic">Basic</acme-select-item>
    <acme-select-item value="plus">Plus</acme-select-item>
  </acme-select-content>
</acme-select>

In a browser build, defineBrand is also exported by fuzor/ui; fuzor/ui/client selects the browser entry explicitly. Prefixes contain lowercase letters and digits, starting with a letter, such as acme or zv.

Registration order is flexible:

  • A brand aliases components that are already registered and components registered later.
  • Existing matching elements in the document upgrade when their alias is defined.
  • Defining the same prefix again is harmless, and several prefixes can coexist.
  • An alias uses its own subclass because the Custom Elements registry requires a constructor per name.
  • A name the page already defined is skipped. Its constructor and behavior stay owned by that page, and the other aliases still register. This holds whether the canonical component or the page-owned name was registered first.

Brands are document-wide. Component registration remains explicit: call individual register… functions, defineAll(), or use the existing deferred UI runtime.

Let the compiler emit the call

Configure the Vite plugin:

import { defineConfig } from "vite";
import { fuzorPlugin } from "fuzor/vite";

export default defineConfig({
  plugins: [fuzorPlugin({ ui: { brand: "acme" } })]
});

The generated browser entry calls defineBrand("acme") before application activation in SPA, MPA and inline builds. Register the components separately. The option leaves authored HTML unchanged and does not select a driver or bundle a product stylesheet. A standalone runtime distributed without a Fuzor client entry can call defineBrand directly.

This site's example uses ui: { brand: "demo" }. The ordinary docs controls keep their canonical tags, while the example below uses <demo-select>. Docs mode supplies deferred registration through the unchanged data-fuzor-ui marker.

Example plan

Choose a plan, then reset the form to restore Basic. The control is a demo-select.

Contracts that keep their names

SurfaceUnder every brand
Eventsui:value-change, ui:open-change and their detail shapes
Attributesname, value, disabled, ARIA attributes, data-part, data-fuzor-ui and other existing attributes
CSS custom propertiesExisting --fuzor-* names, such as --fuzor-dialog-z-index
ImportsThe existing fuzor/ui/* package entry points

Only component and part tag names gain aliases. Branded roots find their parts across the registered prefixes, and parts created by a component, such as a select positioner, use their owning root's prefix.

Styles per prefix

Fuzor copies its default structural styles for each registered prefix when styles are injected. This covers layout, hidden parts and overlay structure while keeping custom properties and data attributes unchanged.

Your product's CSS still supplies its own selectors and theme:

acme-select-trigger {
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 8px 12px;
}

acme-select-positioner { z-index: 1000; }

The brand mechanism does not rewrite an application's stylesheet. Use branded selectors, unchanged part/state attributes or a styling driver for your visual rules. Drivers continue to supply classes and attributes; their corresponding CSS is a separate application dependency.

Form-associated selects

A branded select retains the canonical select's form contract. With ElementInternals, the custom element itself submits its value under name; a multiple select submits each selected value separately. It keeps no hidden native select in that path. It supports external form="id" associations, labels, required/custom validation, native form reset, browser state restoration and disabled fieldsets.

Use setValue([...]) for a multiple selection. Structured form state preserves commas inside individual values. checkValidity(), reportValidity() and setCustomValidity() use the same validation contract, anchored to the trigger. DOMs without ElementInternals use the hidden-select path. Use a native <select> when form submission must work before JavaScript enhancement. See the select reference for the full control API.

Ship a runtime to independently authored pages

A host product can bundle a curated set of components with defineBrand("zv") and distribute that module with its stylesheet. Page authors then write branded HTML without importing Fuzor or running a build themselves. Avoid registering tag names already owned by another host library; brand aliases skip pre-owned names.

Zelavis uses this arrangement:

  1. Its dashboard frontend builds a static zv runtime and stylesheet. It omits Button, Badge, Card and Stack because the existing service-page element library owns those names.
  2. The Platform injects the runtime and stylesheet into HTML service pages. Its runtime/service-ui.js and runtime/service-ui.css assets are public, CORS-readable static code/styles with no installation data.
  3. Extension pages run in opaque sandboxed frames without allow-same-origin. Their own files use a signed capability limited to one service bundle and optional Project; API requests use a scoped broker. A page can opt out of injection with <meta name="zelavis-service-ui" content="none">.

Those delivery and permission boundaries belong to the host. Fuzor supplies the component aliases and behavior; branding itself grants no authority to a page.

Built with Fuzor Back to top ↑
On this page Back to top ↑