A utility CSS library designed for simplicity, zero tooling, and easy extension.
- No build step, no CLI, no config files
- Driven by CSS variables — retheme by overriding tokens
- Consistent variant naming:
.utility-hover,.utility-focus,.utility-active,.utility-md - Extend with a single CSS file
Add two <link> tags. That's it.
<link rel="stylesheet" href="unc.css">
<link rel="stylesheet" href="unc-extend.css">Load unc-extend.css after unc.css so your overrides take precedence.
All tokens are CSS custom properties defined in :root. Override any of them in unc-extend.css.
Semantic color tokens with four built-in states each.
--color-primary: #3b82f6;
--color-primary-hover: #2563eb;
--color-primary-focus: #1d4ed8;
--color-primary-active: #1e40af;
--color-secondary: #8b5cf6;
--color-secondary-hover: #7c3aed;
--color-secondary-focus: #6d28d9;
--color-secondary-active: #5b21b6;
--color-muted: #6b7280;
--color-surface: #f9fafb;
--color-background: #ffffff;
--color-text: #111827;
--color-border: #e5e7eb;
--color-success: #22c55e;
--color-danger: #ef4444;
--color-warning: #eab308;
--color-white: #ffffff;
--color-black: #000000;Each color (except white/black) has -hover, -focus, and -active variants.
A 0–10 scale used across margin, padding, and gap utilities.
--space-0: 0;
--space-1: 0.25rem; /* 4px */
--space-2: 0.5rem; /* 8px */
--space-3: 0.75rem; /* 12px */
--space-4: 1rem; /* 16px */
--space-5: 1.25rem; /* 20px */
--space-6: 1.5rem; /* 24px */
--space-7: 1.75rem; /* 28px */
--space-8: 2rem; /* 32px */
--space-9: 2.25rem; /* 36px */
--space-10: 2.5rem; /* 40px */--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 1.875rem;
--text-4xl: 2.25rem;
--text-5xl: 3rem;
--text-6xl: 3.75rem;
--text-7xl: 4.5rem;--font-normal: 400;
--font-medium: 500;
--font-semibold: 600;
--font-bold: 700;
--font-black: 900;--radius-sm: 0.125rem;
--radius-md: 0.375rem;
--radius-lg: 0.5rem;
--radius-full: 9999px;--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);--transition-fast: 150ms ease;
--transition-base: 200ms ease;
--transition-slow: 300ms ease;<div class="block">...</div>
<div class="inline-block">...</div>
<div class="inline">...</div>
<div class="flex">...</div>
<div class="inline-flex">...</div>
<div class="grid">...</div>
<div class="hidden">...</div><div class="relative">
<div class="absolute top-0 right-0">pinned</div>
</div>
<div class="fixed">...</div>
<div class="sticky">...</div>Inset helpers: .inset-0 .top-0 .right-0 .bottom-0 .left-0
<div class="overflow-hidden">...</div>
<div class="overflow-auto">...</div>
<div class="overflow-x-auto">...</div>
<div class="overflow-y-auto">...</div><!-- Direction -->
<div class="flex flex-row gap-4">...</div>
<div class="flex flex-col gap-2">...</div>
<!-- Justify content -->
<div class="flex justify-start">...</div>
<div class="flex justify-center">...</div>
<div class="flex justify-end">...</div>
<div class="flex justify-between">...</div>
<div class="flex justify-around">...</div>
<div class="flex justify-evenly">...</div>
<!-- Align items -->
<div class="flex items-start">...</div>
<div class="flex items-center">...</div>
<div class="flex items-end">...</div>
<div class="flex items-stretch">...</div>
<!-- Grow & shrink -->
<div class="flex">
<div class="flex-none">fixed</div>
<div class="flex-1">grows to fill</div>
</div>
<!-- Wrap -->
<div class="flex flex-wrap">...</div><div class="grid grid-cols-2 gap-4">...</div>
<div class="grid grid-cols-3 gap-4">...</div>
<div class="grid grid-cols-4 gap-4">...</div>
<!-- Column spanning -->
<div class="grid grid-cols-4 gap-4">
<div class="col-span-2">spans 2</div>
<div class="col-span-full">full width</div>
</div><div class="flex gap-2">...</div>
<div class="flex gap-4">...</div>
<div class="grid grid-cols-3 gap-6">...</div>
<div class="grid grid-cols-2 gap-x-4 gap-y-2">...</div>Values: gap-0 through gap-10, gap-x-*, gap-y-*
<div class="p-4">all sides</div>
<div class="px-6 py-3">horizontal + vertical</div>
<div class="pt-4 pb-2 pl-4 pr-4">individual sides</div>Values: p-0 through p-10, px-*, py-*, pt-*, pr-*, pb-*, pl-*
<div class="mx-auto max-w-md">centered</div>
<div class="mt-4 mb-8">vertical margin</div>
<div class="ml-auto">push right</div>Values: m-0 through m-10, mx-*, my-*, mt-*, mr-*, mb-*, ml-*, m-auto, mx-auto, ml-auto, mr-auto
<div class="w-full">100%</div>
<div class="w-auto">shrink to content</div>
<div class="w-fit">...</div>
<div class="w-screen">100vw</div>
<div class="h-full">...</div>
<div class="h-screen">100vh</div>
<div class="min-h-screen">...</div><div class="max-w-sm mx-auto">...</div> <!-- 24rem -->
<div class="max-w-md mx-auto">...</div> <!-- 28rem -->
<div class="max-w-lg mx-auto">...</div> <!-- 32rem -->
<div class="max-w-xl mx-auto">...</div> <!-- 36rem -->
<div class="max-w-2xl mx-auto">...</div> <!-- 42rem -->
<div class="max-w-4xl mx-auto">...</div> <!-- 56rem -->
<div class="max-w-7xl mx-auto">...</div> <!-- 80rem -->
<div class="container">...</div> <!-- max 80rem, auto margins, padded --><!-- Size -->
<p class="text-xs">Extra small</p>
<p class="text-sm">Small</p>
<p class="text-base">Base</p>
<p class="text-lg">Large</p>
<p class="text-xl">X-Large</p>
<p class="text-2xl">2X-Large</p>
<p class="text-3xl">3X-Large</p>
<p class="text-4xl">4X-Large</p>
<p class="text-5xl">5X-Large</p>
<p class="text-6xl">6X-Large</p>
<p class="text-7xl">7X-Large</p>
<!-- Weight -->
<p class="font-normal">Normal 400</p>
<p class="font-medium">Medium 500</p>
<p class="font-semibold">Semibold 600</p>
<p class="font-bold">Bold 700</p>
<p class="font-black">Black 900</p>
<!-- Alignment -->
<p class="text-left">...</p>
<p class="text-center">...</p>
<p class="text-right">...</p>
<!-- Style & transform -->
<p class="italic">...</p>
<p class="uppercase">...</p>
<p class="capitalize">...</p>
<p class="underline">...</p>
<p class="line-through">...</p>
<p class="truncate">truncated with ellipsis...</p>
<!-- Line height -->
<p class="leading-tight">1.25</p>
<p class="leading-normal">1.5</p>
<p class="leading-relaxed">1.625</p>
<p class="leading-loose">2</p><!-- Text -->
<p class="text-primary">...</p>
<p class="text-secondary">...</p>
<p class="text-muted">...</p>
<p class="text-success">...</p>
<p class="text-danger">...</p>
<p class="text-warning">...</p>
<p class="text-white">...</p>
<p class="text-black">...</p>
<!-- Background -->
<div class="bg-primary">...</div>
<div class="bg-surface">...</div>
<div class="bg-success">...</div>
<div class="bg-danger">...</div>
<div class="bg-white">...</div>
<div class="bg-transparent">...</div>
<!-- Border color -->
<div class="border border-primary">...</div>
<div class="border border-danger">...</div><div class="border">all sides, default color</div>
<div class="border-t">top only</div>
<div class="border-r">right only</div>
<div class="border-b">bottom only</div>
<div class="border-l">left only</div>
<div class="border border-2">2px</div>
<div class="border border-4">4px</div>
<div class="border border-dashed">dashed</div>
<div class="border border-dotted">dotted</div>
<div class="border-0">remove border</div><div class="rounded-sm">...</div>
<div class="rounded-md">...</div>
<div class="rounded-lg">...</div>
<div class="rounded-full">pill or circle</div>
<div class="rounded-none">no radius</div>
<!-- Top/bottom only -->
<div class="rounded-t-lg">...</div>
<div class="rounded-b-md">...</div><div class="shadow-sm">subtle</div>
<div class="shadow-md">medium</div>
<div class="shadow-lg">large</div>
<div class="shadow-xl">extra large</div>
<div class="shadow-none">remove shadow</div><div class="opacity-100">fully visible</div>
<div class="opacity-75">75%</div>
<div class="opacity-50">50%</div>
<div class="opacity-25">25%</div>
<div class="opacity-0">invisible</div><div class="transition">all properties, base speed</div>
<div class="transition-fast">150ms</div>
<div class="transition-slow">300ms</div>
<div class="transition-colors">color, background, border only</div>
<div class="transition-opacity">opacity only</div>
<div class="transition-transform">transform only</div>
<div class="transition-none">disable</div><button class="cursor-pointer">...</button>
<span class="cursor-not-allowed opacity-50">disabled</span>
<div class="cursor-grab">...</div>All state variants use a suffix, consistent with responsive variants.
Applied only on :hover. Each color has a dedicated --color-*-hover variable.
<!-- Background changes on hover -->
<button class="bg-primary bg-primary-hover transition-colors">Button</button>
<!-- Border highlights on hover -->
<div class="border border-primary-hover transition-colors">Card</div>
<!-- Text color changes on hover -->
<a class="text-muted text-primary-hover transition-colors">Link</a>
<!-- Shadow lifts on hover -->
<div class="shadow-sm shadow-md-hover transition">Card</div>
<!-- Opacity dims on hover -->
<img class="opacity-100 opacity-75-hover transition-opacity">Available: bg-*-hover, text-*-hover, border-*-hover, shadow-*-hover, opacity-*-hover
Applied on :focus. Essential for accessible form inputs.
<input class="border outline-none-focus border-primary-focus transition-colors">
<!-- ring-focus adds a 2px outline using --color-primary-focus -->
<button class="ring-focus">Accessible button</button>Available: bg-*-focus, text-*-focus, border-*-focus, outline-none-focus, ring-focus, ring-danger-focus
Applied on :active (while pressed).
<!-- Full interactive state stack -->
<button class="bg-primary bg-primary-hover bg-primary-active transition-colors">
Button
</button>Available: bg-*-active, text-*-active, border-*-active, opacity-*-active
Breakpoint variants use a -{breakpoint} suffix and are mobile-first (min-width).
| Suffix | Breakpoint |
|---|---|
-sm |
640px+ |
-md |
768px+ |
-lg |
1024px+ |
<!-- Stack on mobile, side by side at md -->
<div class="flex flex-col flex-row-md gap-4">
<div>Column 1</div>
<div>Column 2</div>
</div>
<!-- Hide on mobile, show at lg -->
<nav class="hidden flex-lg">...</nav>
<!-- 1 col on mobile, 2 at sm, 3 at md -->
<div class="grid grid-cols-1 grid-cols-2-sm grid-cols-3-md gap-4">
...
</div>
<!-- Larger text on bigger screens -->
<h1 class="text-3xl text-5xl-md text-7xl-lg">Heading</h1>Available responsive utilities: display, flex direction, justify, align items, grid columns, text sizes, width
Use unc-extend.css to override tokens or add custom utilities. It loads after unc.css so everything cascades correctly.
/* unc-extend.css */
:root {
--color-primary: #e11d48;
--color-primary-hover: #be123c;
--color-primary-focus: #9f1239;
--color-primary-active: #881337;
}:root {
--color-brand: #f97316;
--color-brand-hover: #ea6c0a;
--color-brand-focus: #c2540a;
--color-brand-active: #9a3e06;
}
.bg-brand { background-color: var(--color-brand); }
.text-brand { color: var(--color-brand); }
.bg-brand-hover:hover { background-color: var(--color-brand-hover); }
.bg-brand-focus:focus { background-color: var(--color-brand-focus); }
.bg-brand-active:active { background-color: var(--color-brand-active); }.btn {
display: inline-flex;
align-items: center;
gap: var(--space-2);
padding: var(--space-2) var(--space-5);
background: var(--color-primary);
color: var(--color-white);
font-weight: var(--font-medium);
border-radius: var(--radius-md);
border: none;
cursor: pointer;
transition: background var(--transition-fast);
}
.btn:hover { background: var(--color-primary-hover); }
.btn:active { background: var(--color-primary-active); }
.btn-outline {
background: transparent;
color: var(--color-primary);
border: 1px solid var(--color-primary);
}
.btn-outline:hover {
background: var(--color-primary);
color: var(--color-white);
}