# Create a Dialog Component with Radix UI, Tailwind CSS & Framer Motion 2023-04-02 In this tutorial, we'll dive into the world of Radix UI, Tailwind CSS, and Framer Motion to create a dialog that animates from the bottom up on mobile viewports and slides in from the right like a drawer on desktop. By following these step-by-step instructions, you'll learn how to create a versatile, accessible, and visually impressive component. To get you started quickly, here's a project demonstrating the component. Resize the mini-browser area to see the different transitions and layouts for the modal in smaller and larger viewports. **Setting up the project to kick things off.** Fork the Stackblitz project above, or if you'd like to add this to your own React project, roughly follow these commands: ```bash npm create vite@latest my-react-app -- --template react-ts cd my-react-app npm install ``` Next, we'll install the necessary dependencies: Radix UI, Tailwind CSS, and Framer Motion. ```bash npm install -D tailwindcss postcss autoprefixer npm install @radix-ui/react-dialog framer-motion npm install usehooks-ts classnames ``` **Integrating Tailwind CSS** ```bash npx tailwindcss init -p ``` Copy the `tailwind.config.cjs` and `index.css` from the Stackblitz. You should now be able to run the project ```bash npm run dev ``` **Building the Dialog Component With Tailwind CSS integrated, let's start building our dialog component. We'll leverage the power of Radix UI to create an accessible, flexible, and customizable component.** [Radix dialogs](https://www.radix-ui.com/docs/primitives/components/dialog) have a specific component structure. We'll be relying on Radix for accessibility and certain behavior expected of dialogs, focus trapping, keyboard navigation and more. ```jsx import * as Dialog from '@radix-ui/react-dialog'; export default () => ( ); ``` This looks a bit verbose, but every component serves a purpose. Radix renders the dialog in a portal outside the React DOM hierarchy which makes it easier to style and position on top of the UI. We'll want to animate both the `Dialog.Overlay` and the `Dialog.Content`. The overlay is a layer between the UI and dialog itself which we'll use to block and tint the UI so that it looks inaccessible, drawing attention to the dialog. An easy way to let Frame Motion animate these elements is to ask Radix to always keep the top level `Dialog.Portal` mounted and wrap it in `AnimatePresence`. This way we can pass an `open` prop to toggle the portal. Before continuing to the actual animation, you might be wondering about `useMediaQuery`. Aren't media queries a CSS thing? Usually yes, but Frame Motion does not have a notion of media queries so we'll have to use this hook from the [usehook-ts](http://usehooks-ts.com) collection library. Another way to achieve this is to write two separate components and simply toggle visibility with media query targeting, or simply use CSS animations and not Framer Motion. Using the hook we can have just one component. ```jsx const DialogContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { open: boolean; } >(({ className, children, open, ...props }, ref) => { const isMobile = useMediaQuery('(max-width: 640px)'); return ( {open ? ( {/* see next snippet 👇🏻 */} ) : null} ); }); ``` The `forceMount` is necessary to let Frame Motion keep the component around during its exit animation. ### Adding Framer Motion Animation **With our dialog component in place and wrapped in `AnimatePresence`, it's time to breathe life into it using Framer Motion. We'll create two animations: one for mobile viewports and another for desktop.** The `Dialog.Overlay` is wrapped in a simple opacity in-out animation. ```jsx {/* see next snippet for content 👇🏻 */} ``` Now let's zoom into the main part - `Dialog.Content`! Here we're using the `isMobile` to toggle between animating the full width of the dialog from the right on desktop, or the full height from the bottom, like a sheet UI that is common on smaller screens, where controls and buttons are likely to be closer to the thumb. Notice that `{children}` is being passed in, letting us re-use this component for different dialog use cases – like confirmation dialogs, settings, user input and more. ```jsx
{children}
``` [Framer Motion](http://framer.com/motion/examples/) provides an expressive and complete control of animations - from simple to complex orchestrated transitions. **Congratulations! You've just created a responsive dialog component using Radix UI, Tailwind CSS, and Framer Motion.** Here's how the component is put to use, with a single state hook. ```jsx function App() { const [open, setOpen] = useState(false); return (
{ setOpen(open); }} > I'm a dialog
Content - put anything here!
); } ``` I hope the combination of libraries presented here has given you some ideas for how to create more accessible and good looking interactive components for your project. A great place to explore good component practises is [github.com/shadcn/ui](http://github.com/shadcn/ui) - a great collection of components using Radix UI and Tailwind. In fact - this component is largely based on shadcn's dialog wrapper.