Skip to content

Repository files navigation

Adire UI

A component registry for React and Tailwind CSS v4 — components install into your app as source files you own and edit, not as a package you depend on.

Every component styles against a semantic token contract (accent, bg, text, muted, …), so each app keeps its own palette and the components just work.

Adire (ah-DEE-ray) is the Yoruba craft of resist-dyed cloth: one pattern, a different indigo every time. Same idea here — one set of components, a different palette in every project.

Quickstart

Point your app's components.json at the registry:

{
	"registries": {
		"@adire": "https://raw.githubusercontent.com/Timonwa/adire-ui/main/r/{name}.json",
	},
}

Then install:

npx shadcn@latest add @adire/styles  # once per new app — the stylesheet structure + token contract
npx shadcn@latest add @adire/button  # pulls cn automatically

Files land in your source tree (src/styles/*.css, components/ui/base/button.tsx, lib/utils/cn.ts) and are yours from that moment — edit them to fit the project.

What's inside

Item What it is
styles The stylesheet structure — globals.css importing the active theme, overrides.css (project tweaks that survive theme switches), and the base, typography, forms, animations, utilities and components layers
theme-lilac / theme-ocean / theme-ember / theme-slate Complete palettes (light + dark, matched shadows and glass) — pick one, or use it as the starting point for a custom palette
27 base components avatar, badge, bullet-list, button, checkbox, chip, dual-toggle, external-link, gradient, icon-badge, icon-button, image, input, label, link, overlay, progress-bar, radio, select, separator, skeleton, spinner, swatch-picker, switch, tag, textarea, theme-script
Blocks accordion, alert, breadcrumbs, card, segmented-control, tabs, tabs-nav
cn Class-name merge with Tailwind conflict resolution (clsx + tailwind-merge)

Each component installs only its own file plus the code it genuinely imports — add @adire/button brings the button and cn, nothing else. Every axis is a fixed vocabulary (7 sizes, 10 radii, 7 tones, 5 interactive variants) rather than per-component invention, so components compose without surprises.

Using your router

Every component that links internally — button, icon-button, card, breadcrumbs, tabs-nav — renders through link, and that file is the single place to switch:

// components/ui/base/link.tsx
import NextLink from "next/link";

const DEFAULT_LINK: ElementType = NextLink;

One edit and the whole set does client-side navigation with prefetch, instead of the full page reload a plain <a> causes. Individual instances can still override it with linkAs. Offsite destinations use external-link, which stays a plain anchor — a router adds nothing there, and it hardens rel against tab-napping.

Components style against the semantic token names (--color-accent, --color-bg, …), never raw values — swap the values in themes.css per app and every component follows. Dark mode is token overrides under [data-theme="dark"]; components never branch on the theme.

Components are organized in tiers — base (primitives) → blocks (composed) → patterns (full sections) → layouts (page shells) — and install into matching folders. More components are added tier by tier.

Accessibility

Accessibility is part of "done" here, not a later pass, and it is enforced rather than intended:

  • Anything interactive is a native control. Clicks live on button, a and input — never on a div with a handler — so focus order, Enter and Space, and disabled states come from the platform instead of from someone remembering them. tabIndex appears only where an ARIA pattern requires it, such as the roving tabindex in tabs.
  • Every interactive component has a story that operates it by keyboard alone, asserting focus and activation by key. Those stories run as tests, so a component that stops being keyboard-operable fails the build.
  • Axe runs on every story at error level (a11y: { test: "error" }), so a violation fails the test run.
  • No state rides on colour alone. Sorting says aria-sort, the current page says aria-current, a finished step says "completed" in words — and the contrast of every token pair is checked by pnpm check:contrast in all four themes.
  • RTL is a first-class direction: logical properties throughout, and only direction-neutral icons go unmirrored.

Requirements

Tailwind CSS v4 and React. The registry ships no runtime package; per-component npm dependencies (like clsx) are installed by the CLI as needed.

Contributing

This registry tracks my own component defaults, but issues and suggestions are welcome.

License

MIT

About

A themeable component registry for React and Tailwind CSS v4 — install components as source you own and edit.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages