Utilities and variants for styling Radix state
npm i tailwindcss-radix
yarn add tailwindcss-radix
To prevent a possible future name clashing the skipAttributeNames
option has been removed. In case you used this option, please update the class names accordingly.
Click on the banner to check out the demo components. You can find the code inside the demo folder.
Add the plugin to your plugins array:
module.exports = {
theme: {
// --snip--
},
variants: {
// --snip--
},
plugins: [
// Initialize with default values (see options below)
require("tailwindcss-radix")(),
],
};
require("tailwindcss-radix")({
// Default: `radix`
variantPrefix: "rdx",
});
// Example 1: Generates `rdx-[state/side/orientation]-*` utilities for `data-[state/side/orientation]="*"`
variantPrefix: "rdx",
// Example 2: Generates `[state/side/orientation]-*` utilities for `data-[state/side/orientation]="*"`
variantPrefix: false,
This plugin works with CSS attribute selectors. Use the variants based on the data-*
attribute added by Radix.
import React from "react";
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
const App = () => {
return (
<DropdownMenuPrimitive.Root>
<DropdownMenuPrimitive.Trigger className="border-black radix-state-open:border-2">
Trigger
</DropdownMenuPrimitive.Trigger>
<DropdownMenuPrimitive.Content>
<DropdownMenuPrimitive.Item>Item</DropdownMenuPrimitive.Item>
</DropdownMenuPrimitive.Content>
</DropdownMenuPrimitive.Root>
);
};
export default App;
Sometimes we want to access state in the child of the trigger element. This can be achieved by adding the group
class to the parent element and the group-*
variants on the child element.
Example usage of a conditional transform for a Radix Accordion
:
import React from "react";
import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { ChevronDownIcon } from "@radix-ui/react-icons";
const Accordion = () => {
return (
<AccordionPrimitive.Root type="multiple">
<AccordionPrimitive.Item value="item-1">
<AccordionPrimitive.Header>
<AccordionPrimitive.Trigger className="group">
<div className="flex items-center">
Item 1
<ChevronDownIcon className="w-5 h-5 ml-2 transform group-radix-state-open:rotate-180" />
</div>
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
<AccordionPrimitive.Content>Content 1</AccordionPrimitive.Content>
</AccordionPrimitive.Item>
<AccordionPrimitive.Item value="item-2">
<AccordionPrimitive.Header>
<AccordionPrimitive.Trigger className="group">
<div className="flex items-center">
Item 2
<ChevronDownIcon className="w-5 h-5 ml-2 transform group-radix-state-open:rotate-180" />
</div>
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
<AccordionPrimitive.Content>Content 2</AccordionPrimitive.Content>
</AccordionPrimitive.Item>
</AccordionPrimitive.Root>
);
};
export default App;
Use the generated disabled
variant.
import React from "react";
import * as ContextMenuPrimitive from "@radix-ui/react-context-menu";
const ContextMenu = () => {
return (
// --snip--
<ContextMenuPrimitive.Item
disabled
className="radix-disabled:opacity-50 radix-disabled:cursor-not-allowed"
>
Item
</ContextMenuPrimitive.Item>
// --snip--
);
};
Use the generated origin-*
utilities to transform from the content position origin.
.origin-radix-dropdown-menu {
transform-origin: var(--radix-dropdown-menu-content-transform-origin);
}
.origin-radix-hover-card {
transform-origin: var(--radix-hover-card-content-transform-origin);
}
.origin-radix-context-menu {
transform-origin: var(--radix-context-menu-content-transform-origin);
}
.origin-radix-popover {
transform-origin: var(--radix-popover-content-transform-origin);
}
.origin-radix-tooltip {
transform-origin: var(--radix-tooltip-content-transform-origin);
}
Use the generated h-*
and w-*
utilities to animate the size of the content when it opens/closes.
.h-radix-accordion {
height: var(--radix-accordion-content-height);
}
.w-radix-accordion {
width: var(--radix-accordion-content-width);
}
.h-radix-collapsible {
height: var(--radix-collapsible-content-height);
}
.w-radix-collapsible {
width: var(--radix-collapsible-content-width);
}
Example usage with the <Transition/>
component from @headlessui/react
:
import React from "react";
import * as AccordionPrimitive from "@radix-ui/react-accordion";
import { Transition } from "@headlessui/react";
const AnimatedAccordion = () => {
return (
// --snip--
<AccordionPrimitive.Content forceMount className="overflow-hidden">
<Transition
show={currentItem === "item-1"}
enter="ease-out duration-300"
enterFrom="h-0"
enterTo="h-radix-accordion"
leave="ease-in duration-300"
leaveFrom="h-radix-accordion"
leaveTo="h-0"
>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Voluptatum
ullam, ratione veniam voluptate nobis sunt laboriosam aperiam harum
fugit corrupti alias magnam officiis nihil minima eum excepturi natus
similique? Cupiditate reprehenderit, hic sequi modi nemo odit esse
quas adipisci perferendis beatae deserunt ducimus itaque molestias
quibusdam porro assumenda laudantium id!
</p>
</Transition>
</AccordionPrimitive.Content>
// --snip--
);
};
Use the generated translate-*
utilities to animate swipe gestures.
.translate-x-radix-toast-swipe-move-x {
transform: translateX(var(--radix-toast-swipe-move-x));
}
.translate-y-radix-toast-swipe-move-y {
transform: translateY(var(--radix-toast-swipe-move-y));
}
.translate-x-radix-toast-swipe-end-x {
transform: translateX(var(--radix-toast-swipe-end-x));
}
.translate-y-radix-toast-swipe-end-y {
transform: translateY(var(--radix-toast-swipe-end-y));
}
MIT