Utilities
Helper functions for styling, responsive design, form layout, and component composition.
Utilities
Utility functions help you build components and layouts more efficiently. These are foundational tools for styling, responsiveness, form structure, and polymorphic component patterns.
Essential utilities
cn — Merge and resolve Tailwind classes
Use cn to merge class names while intelligently resolving Tailwind conflicts. This is your go-to for combining base styles with conditional or override classes.
import { cn } from "@loke/design-system/cn";
// Merge classes with conflict resolution
const buttonClasses = cn("px-4 py-2 rounded", "px-6"); // Result: "py-2 rounded px-6"
// Conditional classes
function Card({ variant, className }) {
return (
<div
className={cn(
"rounded border p-4",
variant === "elevated" && "shadow-lg",
className
)}
>
{/* content */}
</div>
);
}
// Override parent styles
<button className={cn(buttonVariants({ size: "default" }), "bg-purple-600")}>
Custom Button
</button>When to use: Whenever you need to merge multiple class strings or conditionally add classes without Tailwind conflicts appearing.
responsive — Breakpoint-aware variant generation
Use responsive to generate Tailwind classes for multiple breakpoints. Create size, color, and dimension variants that change based on screen size.
import { cva } from "class-variance-authority";
import {
createResponsiveComponent,
getSizeVariants,
} from "@loke/design-system/responsive";
// Define responsive component with size variants
const boxVariants = cva("box", {
variants: {
padding: getSizeVariants("p"), // p-0, p-1, ..., p-32, small, medium, large
},
});
const { createResponsive } = createResponsiveComponent(boxVariants);
// Use responsive array: [default, sm:, md:, lg:]
const classes = createResponsive({
padding: [2, 4, 6, 8], // p-2 at default, sm:p-4, md:p-6, lg:p-8
});
// In a component
function ResponsiveGrid() {
const gridClasses = createResponsive({
cols: [1, 2, 3, 4], // 1 column mobile → 4 columns desktop
gap: [2, 4, 6], // smaller gaps on mobile
});
return <div className={gridClasses}>{/* items */}</div>;
}When to use: Building layouts that adapt to screen sizes, creating responsive spacing or sizing without manual breakpoint prefixes.
Supporting utilities
Use form-classes to structure accessible form layouts with react-hook-form. It exports predefined CSS class names for form items, labels, descriptions, and error messages.
import { formClasses } from "@loke/design-system/form";
function MyForm() {
return (
<form>
<div className={formClasses.formItem}>
<label className={formClasses.formLabel}>Name</label>
<input type="text" />
<p className={formClasses.formDescription}>
Your full name as it appears on documents.
</p>
</div>
</form>
);
}Use slot to build polymorphic components with asChild composition. Slot merges parent props onto child elements, enabling flexible rendering without extra DOM nodes.
import { Slot } from "@loke/design-system/slot";
// Button can render as button, link, or custom component
<Button asChild>
<a href="/docs">Go to Docs</a>
</Button>
// Props and classes merge onto the child
<Button asChild className="text-lg">
<a href="/docs" className="underline">
Docs
</a>
</Button>
// Result: <a href="/docs" class="button-classes text-lg underline">Docs</a>Components
| Utility | Purpose | Common use case |
|---|---|---|
| cn | Merge and deduplicate Tailwind classes with conflict resolution | Conditional styling, overrides, combining base + variant styles |
| responsive | Generate typed responsive variants across breakpoints (sm, md, lg) | Responsive spacing, sizing, grids that adapt to screen size |
| form-classes | CSS class names for form field layout structure | Form layouts with react-hook-form |
| slot | Merge props onto child elements for polymorphic rendering | asChild pattern, flexible component APIs |
Quick decision tree
- Merging class strings without Tailwind conflicts? → cn
- Different spacing/sizing at different breakpoints? → responsive
- Building form field layouts with react-hook-form? → form-classes
- Rendering Button as a link or custom component? → slot with asChild