ecklf / tailwindcss-radix Goto Github PK
View Code? Open in Web Editor NEWUtilities and variants for styling Radix state
Home Page: https://tailwindcss-radix.vercel.app
License: MIT License
Utilities and variants for styling Radix state
Home Page: https://tailwindcss-radix.vercel.app
License: MIT License
Hi, I have issues installing tailwindcss-radix into a create-t3-app (https://create.t3.gg/)
I just wanted to say thank you for the high quality work and huge effort you've been dedicating to this library.
The API you've created makes total sense and conforms to Radix/Tailwind conventions. It's so good that it seems like it was created by the Radix/Tailwind authors.
Also the work you've made here https://tailwindcss-radix.vercel.app is mind blowing, I have no words to describe how good it is.
Thank you very much!
Hello I'm trying to use this lib with a monorepo with pnpm
workspaces and turborepo
. I used this example from turborepo
itself that contains tailwind. But I don't know what I'm missing to make it work properly.
My final result is this (Accordion and Select components):
You can see that the tailwind classes are working because of the green text (color that I configured in tailwindcss).
I copy your components from the demo but the styles are not working.
Can you help with this? Thanks for this amazing library!
While content is opening and closing, I want to add animations but how is this possible ?
I also have a custom plugin setup like yours.
But after I found your plugin, really wanna switch to yours and found peer
variant missing.
You can find the peer
variant of my plugin here.
Is there a working example with the radix-state-open/closed utilities?
or even the headless ui example in the readme? (how does currentItem get set?)
I am using both windy-radix-palette and tailwindcss-radix.
But I found that the css class of tailwindcss-radix does not work properly.
For example this.
<DropdownMenu.Content
align="end"
sideOffset={5}
className={cx(
" radix-side-top:animate-slide-up radix-side-bottom:animate-slide-down",
"rounded-md p-3 beautify-shadow",
"bg-white dark:bg-gray-800"
)}
style={{
width: '278px'
}}
>
There is no animation applied on
Is there a way to make it work with twin.macro? Thanks!
I see all those utilities for the animations, but there's no documentation about how to use them. Also, when I go to see the animations in the demo, sometimes there is none (like in the case animating the accordion content height).
Not sure how to proceed without clear documentation.
Hi,
First of all thanks for these amazing utilities!
I've ran into an issue and wanted to check if it's my lack of knowledge or a bug to report.
When using the Accordion and styling the Header in its open and close states, it works fine for the default light mode but the dark mode doesn't seem to work:
<AccordionPrimitive.Header className="w-full h-full leading-[3rem]">
<AccordionPrimitive.Trigger
className={clsx(
"group",
"radix-state-open:rounded-t-xl radix-state-closed:rounded-xl",
"focus:outline-none",
"inline-flex w-full items-center justify-between px-10 md:px-16 py-6 md:py-10 text-left",
"radix-state-open:bg-white radix-state-closed:bg-neutral-200 hover:bg-neutral-100",
"radix-state-open:dark:bg-neutral-700 radix-state-closed:dark:bg-neutral-900 hover:dark:bg-neutral-800 transition-colors"
)}
>
(...)
</AccordionPrimitive.Trigger>
</AccordionPrimitive.Header>
In the above code I get an error in VS Code saying 'radix-state-open:dark:bg-neutral-700' applies the same CSS properties as 'radix-state-closed:dark:bg-neutral-900'.(cssConflict)
.
The visual result on my end is that the bg radix-states are being applied in the light mode (for some also strange reason the hover state doesn't). And that in the dark mode they just don't get implemented at all defaulting to the light mode values (and ironically the hover state works!).
Is this some mistake of mine? Or a bug to report?
Thank you
P.S.- If I remove the radix-states the hover works fine on both light and dark modes.
Radix supports leave animations by suspending unmount while your animation plays out, more info here.
While going over the source code, I've noticed how this plugin adds support for the closed
state (radix-state-closed
). However, I was not able to successfully animate the unmount phase using tailwind. Most if not all of the demo components have the same issue of being instantly unmounted without a smooth transition.
Is it possible with the current API to achieve this? Otherwise, is it feasible to implement support for it?
import tailwindRadix from 'tailwindcss-radix';
tailwind.config.ts
plugins: [
tailwindRadix,
],
I am not sure how to specify variantPrefix with esm import.
Hello.
Can we add this feature in the navigation menu. Here are its descriptions radix-ui/primitives#1462 and the solution.
Hi, I'm new to the library, I was learning how to use radix + tailwind and discovered an issue with the dialog demo.
There is a side effect when using flex + gap because the Transitions aren't wrapped with DialogPrimitive.Portal component.
<DialogPrimitive.Root open={isOpen} onOpenChange={setIsOpen}>
<DialogPrimitive.Trigger asChild>
<Button>Click</Button>
</DialogPrimitive.Trigger>
<DialogPrimitive.Portal> // <---- Here!
<Transition.Root show={isOpen}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-200"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
Thank you for the library, and the demos are fantastic!
Didn't see anything about this. Possible to combine multiple states? If so, doesn't seem to work. Not sure which should come first.
rdx-state-checked:rdx-state-disabled:bg-disabled
Hi @ecklf - thanks for the excellent project.
So far all works as demo'd, however, we've hit a speedbump with the @radix-ui/react-toast component.
We have tailwind configured in a Remix.run project via postCSS (we are importing other CSS files)
For example... our postcsss.config.js looks like this...
// postcss.config.js
module.exports = cfg => {
const
dev = cfg.env === 'development',
scss = cfg.file.extname === '.scss'
return {
map: dev ? { inline: false } : false,
parser: scss ? 'postcss-scss' : false,
plugins: {
'postcss-import': {},
'postcss-nested': {},
tailwindcss: {},
autoprefixer: {},
...(dev ? {} : { cssnano: {} }),
},
}
}
And our tailwind.config.js config looks like this...
/** @type {import('tailwindcss').Config} */
const defaultTheme = require("tailwindcss/defaultTheme")
module.exports = {
darkMode: 'class',
content: [
"./app/**/*.{js,ts,jsx,tsx}",
],
plugins: [
require('@tailwindcss/typography'),
require('@tailwindcss/forms'),
require("tailwindcss-radix")(),
],
theme: {
...defaultTheme,
},
extend: {},
},
}
And in our app.css file, we import the tailwind base components and utilities files as:
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
However, after all of this, and despite including the require("tailwindcss-radix")(),
in our tailwind.config.js file, we appear to be missing the radix variant state and animation classes - such as radix-state-open:animate-toast-slide-in-right
. They're present as class attributes of the components/elements, but in devtools, we can see that no corresponding class definition is found.
Are we missing an import? Or configuration setting? Remix.run is using ESBuild - not sure if this is a factor?
Thoughts or suggestions greatly appreciated.
Particularly, I believe the new variables to enable advanced animation (e.g. NavigationMenu Advanced Animation, --radix-navigation-menu-viewport-[width|height]
) may need to be explicitly supported.
An example/demo much like the great demos already here, would also be great.
I've created a Drawer
component based off of the Radix Dialog
component something I think the Radix library is missing. Do you have any interest in adding this component? Here's a rough sketch of how it would look:
drawer.tsx:
import { Transition } from "@headlessui/react";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { Cross1Icon } from "@radix-ui/react-icons";
import { clsx } from "clsx";
import React, { Fragment } from "react";
import Button from "./shared/button";
type Position = "left" | "right";
export interface DrawerProps {
title?: string;
description?: string;
position?: Position;
isOpen: boolean;
onOpenChange: () => void;
}
const Drawer = (props: DrawerProps) => {
const {
title = "Drawer",
position = "right",
description,
isOpen,
onOpenChange,
} = props;
return (
<DialogPrimitive.Root open={isOpen} onOpenChange={onOpenChange}>
<DialogPrimitive.Portal forceMount>
<Transition.Root show={isOpen}>
<Transition.Child
as={Fragment}
enter="ease-in-out duration-300"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in-out duration-300"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<DialogPrimitive.Overlay className="fixed inset-0 bg-black/50" />
</Transition.Child>
<Transition.Child
as={Fragment}
enter="transform transition ease-in-out duration-300"
enterFrom="translate-x-full"
enterTo="translate-x-0"
leave="transform transition ease-in-out duration-300"
leaveFrom="translate-x-0"
leaveTo="translate-x-full"
>
<DialogPrimitive.Content
forceMount
className={clsx(
position === "right" ? "right-0" : "left-0",
"fixed top-0 flex h-full w-screen max-w-md flex-col overflow-y-scroll bg-gray-800 py-6 shadow-xl"
)}
>
<DialogPrimitive.Title className="mb-2 px-4 text-sm font-medium text-gray-900 dark:text-gray-100">
{title}
</DialogPrimitive.Title>
{description && (
<DialogPrimitive.Description className="px-4 text-sm font-normal text-gray-700 dark:text-gray-400">
{description}
</DialogPrimitive.Description>
)}
<div className="mt-[25px] flex justify-end px-4">
<DialogPrimitive.Close
className={clsx(
"inline-flex select-none justify-center rounded-md px-4 py-2 text-sm font-medium",
"bg-purple-600 text-white hover:bg-purple-700 dark:bg-purple-700 dark:text-gray-100 dark:hover:bg-purple-600",
"border border-transparent",
"focus:outline-none focus-visible:ring focus-visible:ring-purple-500 focus-visible:ring-opacity-75"
)}
>
Save changes
</DialogPrimitive.Close>
</div>
<DialogPrimitive.Close className="absolute top-6 right-3.5 inline-flex items-center justify-center rounded-full p-1 focus:outline-none focus-visible:ring focus-visible:ring-purple-500 focus-visible:ring-opacity-75">
<Cross1Icon className="h-4 w-4 text-gray-500 hover:text-gray-700 dark:text-gray-500 dark:hover:text-gray-400" />
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</Transition.Child>
</Transition.Root>
</DialogPrimitive.Portal>
</DialogPrimitive.Root>
);
};
export { Drawer };
index.tsx:
const DrawerWithState = () => {
const [drawerOpen, setDrawerOpen] = useState<boolean>(false);
const handleDrawerToggle = () => {
setDrawerOpen(!drawerOpen);
};
return (
<>
<Button onClick={handleDrawerToggle}>Click</Button>
<Drawer
isOpen={drawerOpen}
onOpenChange={handleDrawerToggle}
description="Navigation drawers provide access to destinations in your app. Side sheets are surfaces containing supplementary content that are anchored to the left or right edge of the screen."
/>
</>
);
};
{
label: "Drawer",
link: `${REPO_URL}/components/drawer.tsx`,
component: <DrawerWithState />,
},
I have the changes on a PR locally. I'd very much like to contribute to your library moving forward ๐ . Please let me know your thoughts and feedback? Thanks!
Hi, we are trying to style the open and close state of the accordion in Radix, seems t not work or are we doing anything wrong....
Is there any example you can post for quick reference ?
Right now if I use this library like the following, it will not work as expected:
<AccordionContent class="group/my-named">
<div class="group-radix-state-closed/my-named:opacity-0">
// ...
</div>
</AccordionContent>
I'm not sure when this named groups feature was implemented in TailwindCSS, but a helpful guide for how to make this library work with it can be found here: https://tailwindcss.com/docs/plugins#parent-and-sibling-states
I can work on this myself if I find time and if @ecklf shows interest. Either way just leaving this here so it gets documented.
Thanks!
Hi and thanks a lot for the excellent project. We've created several configurable wrapper functional components around your examples, and it's all working great.
One thing we recently tried to do was create options / props for positioning Toasts in either 'top-right', 'bottom-right', 'top-left' and 'bottom-left'.
We've got this working by modifying the keyframes
and animation
options in thailwind.config.js
- as follows:
/** @type {import('tailwindcss').Config} */
const defaultTheme = require("tailwindcss/defaultTheme")
module.exports = {
darkMode: 'class',
content: [
"./app/**/*.{js,ts,jsx,tsx}",
],
plugins: [
require('@tailwindcss/typography'),
require('@tailwindcss/forms'),
require("tailwindcss-radix")(),
],
variants: {
extend: {},
},
theme: {
...defaultTheme,
fontFamily: {
...defaultTheme.fontFamily,
display: ["Roboto", ...defaultTheme.fontFamily.sans],
sans: ["Inter", ...defaultTheme.fontFamily.sans],
mono: ["Source Code Pro", ...defaultTheme.fontFamily.mono],
},
gridTemplateColumns: {
'auto-fit-280': 'repeat(auto-fill, minmax(280px, 1fr))',
'auto-fit-320': 'repeat(auto-fill, minmax(320px, 1fr))',
'auto-fit-480': 'repeat(auto-fill, minmax(480px, 1fr))',
},
extend: {
boxShadow: {
slider: "0 0 0 5px rgba(0, 0, 0, 0.3)",
},
keyframes: {
// Dropdown menu
"scale-in": {
"0%": { opacity: 0, transform: "scale(0)" },
"100%": { opacity: 1, transform: "scale(1)" },
},
"slide-down": {
"0%": { opacity: 0, transform: "translateY(-10px)" },
"100%": { opacity: 1, transform: "translateY(0)" },
},
"slide-up": {
"0%": { opacity: 0, transform: "translateY(10px)" },
"100%": { opacity: 1, transform: "translateY(0)" },
},
// Tooltip
"slide-up-fade": {
"0%": { opacity: 0, transform: "translateY(2px)" },
"100%": { opacity: 1, transform: "translateY(0)" },
},
"slide-right-fade": {
"0%": { opacity: 0, transform: "translateX(-2px)" },
"100%": { opacity: 1, transform: "translateX(0)" },
},
"slide-down-fade": {
"0%": { opacity: 0, transform: "translateY(-2px)" },
"100%": { opacity: 1, transform: "translateY(0)" },
},
"slide-left-fade": {
"0%": { opacity: 0, transform: "translateX(2px)" },
"100%": { opacity: 1, transform: "translateX(0)" },
},
// Navigation menu
"enter-from-right": {
"0%": { transform: "translateX(200px)", opacity: 0 },
"100%": { transform: "translateX(0)", opacity: 1 },
},
"enter-from-left": {
"0%": { transform: "translateX(-200px)", opacity: 0 },
"100%": { transform: "translateX(0)", opacity: 1 },
},
"exit-to-right": {
"0%": { transform: "translateX(0)", opacity: 1 },
"100%": { transform: "translateX(200px)", opacity: 0 },
},
"exit-to-left": {
"0%": { transform: "translateX(0)", opacity: 1 },
"100%": { transform: "translateX(-200px)", opacity: 0 },
},
"scale-in-content": {
"0%": { transform: "rotateX(-30deg) scale(0.9)", opacity: 0 },
"100%": { transform: "rotateX(0deg) scale(1)", opacity: 1 },
},
"scale-out-content": {
"0%": { transform: "rotateX(0deg) scale(1)", opacity: 1 },
"100%": { transform: "rotateX(-10deg) scale(0.95)", opacity: 0 },
},
"fade-in": {
"0%": { opacity: 0 },
"100%": { opacity: 1 },
},
"fade-out": {
"0%": { opacity: 1 },
"100%": { opacity: 0 },
},
// Toast
"toast-hide": {
"0%": { opacity: 1 },
"100%": { opacity: 0 },
},
"toast-slide-in-right": {
"0%": { transform: `translateX(calc(100% + 1rem))` },
"100%": { transform: "translateX(0)" },
},
"toast-slide-in-left": {
"0%": { transform: `translateX(calc(-1 * (100% + 1rem)))` },
"100%": { transform: "translateX(0)" },
},
"toast-slide-in-bottom": {
"0%": { transform: `translateY(calc(100% + 1rem))` },
"100%": { transform: "translateY(0)" },
},
// Leave toast-swipe-out for compatibility - swipe out right
"toast-swipe-out": {
"0%": { transform: "translateX(var(--radix-toast-swipe-end-x))" },
"100%": {
transform: `translateX(calc(100% + 1rem))`,
},
},
"toast-swipe-out-right": {
"0%": { transform: "translateX(var(--radix-toast-swipe-end-x))" },
"100%": {
transform: `translateX(calc(100% + 1rem))`,
},
},
"toast-swipe-out-left": {
"0%": { transform: "translateX(var(--radix-toast-swipe-end-x))" },
"100%": {
transform: `translateX(calc(-1 * (100% + 1rem)))`,
},
},
},
animation: {
// Dropdown menu
"scale-in": "scale-in 0.2s ease-in-out",
"slide-down": "slide-down 0.6s cubic-bezier(0.16, 1, 0.3, 1)",
"slide-up": "slide-up 0.6s cubic-bezier(0.16, 1, 0.3, 1)",
// Tooltip
"slide-up-fade": "slide-up-fade 0.4s cubic-bezier(0.16, 1, 0.3, 1)",
"slide-right-fade":
"slide-right-fade 0.4s cubic-bezier(0.16, 1, 0.3, 1)",
"slide-down-fade": "slide-down-fade 0.4s cubic-bezier(0.16, 1, 0.3, 1)",
"slide-left-fade": "slide-left-fade 0.4s cubic-bezier(0.16, 1, 0.3, 1)",
// Navigation menu
"enter-from-right": "enter-from-right 0.25s ease",
"enter-from-left": "enter-from-left 0.25s ease",
"exit-to-right": "exit-to-right 0.25s ease",
"exit-to-left": "exit-to-left 0.25s ease",
"scale-in-content": "scale-in-content 0.2s ease",
"scale-out-content": "scale-out-content 0.2s ease",
"fade-in": "fade-in 0.2s ease",
"fade-out": "fade-out 0.2s ease",
// Toast
"toast-hide": "toast-hide 100ms ease-in forwards",
"toast-slide-in-right":
"toast-slide-in-right 150ms cubic-bezier(0.16, 1, 0.3, 1)",
"toast-slide-in-left":
"toast-slide-in-left 150ms cubic-bezier(0.16, 1, 0.3, 1)",
"toast-slide-in-bottom":
"toast-slide-in-bottom 150ms cubic-bezier(0.16, 1, 0.3, 1)",
// Leave toast-swipe-out for compatibility - swipe out right.
"toast-swipe-out": "toast-swipe-out 100ms ease-out forwards",
"toast-swipe-out-right": "toast-swipe-out-right 100ms ease-out forwards",
"toast-swipe-out-left": "toast-swipe-out-left 100ms ease-out forwards",
},
},
},
}
This is all working fine, and we can now position and animate the entrance and close of the Toast component to any corner.
There's just one problem. The direction of the pointer 'drag' and data attribute for 'move' event data-swipe='move' has its drag direction configured at the provider level - as in the docs here...
https://www.radix-ui.com/docs/primitives/components/toast#provider - with the swipeDirection
prop and enum (for "right" | "left" | "up" | "down").
For example ToastPrimitive.Provider swipeDirection='right'
Which means we're not sure whether it's possible to configure this at the ToastPrimitive.Root
level (which we wrap in our configurable component) to change the direction of the manual 'drag' and 'move' of the Toast.
Are we going about this the wrong way? Or is there no easy solution?
For interest, our complete Toast component implementation is here...
Suggestions or thoughts greatly appreciated.
And again - thanks for the great project - and Happy New Year!
Is there any way we can turn off -state
prefix in data-state variants?
So the radix-state-checked
will be transformed into radix-checked
.
I think it's easier to read and understand (e.g. radix-disable
)
Looking at the Dialog
component, any way of managing the transitions without bringing @headless-ui
in? Getting two headless libraries seems dull
Great job on the repo :-)
I'm perusing the demo here and trying to adapt some of the examples. I'm noticing there's reference to origin-[top_center]
in the Navigation Menu demo:
Implementing the demo as is, the menu is centered with respect to the parent element, and is missing the small caret that connects the flyout to the nav. Would appreciate any insight here!
Edit: I'm an actual idiot. It's Friday. Don't hate me. I'm now remembering the [ ]
syntax in Tailwind.
Hello, how are you?
I've been using tailwindcss-radix for a few weeks now and it's great. However, I recently included the library in a project that also uses DaisyUI, and I noticed that some functionalities are not compatible. It's possible that the classes generated by the library don't properly call the corresponding DaisyUI classes.
Here's an example of an implementation where I found the problem:
import { Accordion } from '@primitives/radix';
import { IAccordionProps } from './accordion.interface';
export function AccordionComponent(props: IAccordionProps): JSX.Element {
return (
<Accordion.Root type='multiple' disabled={props.disabled}>
{props.items.map((item, index) => {
return (
<>
<Accordion.Item className='collapse rounded-box collapse-arrow w-80 m-3 radix-state-open:collapse-open radix-state-closed:collapse-close' value={`item-${index}`}>
<Accordion.Trigger className='collapse-title bg-neutral-focus text-neutral-focus-content'>
{item.label}
</Accordion.Trigger>
<Accordion.Content className='collapse-content p-4 bg-neutral text-neutral-content'>
{item.content}
</Accordion.Content>
</Accordion.Item>
</>
);
})}
</Accordion.Root>
);
}
Basically, when using the radix-state passing tailwind's own classes, the application works correctly. I tested it with border, padding, and other classes. However, with DaisyUI's own classes, there seems to be no compatibility. Let me know if I can help by providing more information about the problem. Congratulations on the great work.
I'm receiving errors on my formatter:
./src/components/sidebar/account-dropdown.tsx
36:33 Warning: Classname 'radix-side-top:animate-slide-up' is not a Tailwind CSS class! tailwindcss/no-custom-classname
36:33 Warning: Classname 'radix-side-bottom:animate-slide-down' is not a Tailwind CSS class! tailwindcss/no-custom-classname
Config
{
"extends": [
"next/core-web-vitals",
"prettier",
"plugin:storybook/recommended",
"plugin:tailwindcss/recommended"
]
}
I believe the documentation for this project may not beginner friendly for new contributor who are just starting their contributions
can someone write here the step by steps of installation to fork or clone
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.