tailwindcss-radix
Tailwind CSS utilities and variants for styling Radix Primitives' data-state attributes.
Repository Health
Technical Analysis
tailwindcss-radix is a small Tailwind CSS plugin purpose-built for apps using Radix UI (now Radix Primitives). Radix components communicate state — open/closed, checked, disabled, which side a popover renders on — through data-* attributes rather than class names, which normally forces developers to write raw attribute selectors by hand. This plugin turns those attributes into first-class Tailwind variants (radix-state-open:, radix-side-bottom:, radix-disabled:, and more), so they get the same autocomplete, consistency, and readability as any other Tailwind modifier.
Beyond variants, it ships utility classes for the CSS custom properties Radix components expose at runtime — trigger width, content available height, transform origin — which are otherwise easy to miss and painful to wire up manually for things like matching a dropdown’s width to its trigger. The plugin supports both the legacy require()-based Tailwind config and the newer CSS-native @plugin directive introduced in Tailwind v4, with a configurable variant prefix if radix- collides with an existing convention.
It’s a natural pairing for teams building their own component library on top of Radix Primitives or shadcn/ui, where every interactive primitive (dialogs, dropdowns, accordions, tooltips) needs state-driven styling and the alternative is repeating data-[state=open]: selectors across dozens of components.
What You Get
- Boolean-state variants (
radix-disabled:,radix-highlighted:,radix-placeholder:) mapped directly to Radix’sdata-*boolean attributes - Value-state variants for
state,side,align,orientation,motion,swipe, andswipe-directionattributes, covering every Radix Primitives component group-radix-*andpeer-radix-*variants for styling an element based on a parent or sibling Radix component’s state- Width/height utilities (
w-radix-*,h-radix-*) bound to Radix’s exposed CSS custom properties like trigger width and content-available height - A
translate-x-radix-toast-swipe-*/translate-y-radix-toast-swipe-*utility pair for wiring up Radix Toast’s swipe-to-dismiss gesture - Both Tailwind v3 (
require()-based config) and Tailwind v4 (@pluginCSS directive) compatibility, with a configurablevariantPrefixoption
Common Use Cases
- Rotating a chevron icon when a Radix Accordion or Collapsible item opens, using
group-radix-state-open:rotate-180on the trigger’s group - Animating a Radix Dialog or Popover’s entrance/exit direction with
radix-side-bottom:/radix-state-closed:variants instead of hand-written CSS - Matching a Radix Select or Dropdown Menu’s open content width to its trigger via the
w-radix-*-triggerutility - Building a reusable component library on top of Radix Primitives (or extending shadcn/ui components) where every primitive needs consistent state styling
- Styling Radix Toast’s swipe gesture feedback using the generated swipe-transform utilities
Under The Hood
Architecture
tailwindcss-radix is a single-file Tailwind plugin (src/index.ts) built with Tailwind’s official plugin.withOptions factory, which returns a configurable plugin function receiving addUtilities and matchVariant from Tailwind’s plugin API. The whole implementation is a sequence of declarative loops: one registers boolean-attribute variants (disabled, highlighted, placeholder) via matchVariant, one iterates a record of attribute-name-to-allowed-values pairs (state, side, align, orientation, motion, swipe, swipe-direction) to generate value-based variants, and several forEach passes register width/height/transform-origin utility classes keyed off Radix’s exposed CSS custom properties. There is no runtime state, no class hierarchy, and no dependency between the loops — each is independent and additive, so the plugin’s output is fully determined by its one Options input (the variantPrefix string) at build time.
Tech Stack
The project is TypeScript-only, compiled with tsc directly (tsc --removeComments) rather than a bundler, targeting CommonJS via export = for compatibility with Tailwind’s plugin loading convention. Its only real dependency is a peer dependency on tailwindcss itself (^3.0 || ^4.0), keeping the published package’s own footprint minimal. Development tooling includes Biome for linting and formatting (replacing ESLint/Prettier), Vitest for tests, Husky for a pre-commit hook that runs the test suite, and release-it for tagging and publishing releases. A separate demo/ Next.js app (with its own package.json, Tailwind config, and Vercel deployment) hosts the live component gallery linked from the README.
Code Quality
Tests in src/index.test.ts exercise the plugin through PostCSS directly — running actual Tailwind configs with the plugin attached against raw HTML fixtures and asserting on the generated CSS output, using both inline and stored Vitest snapshots. This is an integration-style test approach well suited to a CSS-generation plugin, since it verifies real generated output rather than mocking Tailwind’s internals. Coverage extends to boolean variants, value variants, group/peer variants (including named groups), and the width/height/transform utilities. TypeScript is used throughout with an explicit Options interface, and Biome’s recommended rule set plus a pre-commit hook enforce formatting and passing tests before any commit reaches the repository. No CI workflow is configured in .github/ beyond a funding file, so enforcement relies on the local Husky hook and manual review rather than a public build status.
API Design
The public surface is exactly one default export — the plugin itself — configured with a single optional field (variantPrefix), which keeps the getting-started path to a one-line plugins: [] addition or @plugin directive. Generated class names follow Tailwind’s own naming conventions closely (radix-state-open:, w-radix-select-trigger), so they read naturally alongside built-in utilities and require no new mental model beyond “replace data-* selectors with radix-* variants.” The README documents every variant category with runnable JSX examples against real Radix component packages (Accordion, Checkbox, Dropdown Menu, Toast), and a hosted demo site shows the utilities applied to live components, which shortens the path from reading docs to shipping styled Radix components in an existing project.
Used by 7 apps in this directory
Cal.diy
Scheduling
The 100% MIT-licensed, community-driven scheduling platform — self-host your own booking infrastructure with no enterprise strings attached.
Dub
Marketing · Analytics
The open-source link attribution platform for short links, conversion tracking, and affiliate programs — powering 100M+ clicks monthly.
Flipt
Devops · Developer Tools
Git-native feature flag platform that stores, versions, and deploys feature toggles directly in your own Git repositories with no external database required.
LibreChat
Developer Tools · AI Assistants
Unite every major AI model in one self-hosted chat platform with agents, code execution, MCP tools, and enterprise authentication.
Polar
Ecommerce · Developer Tools · Invoicing Finance
Open source payments infrastructure that turns software into a business — subscriptions, usage-based billing, digital products, and merchant-of-record compliance in one platform.
Snapify
Collaboration · Productivity
Open-source, self-hostable screen recording and video sharing built as a Loom alternative — no accounts required to watch, full S3-backed storage for your data.
Spacedrive
File Storage · Collaboration
One file manager for all your devices and clouds — powered by a Virtual Distributed File System built in Rust.