Open Dialog
Introduction
Toldo is an elevated dialog component built on top of @radix-ui that provides a few extra features to make it easier to work with dialogs in your application.
Installation
Install the component from your command line.
pnpm install toldo
Anatomy
Import all parts and piece them together.
import * as Dialog from "@radix-ui/react-dialog" ;
export default () => (
< Dialog.Root >
< Dialog.Trigger >
< Dialog.SharedItem >
</ Dialog.Trigger >
< Dialog.Portal >
< Dialog.Overlay />
< Dialog.Content >
< Dialog.Title />
< Dialog.Description />
< Dialog.Close />
</ Dialog.Content >
< Dialog.Stack >
< Dialog.StackContent >
< Dialog.StackTitle />
< Dialog.StackDescription />
< Dialog.StackAdd />
< Dialog.StackRemove />
</ Dialog.StackContent >
</ Dialog.Stack >
</ Dialog.Portal >
</ Dialog.Root >
);
Examples
Basic
This example demonstrates the simplest use of Toldo's dialog component. This setup uses straightforward styles and functional controls to provide a basic dialog interaction.
Open Dialog
import * as Dialog from "toldo" ;
export const Basic = () => {
return (
< Dialog.Root >
< Dialog.Trigger className = "h-[32px] rounded-lg border border-gray-3 bg-gradient-to-t bg-gray-1 from-gray-1 to-gray-2 px-3 transition-all ease-in-out hover:brightness-95" >
Open Dialog
</ Dialog.Trigger >
< Dialog.Portal >
< Dialog.Overlay className = " fixed inset-0 bg-black-a10" />
< Dialog.Content className = "-translate-x-1/2 -translate-y-1/2 fixed top-1/2 left-1/2 max-h-[85vh] w-[90vw] max-w-[450px] flex-col overflow-hidden rounded-xl border border-gray-3 bg-gray-1 sm:w-[384px]" >
< Dialog.Title className = "px-6 pt-5 font-semibold text-foreground text-large" >Change Username</ Dialog.Title >
< Dialog.Description className = "px-6 py-1 text-default text-muted" >
Make changes to your username here.
</ Dialog.Description >
< fieldset className = "mb-[15px] flex items-center gap-4 px-6 py-4" >
< input
id = "name"
placeholder = "@raphaelsalaja"
className = "inline-flex h-[32px] w-full flex-1 items-center justify-center rounded-lg border border-gray-4 bg-gray-2 px-2.5 text-[15px] text-default leading-none transition-all placeholder:text-muted focus:outline-none focus:ring-1 focus:ring-green-11 focus:ring-offset-2 focus:ring-offset-gray-1"
/>
</ fieldset >
< div className = "flex justify-between gap-4 border-gray-3 border-t bg-gray-2 px-6 py-5" >
< Dialog.Close className = "!text-gray-11 h-[32px] max-w-fit rounded-lg bg-gray-a3 px-3 transition-all ease-in-out hover:brightness-150" >
Cancel
</ Dialog.Close >
< Dialog.Close className = "!text-green-11 h-[32px] max-w-fit rounded-lg bg-green-a3 px-3 transition-all ease-in-out hover:brightness-150" >
Save Changes
</ Dialog.Close >
</ div >
</ Dialog.Content >
</ Dialog.Portal >
</ Dialog.Root >
);
};
Basic with Animation
In this example, we add animations to the basic dialog for a more engaging experience. Using Framer Motion, we apply smooth fade-in and scaling effects when the dialog opens and closes.
In order for the animation presence to work, you need to make sure to mount the portal components when the dialog is open. This is done by setting the forceMount prop to true on the Dialog.Portal component.
Open Dialog
"use client" ;
import { AnimatePresence, type AnimationProps, motion } from "framer-motion" ;
import React from "react" ;
import * as Dialog from "toldo" ;
export const BasicWithAnimation = () => {
const [ open , setOpen ] = React. useState ( false );
const variants : { [ key : string ] : AnimationProps } = {
overlay: {
initial: { opacity: 0 },
animate: { opacity: 1 },
exit: { opacity: 0 },
transition: { ease: [ 0.19 , 1 , 0.22 , 1 ], duration: 0.4 },
},
content: {
initial: { scale: 0.9 , opacity: 0 },
animate: { scale: 1 , opacity: 1 },
exit: { scale: 0.9 , opacity: 0 },
transition: { ease: [ 0.19 , 1 , 0.22 , 1 ], duration: 0.4 },
},
};
return (
< Dialog.Root open = {open} onOpenChange = {setOpen}>
< Dialog.Trigger className = "h-[32px] rounded-lg border border-gray-3 bg-gradient-to-t bg-gray-1 from-gray-1 to-gray-2 px-3 transition-all ease-in-out hover:brightness-95" >
Open Dialog
</ Dialog.Trigger >
< Dialog.Portal forceMount >
< AnimatePresence mode = "popLayout" >
{open && (
< Dialog.Overlay className = "fixed top-0 left-0 h-full w-full" >
< motion.div className = "fixed inset-0 bg-black-a10" { ... variants.overlay} />
</ Dialog.Overlay >
)}
</ AnimatePresence >
< AnimatePresence mode = "popLayout" >
{open && (
< Dialog.Content className = "-translate-x-1/2 -translate-y-1/2 fixed top-1/2 left-1/2 max-h-[85vh] w-[90vw] max-w-[450px]" >
< motion.div
className = "flex-col overflow-hidden rounded-xl border border-gray-3 bg-gray-1 sm:w-[384px]"
{ ... variants.content}
>
< Dialog.Title className = "px-6 pt-5 font-semibold text-foreground text-large" >
Change Username
</ Dialog.Title >
< Dialog.Description className = "px-6 py-1 text-default text-muted" >
Make changes to your username here.
</ Dialog.Description >
< fieldset className = "mb-[15px] flex items-center gap-4 px-6 py-4" >
< input
id = "name"
placeholder = "@raphaelsalaja"
className = "inline-flex h-[32px] w-full flex-1 items-center justify-center rounded-lg border border-gray-4 bg-gray-2 px-2.5 text-[15px] text-default leading-none transition-all placeholder:text-muted focus:outline-none focus:ring-1 focus:ring-green-11 focus:ring-offset-2 focus:ring-offset-gray-1"
/>
</ fieldset >
< div className = "flex justify-between gap-4 border-gray-3 border-t bg-gray-2 px-6 py-5" >
< Dialog.Close className = "!text-gray-11 h-[32px] max-w-fit rounded-lg bg-gray-a3 px-3 transition-all ease-in-out hover:brightness-150" >
Cancel
</ Dialog.Close >
< Dialog.Close className = "!text-green-11 h-[32px] max-w-fit rounded-lg bg-green-a3 px-3 transition-all ease-in-out hover:brightness-150" >
Save Changes
</ Dialog.Close >
</ div >
</ motion.div >
</ Dialog.Content >
)}
</ AnimatePresence >
</ Dialog.Portal >
</ Dialog.Root >
);
};
Stacked
Stacked dialogs require a different setup. Them main diffrence is that we create our dialogs in an array and pass them to the Dialog.Root component. Use the Dialog.Stack component to manage the dialogs in the stack.
We use the Dialog.StackAdd and Dialog.StackRemove components to add and remove dialogs from the stack. Be mindful to include the dialogId prop to identify the dialog you want to add or remove within the trigger.
Note that modal dialogs interrupt users and demand an action. They are appropriate when user’s attention needs to be directed toward important information. It is not reccomended to use stacked dialogs for simple tasks. Only use them when the user needs to complete a series of tasks or decisions.
Open Dialog
"use client" ;
import { AnimatePresence, type AnimationProps, motion } from "framer-motion" ;
import { useState } from "react" ;
import * as Dialog from "toldo" ;
export const Stacked = () => {
const [ open , setOpen ] = useState ( false );
const dialogs : Dialog . Props [] = [
{
id: "username" ,
dialog : (
< Dialog.StackContent className = "flex max-h-[85vh] w-[90vw] flex-col overflow-hidden rounded-xl border border-gray-3 bg-gray-1 sm:w-[384px]" >
< Dialog.StackTitle className = "px-6 pt-5 font-semibold text-foreground text-large" >
Change Username
</ Dialog.StackTitle >
< Dialog.StackDescription className = "px-6 py-1 text-default text-muted" >
Make changes to your username here.
</ Dialog.StackDescription >
< fieldset className = "mb-[15px] flex items-center gap-4 px-6 py-5" >
< input
id = "name"
placeholder = "@raphaelsalaja"
className = "inline-flex h-[32px] w-full flex-1 items-center justify-center rounded-lg border border-gray-4 bg-gray-2 px-2.5 text-[15px] text-default leading-none transition-all placeholder:text-muted focus:outline-none focus:ring-1 focus:ring-green-11 focus:ring-offset-2 focus:ring-offset-gray-1"
/>
</ fieldset >
< div className = "flex justify-between gap-4 border-gray-3 border-t bg-gray-2 px-6 py-4" >
< Dialog.Close className = "!text-gray-11 h-[32px] max-w-fit rounded-lg bg-gray-a3 px-3 transition-all ease-in-out hover:brightness-150" >
Cancel
</ Dialog.Close >
< Dialog.StackAdd
dialogId = "email"
className = "!text-blue-11 h-[32px] max-w-fit rounded-lg bg-blue-a3 px-3 transition-all ease-in-out hover:brightness-150"
>
Continue
</ Dialog.StackAdd >
</ div >
</ Dialog.StackContent >
),
},
{
id: "email" ,
dialog : (
< Dialog.StackContent className = "flex max-h-[85vh] w-[90vw] flex-col overflow-hidden rounded-xl border border-gray-3 bg-gray-1 sm:w-[384px]" >
< Dialog.StackTitle className = "px-6 pt-5 font-semibold text-foreground text-large" >
Change Email
</ Dialog.StackTitle >
< Dialog.StackDescription className = "px-6 py-1 text-default text-muted" >
Make changes to your email here.
</ Dialog.StackDescription >
< fieldset className = "mb-[15px] flex items-center gap-4 px-6 py-5" >
< input
id = "email"
placeholder = "raphaelsalaja@gmail.com"
className = "inline-flex h-[32px] w-full flex-1 items-center justify-center rounded-lg border border-gray-4 bg-gray-2 px-2.5 text-[15px] text-default leading-none transition-all placeholder:text-muted focus:outline-none focus:ring-1 focus:ring-green-11 focus:ring-offset-2 focus:ring-offset-gray-1"
/>
</ fieldset >
< div className = "flex justify-between gap-4 border-gray-3 border-t bg-gray-2 px-6 py-4" >
< Dialog.StackRemove
dialogId = "email"
className = "!text-gray-11 h-[32px] max-w-fit rounded-lg bg-gray-a3 px-3 transition-all ease-in-out hover:brightness-150"
>
Return
</ Dialog.StackRemove >
< Dialog.StackAdd
dialogId = "date-of-birth"
className = "!text-blue-11 h-[32px] max-w-fit rounded-lg bg-blue-a3 px-3 transition-all ease-in-out hover:brightness-150"
>
Continue
</ Dialog.StackAdd >
</ div >
</ Dialog.StackContent >
),
},
{
id: "date-of-birth" ,
dialog : (
< Dialog.StackContent className = "flex max-h-[85vh] w-[90vw] flex-col overflow-hidden rounded-xl border border-gray-3 bg-gray-1 sm:w-[384px]" >
< Dialog.StackTitle className = "px-6 pt-5 font-semibold text-foreground text-large" >
Change Date of Birth
</ Dialog.StackTitle >
< Dialog.StackDescription className = "px-6 py-1 text-default text-muted" >
Make changes to your birth date here.
</ Dialog.StackDescription >
< fieldset className = "mb-[15px] flex items-center gap-4 px-6 py-5" >
< input
id = "date-of-birth"
placeholder = "January 1, 2000"
className = "inline-flex h-[32px] w-full flex-1 items-center justify-center rounded-lg border border-gray-4 bg-gray-2 px-2.5 text-[15px] text-default leading-none transition-all placeholder:text-muted focus:outline-none focus:ring-1 focus:ring-green-11 focus:ring-offset-2 focus:ring-offset-gray-1"
/>
</ fieldset >
< div className = "flex justify-between gap-4 border-gray-3 border-t bg-gray-2 px-6 py-4" >
< Dialog.StackRemove
dialogId = "date-of-birth"
className = "!text-gray-11 h-[32px] max-w-fit rounded-lg bg-gray-a3 px-3 transition-all ease-in-out hover:brightness-150"
>
Return
</ Dialog.StackRemove >
< Dialog.Close className = "!text-green-11 h-[32px] max-w-fit rounded-lg bg-green-a3 px-3 transition-all ease-in-out hover:brightness-150" >
Save Changes
</ Dialog.Close >
</ div >
</ Dialog.StackContent >
),
},
];
const variants : { [ key : string ] : AnimationProps } = {
overlay: {
initial: { opacity: 0 },
animate: { opacity: 1 },
exit: { opacity: 0 },
transition: { ease: [ 0.19 , 1 , 0.22 , 1 ], duration: 0.4 },
},
content: {
initial: { scale: 0.9 , opacity: 0 },
animate: { scale: 1 , opacity: 1 },
exit: { scale: 0.9 , opacity: 0 },
transition: { ease: [ 0.19 , 1 , 0.22 , 1 ], duration: 0.4 },
},
};
return (
< Dialog.Root open = {open} onOpenChange = {setOpen} dialogs = {dialogs}>
< Dialog.Trigger
dialogId = "username"
className = "h-[32px] rounded-lg border border-gray-3 bg-gradient-to-t bg-gray-1 from-gray-1 to-gray-2 px-3 transition-all ease-in-out hover:brightness-95"
>
Open Dialog
</ Dialog.Trigger >
< Dialog.Portal forceMount >
< AnimatePresence >
{open && (
< Dialog.Overlay className = "fixed top-0 left-0 h-full w-full" >
< motion.div className = "fixed inset-0 bg-black-a10" { ... variants.overlay} />
</ Dialog.Overlay >
)}
</ AnimatePresence >
< AnimatePresence >{open && < Dialog.Stack { ... variants.content} />}</ AnimatePresence >
</ Dialog.Portal >
</ Dialog.Root >
);
};
Shared Layout
The Dialog.SharedItem component is a handy component to share animations between dialogs. It wraps Framer's motion.div layout into a more readable component.
For more information on shared layout transitions, check out the docs on Framer Motion .
Open Dialog
"use client" ;
import { AnimatePresence, type AnimationProps, motion } from "framer-motion" ;
import React from "react" ;
import * as Dialog from "toldo" ;
export const Shared = () => {
const [ open , setOpen ] = React. useState ( false );
const variants : { [ key : string ] : AnimationProps } = {
overlay: {
initial: { opacity: 0 },
animate: { opacity: 1 },
exit: { opacity: 0 },
transition: { ease: [ 0.19 , 1 , 0.22 , 1 ], duration: 0.4 },
},
content: {
initial: { scale: 0.9 , opacity: 0 },
animate: { scale: 1 , opacity: 1 },
exit: { scale: 0.9 , opacity: 0 },
transition: { ease: [ 0.19 , 1 , 0.22 , 1 ], duration: 0.4 },
},
button: {
transition: { layout: { ease: [ 0.19 , 1 , 0.22 , 1 ], duration: 0.6 } },
},
};
return (
< Dialog.Root open = {open} onOpenChange = {setOpen}>
< Dialog.Trigger >
< Dialog.SharedItem
layout
layoutId = "action"
className = "pointer-events-auto flex h-[32px] items-center rounded-lg border border-gray-3 bg-gradient-to-t bg-gray-1 from-gray-1 to-gray-2 px-3"
{ ... variants.button}
>
Open Dialog
</ Dialog.SharedItem >
</ Dialog.Trigger >
< AnimatePresence >
{open && (
< Dialog.Portal forceMount >
< Dialog.Overlay className = "fixed top-0 left-0 h-full w-full" >
< motion.div className = "fixed inset-0 bg-black-a10" { ... variants.overlay} />
</ Dialog.Overlay >
< Dialog.Content className = "-translate-x-1/2 -translate-y-1/2 fixed top-1/2 left-1/2 max-h-[85vh] w-[90vw] max-w-[450px]" >
< motion.div
className = "w-full flex-col overflow-hidden rounded-xl border border-gray-3 bg-gray-1 sm:w-[384px]"
{ ... variants.content}
>
< Dialog.Title className = "px-6 pt-5 font-semibold text-foreground text-large" >
Change Username
</ Dialog.Title >
< Dialog.Description className = "px-6 py-1 text-default text-muted" >
Make changes to your username here.
</ Dialog.Description >
< fieldset className = "mb-[15px] flex items-center gap-4 px-6 py-4" >
< input
id = "name"
placeholder = "@raphaelsalaja"
className = "inline-flex h-[32px] w-full flex-1 items-center justify-center rounded-lg border border-gray-4 bg-gray-2 px-2.5 text-[15px] text-default leading-none transition-all placeholder:text-muted focus:outline-none focus:ring-1 focus:ring-green-11 focus:ring-offset-2 focus:ring-offset-gray-1"
/>
</ fieldset >
< div className = "flex justify-between gap-4 border-gray-3 border-t bg-gray-2 px-6 py-5" >
< Dialog.Close className = "!text-gray-11 h-[32px] max-w-fit rounded-lg bg-gray-a3 px-3 transition-all ease-in-out hover:brightness-150" >
Cancel
</ Dialog.Close >
< motion.div layout layoutId = "action" { ... variants.button}>
< Dialog.Close className = "flex h-[32px] items-center rounded-lg border border-gray-3 bg-gradient-to-t bg-gray-1 from-gray-1 to-gray-2 px-3" >
Save Changes
</ Dialog.Close >
</ motion.div >
</ div >
</ motion.div >
</ Dialog.Content >
</ Dialog.Portal >
)}
</ AnimatePresence >
</ Dialog.Root >
);
};
Examples Tailwind Config
The examples above use @radix-ui/colors for color variables. The following file contains the color variables used in the examples above.
tailwind.config.ts
import type { Config } from "tailwindcss" ;
import plugin from "tailwindcss/plugin" ;
const config : Config = {
important: true ,
content: [
"./pages/**/*.{js,ts,jsx,tsx,mdx}" ,
"./components/**/*.{js,ts,jsx,tsx,mdx}" ,
"./markdown/**/*.{js,ts,jsx,tsx,mdx}" ,
"./app/**/*.{js,ts,jsx,tsx,mdx}" ,
],
theme: {
extend: {
colors: {
gray: {
1 : "var(--gray-1)" ,
2 : "var(--gray-2)" ,
3 : "var(--gray-3)" ,
4 : "var(--gray-4)" ,
5 : "var(--gray-5)" ,
6 : "var(--gray-6)" ,
7 : "var(--gray-7)" ,
8 : "var(--gray-8)" ,
9 : "var(--gray-9)" ,
10 : "var(--gray-10)" ,
11 : "var(--gray-11)" ,
12 : "var(--gray-12)" ,
a1: "var(--gray-a1)" ,
a2: "var(--gray-a2)" ,
a3: "var(--gray-a3)" ,
a4: "var(--gray-a4)" ,
a5: "var(--gray-a5)" ,
a6: "var(--gray-a6)" ,
a7: "var(--gray-a7)" ,
a8: "var(--gray-a8)" ,
a9: "var(--gray-a9)" ,
a10: "var(--gray-a10)" ,
a11: "var(--gray-a11)" ,
a12: "var(--gray-a12)" ,
},
black: {
a1: "var(--black-a1)" ,
a2: "var(--black-a2)" ,
a3: "var(--black-a3)" ,
a4: "var(--black-a4)" ,
a5: "var(--black-a5)" ,
a6: "var(--black-a6)" ,
a7: "var(--black-a7)" ,
a8: "var(--black-a8)" ,
a9: "var(--black-a9)" ,
a10: "var(--black-a10)" ,
a11: "var(--black-a11)" ,
a12: "var(--black-a12)" ,
},
white: {
a1: "var(--white-a1)" ,
a2: "var(--white-a2)" ,
a3: "var(--white-a3)" ,
a4: "var(--white-a4)" ,
a5: "var(--white-a5)" ,
a6: "var(--white-a6)" ,
a7: "var(--white-a7)" ,
a8: "var(--white-a8)" ,
a9: "var(--white-a9)" ,
a10: "var(--white-a10)" ,
a11: "var(--white-a11)" ,
a12: "var(--white-a12)" ,
},
pink: {
1 : "var(--pink-1)" ,
2 : "var(--pink-2)" ,
3 : "var(--pink-3)" ,
4 : "var(--pink-4)" ,
5 : "var(--pink-5)" ,
6 : "var(--pink-6)" ,
7 : "var(--pink-7)" ,
8 : "var(--pink-8)" ,
9 : "var(--pink-9)" ,
10 : "var(--pink-10)" ,
11 : "var(--pink-11)" ,
12 : "var(--pink-12)" ,
a1: "var(--pink-a1)" ,
a2: "var(--pink-a2)" ,
a3: "var(--pink-a3)" ,
a4: "var(--pink-a4)" ,
a5: "var(--pink-a5)" ,
a6: "var(--pink-a6)" ,
a7: "var(--pink-a7)" ,
a8: "var(--pink-a8)" ,
a9: "var(--pink-a9)" ,
a10: "var(--pink-a10)" ,
a11: "var(--pink-a11)" ,
a12: "var(--pink-a12)" ,
},
yellow: {
1 : "var(--yellow-1)" ,
2 : "var(--yellow-2)" ,
3 : "var(--yellow-3)" ,
4 : "var(--yellow-4)" ,
5 : "var(--yellow-5)" ,
6 : "var(--yellow-6)" ,
7 : "var(--yellow-7)" ,
8 : "var(--yellow-8)" ,
9 : "var(--yellow-9)" ,
10 : "var(--yellow-10)" ,
11 : "var(--yellow-11)" ,
12 : "var(--yellow-12)" ,
a1: "var(--yellow-a1)" ,
a2: "var(--yellow-a2)" ,
a3: "var(--yellow-a3)" ,
a4: "var(--yellow-a4)" ,
a5: "var(--yellow-a5)" ,
a6: "var(--yellow-a6)" ,
a7: "var(--yellow-a7)" ,
a8: "var(--yellow-a8)" ,
a9: "var(--yellow-a9)" ,
a10: "var(--yellow-a10)" ,
a11: "var(--yellow-a11)" ,
a12: "var(--yellow-a12)" ,
},
red: {
1 : "var(--red-1)" ,
2 : "var(--red-2)" ,
3 : "var(--red-3)" ,
4 : "var(--red-4)" ,
5 : "var(--red-5)" ,
6 : "var(--red-6)" ,
7 : "var(--red-7)" ,
8 : "var(--red-8)" ,
9 : "var(--red-9)" ,
10 : "var(--red-10)" ,
11 : "var(--red-11)" ,
12 : "var(--red-12)" ,
a1: "var(--red-a1)" ,
a2: "var(--red-a2)" ,
a3: "var(--red-a3)" ,
a4: "var(--red-a4)" ,
a5: "var(--red-a5)" ,
a6: "var(--red-a6)" ,
a7: "var(--red-a7)" ,
a8: "var(--red-a8)" ,
a9: "var(--red-a9)" ,
a10: "var(--red-a10)" ,
a11: "var(--red-a11)" ,
a12: "var(--red-a12)" ,
},
green: {
1 : "var(--green-1)" ,
2 : "var(--green-2)" ,
3 : "var(--green-3)" ,
4 : "var(--green-4)" ,
5 : "var(--green-5)" ,
6 : "var(--green-6)" ,
7 : "var(--green-7)" ,
8 : "var(--green-8)" ,
9 : "var(--green-9)" ,
10 : "var(--green-10)" ,
11 : "var(--green-11)" ,
12 : "var(--green-12)" ,
a1: "var(--green-a1)" ,
a2: "var(--green-a2)" ,
a3: "var(--green-a3)" ,
a4: "var(--green-a4)" ,
a5: "var(--green-a5)" ,
a6: "var(--green-a6)" ,
a7: "var(--green-a7)" ,
a8: "var(--green-a8)" ,
a9: "var(--green-a9)" ,
a10: "var(--green-a10)" ,
a11: "var(--green-a11)" ,
a12: "var(--green-a12)" ,
},
blue: {
1 : "var(--blue-1)" ,
2 : "var(--blue-2)" ,
3 : "var(--blue-3)" ,
4 : "var(--blue-4)" ,
5 : "var(--blue-5)" ,
6 : "var(--blue-6)" ,
7 : "var(--blue-7)" ,
8 : "var(--blue-8)" ,
9 : "var(--blue-9)" ,
10 : "var(--blue-10)" ,
11 : "var(--blue-11)" ,
12 : "var(--blue-12)" ,
a1: "var(--blue-a1)" ,
a2: "var(--blue-a2)" ,
a3: "var(--blue-a3)" ,
a4: "var(--blue-a4)" ,
a5: "var(--blue-a5)" ,
a6: "var(--blue-a6)" ,
a7: "var(--blue-a7)" ,
a8: "var(--blue-a8)" ,
a9: "var(--blue-a9)" ,
a10: "var(--blue-a10)" ,
a11: "var(--blue-a11)" ,
a12: "var(--blue-a12)" ,
},
background: "var(--bg)" ,
foreground: "var(--fg)" ,
muted: "var(--muted)" ,
hover: "var(--hover)" ,
border: "var(--border)" ,
scrollbar: {
thumb: "var(--scrollbar-thumb)" ,
track: "var(--scrollbar-track)" ,
},
selection: {
background: "var(--selection-background)" ,
foreground: "var(--selection-foreground)" ,
},
highlight: {
background: "var(--highlight-background)" ,
foreground: "var(--highlight-foreground)" ,
},
kbd: {
background: "var(--kbd-background)" ,
foreground: "var(--kbd-foreground)" ,
border: "var(--kbd-border)" ,
},
},
fontFamily: {
inter: [ "var(--font-inter)" ],
},
borderRadius: {
small: "var(--radius-small)" ,
base: "var(--radius-base)" ,
large: "var(--radius-large)" ,
},
},
},
plugins: [
plugin (({ addUtilities }) => {
addUtilities ({
".text-small" : {
fontSize: "12px" ,
letterSpacing: "0.01px" ,
},
".text-default" : {
fontSize: "14px" ,
lineHeight: "21px" ,
letterSpacing: "-0.09px" ,
},
".text-large" : {
fontSize: "16px" ,
lineHeight: "24px" ,
letterSpacing: "-0.18px" ,
},
".text-huge" : {
fontSize: "24px" ,
lineHeight: "36px" ,
letterSpacing: "-0.47px" ,
},
});
}),
],
darkMode: "class" ,
};
export default config;
API Reference
Root
Contains all the parts of a dialog.
Trigger
The button that opens the dialog.
Portal
When used, portals your overlay and content parts into the body element.
Prop Type Default -
document.body
Overlay
A layer that covers the inert portion of the view when the dialog is open.
Content
Contains content to be rendered in the open dialog.
Prop Type Default false
-
-
-
-
-
-
Close
The button that closes the dialog.
Title
An accessible title to be announced when the dialog is opened.
Description
An optional accessible description to be announced when the dialog is opened.
Stack
A wrapper that holds the dialogs in a stack.
Prop Type Default 24
0.05
0.33
-
-
-
-
Stack Content
Contains content to be rendered in the open dialog within a stack.
Stack Title
An accessible title to be announced when the dialog is opened within a stack.
Stack Description
An optional accessible description to be announced when the dialog is opened within a stack.
Stack Remove
The button that removes the dialog from the stack.
Stack Add
The button that adds a dialog to the stack.
Shared Item
A handy component to share animations between dialogs.
Considerations
Dialogs should be used sparingly and only when necessary. They can be disruptive to the user experience.
When using dialogs, ensure that they are accessible to all users. This includes making sure that the dialog can be navigated using the keyboard, that focus is managed correctly, and that the dialog is announced to screen readers.
When it comes to dialogs on mobile devices, consider using a full-screen modal instead of a dialog. This will provide a better user experience on smaller screens. Check out drawer components like Vaul by Emil for more information.