# 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 (
);
}
```
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.