Components Registry
Register and call UI utility functions using dot-notation paths.
Overview
Components are nested functions that return CSS classes, HTML strings, or any value. They're perfect for reusable UI utilities.
// Register
uizy.add({
button: {
primary: () => "px-4 py-2 bg-primary text-white rounded",
secondary: () => "px-4 py-2 bg-gray-200 rounded",
sized: (size) => `px-${size} py-${size / 2}`,
},
});
// Use
uizy.use("button.primary"); // "px-4 py-2 bg-primary text-white rounded"
uizy.use("button.sized", 6); // "px-6 py-3"
Registration
Via start()
uizy.start({
components: {
card: {
base: () => "rounded shadow p-4",
elevated: () => "rounded shadow-lg p-4",
},
text: {
heading: () => "text-2xl font-bold",
body: () => "text-base leading-relaxed",
},
},
});
Via uizy.add()
uizy.add({
modal: {
container: () => "fixed inset-0 flex items-center justify-center",
backdrop: () => "absolute inset-0 bg-black/50",
content: () => "relative bg-white rounded-lg shadow-xl p-6",
},
});
Calling Components
Basic Call
const classes = uizy.use("button.primary");
Multiple Components
Combine multiple components by passing an array of paths:
// All component classes are combined into a single string
uizy.use(["button.base", "button.primary"]);
// "px-4 py-2 rounded bg-primary text-white"
uizy.use(["button.base", "button.primary", "button.lg"]);
// "px-4 py-2 rounded bg-primary text-white text-lg px-6 py-3"
With Props
Pass configuration to components:
uizy.add({
spacing: {
pad: (props) => `p-${props.size}`,
margin: ({ x, y }) => `mx-${x} my-${y}`,
},
});
uizy.use("spacing.pad", { size: 4 }); // "p-4"
uizy.use("spacing.margin", { x: 2, y: 4 }); // "mx-2 my-4"
// Props are shared across all components when using arrays
uizy.use(["button.base", "button.sized"], { size: "lg" });
Return Types
Components can return three different formats:
String (default)
button: {
primary: () => "px-4 py-2 bg-primary text-white rounded",
}
Array
button: {
primary: () => ["px-4", "py-2", "bg-primary", "text-white", "rounded"],
}
Object (conditional classes)
Return an object where keys are class strings and values are booleans. Only keys with truthy values are included:
button: {
sized: (props) => ({
"px-2 py-1 text-sm": props.size === "sm",
"px-4 py-2": props.size === "md",
"px-6 py-3 text-lg": props.size === "lg",
"bg-primary text-white": props.variant === "primary",
"bg-gray-200 text-gray-800": props.variant === "secondary",
}),
}
// Usage
uizy.use("button.sized", { size: "lg", variant: "primary" });
// "px-6 py-3 text-lg bg-primary text-white"
API Reference
uizy.use(path, props?)
Call component(s) by path. Returns combined CSS classes as a string.
| Parameter | Type | Description |
|---|---|---|
path | string | string[] | Single path or array of paths |
props | unknown | Props passed to all components |
| Returns | string | Combined CSS classes |
// Single component
uizy.use("button.primary");
// Multiple components
uizy.use(["button.base", "button.primary"]);
// With props (shared across all components)
uizy.use(["button.base", "button.sized"], { size: "lg" });
uizy.add(items)
Register components. Merges with existing components.
uizy.add({
newComponent: () => "classes",
});
uizy.components.has(path)
Check if a component exists.
uizy.components.has("button.primary"); // true
uizy.components.has("nonexistent"); // false
uizy.components.paths()
Get all registered component paths.
uizy.components.paths();
// ["button.primary", "button.secondary", "card.base", ...]
uizy.components.clear()
Remove all registered components.
uizy.components.clear();
uizy.components.getTree()
Get the raw component tree (readonly).
const tree = uizy.components.getTree();
Using with <uizy-box>
The <uizy-box> web component automatically applies component classes:
<uizy-box use="button.primary">Click me</uizy-box>
<!-- Renders with class="px-4 py-2 bg-primary text-white rounded" -->
<uizy-box use="card.elevated">
<h2>Card Title</h2>
<p>Card content</p>
</uizy-box>
Multiple Components in HTML
Use space-separated component names:
<uizy-box use="button.base button.primary button.lg">
Large Primary Button
</uizy-box>
Props in HTML
Pass props using use:props attribute:
<uizy-box use="button.sized" use:props='{"size": "lg", "variant": "primary"}'>
Large Primary Button
</uizy-box>
<!-- Props are passed to all components -->
<uizy-box use="button.base button.sized" use:props='{"size": "lg"}'>
Large Button
</uizy-box>
Examples
Design System
uizy.start({
components: {
// Typography
text: {
h1: () => "text-4xl font-bold tracking-tight",
h2: () => "text-3xl font-semibold",
h3: () => "text-2xl font-medium",
body: () => "text-base leading-relaxed",
small: () => "text-sm text-gray-600",
},
// Buttons
btn: {
base: () =>
"inline-flex items-center justify-center rounded font-medium transition",
primary: () => "bg-primary text-white hover:bg-primary-dark",
secondary: () => "bg-gray-100 text-gray-900 hover:bg-gray-200",
ghost: () => "bg-transparent hover:bg-gray-100",
sm: () => "px-3 py-1.5 text-sm",
md: () => "px-4 py-2 text-base",
lg: () => "px-6 py-3 text-lg",
},
// Cards
card: {
container: () => "bg-white rounded-lg border border-gray-200",
header: () => "px-4 py-3 border-b border-gray-200",
body: () => "px-4 py-4",
footer: () => "px-4 py-3 border-t border-gray-200 bg-gray-50",
},
},
});
Dynamic Classes
uizy.add({
grid: {
cols: (n) => `grid grid-cols-${n} gap-4`,
responsive: ({ sm, md, lg }) =>
`grid grid-cols-${sm} md:grid-cols-${md} lg:grid-cols-${lg} gap-4`,
},
flex: {
row: () => "flex flex-row",
col: () => "flex flex-col",
center: () => "flex items-center justify-center",
between: () => "flex items-center justify-between",
gap: (n) => `flex gap-${n}`,
},
});
// Usage
uizy.use("grid.cols", 3); // "grid grid-cols-3 gap-4"
uizy.use("grid.responsive", { sm: 1, md: 2, lg: 4 }); // "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"
Conditional Classes
uizy.add({
input: {
field: ({ error, disabled }) =>
[
"w-full px-3 py-2 border rounded",
error
? "border-red-500 focus:ring-red-500"
: "border-gray-300 focus:ring-blue-500",
disabled ? "bg-gray-100 cursor-not-allowed" : "bg-white",
].join(" "),
},
});
uizy.use("input.field", { error: true, disabled: false });
// "w-full px-3 py-2 border rounded border-red-500 focus:ring-red-500 bg-white"