Search for a command to run...
A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.
npx shadcn@latest add @zaidan/dialogpnpx shadcn add @zaidan/dialogyarn dlx shadcn@latest add @zaidan/dialogbunx shadcn@latest add @zaidan/dialogCopy and paste the following code into your project.
1import * as DialogPrimitive from "@kobalte/core/dialog";2import type { PolymorphicProps } from "@kobalte/core/polymorphic";3import { X } from "lucide-solid";4import type { Component, ComponentProps, ValidComponent } from "solid-js";5import { mergeProps, Show, splitProps } from "solid-js";6
7import { cn } from "~/lib/utils";8import { Button } from "~/components/ui/button";9
10const Dialog: Component<DialogPrimitive.DialogRootProps> = (props) => {11 return <DialogPrimitive.Root data-slot="dialog" {...props} />;12};13
14type DialogTriggerProps<T extends ValidComponent = "button"> = PolymorphicProps<15 T,16 DialogPrimitive.DialogTriggerProps<T>17>;18
19const DialogTrigger = <T extends ValidComponent = "button">(props: DialogTriggerProps<T>) => {20 return <DialogPrimitive.Trigger data-slot="dialog-trigger" {...props} />;21};22
23const DialogPortal = (props: DialogPrimitive.DialogPortalProps) => {24 return <DialogPrimitive.Portal data-slot="dialog-portal" {...props} />;25};26
27type DialogCloseProps<T extends ValidComponent = "button"> = PolymorphicProps<28 T,29 DialogPrimitive.DialogCloseButtonProps<T>30>;31
32const DialogClose = <T extends ValidComponent = "button">(props: DialogCloseProps<T>) => {33 return <DialogPrimitive.CloseButton data-slot="dialog-close" {...props} />;34};35
36type DialogOverlayProps<T extends ValidComponent = "div"> = PolymorphicProps<37 T,38 DialogPrimitive.DialogOverlayProps<T>39> &40 Pick<ComponentProps<T>, "class">;41
42const DialogOverlay = <T extends ValidComponent = "div">(props: DialogOverlayProps<T>) => {43 const [local, others] = splitProps(props as DialogOverlayProps, ["class"]);44 return (45 <DialogPrimitive.Overlay46 data-slot="dialog-overlay"47 class={cn("fixed inset-0 isolate z-50 z-dialog-overlay", local.class)}48 {...others}49 />50 );51};52
53type DialogContentProps<T extends ValidComponent = "div"> = PolymorphicProps<54 T,55 DialogPrimitive.DialogContentProps<T>56> &57 Pick<ComponentProps<T>, "class" | "children"> & {58 showCloseButton?: boolean;59 };60
61const DialogContent = <T extends ValidComponent = "div">(props: DialogContentProps<T>) => {62 const mergedProps = mergeProps({ showCloseButton: true } as DialogContentProps, props);63 const [local, others] = splitProps(mergedProps, ["class", "children", "showCloseButton"]);64 return (65 <DialogPortal>66 <DialogOverlay />67 <DialogPrimitive.Content68 data-slot="dialog-content"69 class={cn(70 "fixed top-1/2 left-1/2 z-50 z-dialog-content w-full -translate-x-1/2 -translate-y-1/2 outline-none",71 local.class,72 )}73 {...others}74 >75 {local.children}76 <Show when={local.showCloseButton}>77 <DialogPrimitive.CloseButton78 as={Button}79 variant="ghost"80 size="icon-sm"81 data-slot="dialog-close"82 class="z-dialog-close"83 >84 <X />85 <span class="sr-only">Close</span>86 </DialogPrimitive.CloseButton>87 </Show>88 </DialogPrimitive.Content>89 </DialogPortal>90 );91};92
93type DialogHeaderProps = ComponentProps<"div">;94
95const DialogHeader = (props: DialogHeaderProps) => {96 const [local, others] = splitProps(props, ["class"]);97 return (98 <div99 data-slot="dialog-header"100 class={cn("z-dialog-header flex flex-col", local.class)}101 {...others}102 />103 );104};105
106type DialogFooterProps<T extends ValidComponent = "div"> = PolymorphicProps<107 T,108 ComponentProps<"div">109> &110 Pick<ComponentProps<T>, "class" | "children"> & {111 showCloseButton?: boolean;112 };113
114const DialogFooter = <T extends ValidComponent = "div">(props: DialogFooterProps<T>) => {115 const mergedProps = mergeProps({ showCloseButton: false } as DialogFooterProps, props);116 const [local, others] = splitProps(mergedProps, ["class", "children", "showCloseButton"]);117 return (118 <div119 data-slot="dialog-footer"120 class={cn(121 "z-dialog-footer flex flex-col-reverse gap-2 sm:flex-row sm:justify-end",122 local.class,123 )}124 {...others}125 >126 {local.children}127 <Show when={local.showCloseButton}>128 <DialogPrimitive.CloseButton as={Button} variant="outline">129 Close130 </DialogPrimitive.CloseButton>131 </Show>132 </div>133 );134};135
136type DialogTitleProps<T extends ValidComponent = "h2"> = PolymorphicProps<137 T,138 DialogPrimitive.DialogTitleProps<T>139> &140 Pick<ComponentProps<T>, "class">;141
142const DialogTitle = <T extends ValidComponent = "h2">(props: DialogTitleProps<T>) => {143 const [local, others] = splitProps(props as DialogTitleProps, ["class"]);144 return (145 <DialogPrimitive.Title146 data-slot="dialog-title"147 class={cn("z-dialog-title", local.class)}148 {...others}149 />150 );151};152
153type DialogDescriptionProps<T extends ValidComponent = "p"> = PolymorphicProps<154 T,155 DialogPrimitive.DialogDescriptionProps<T>156> &157 Pick<ComponentProps<T>, "class">;158
159const DialogDescription = <T extends ValidComponent = "p">(props: DialogDescriptionProps<T>) => {160 const [local, others] = splitProps(props as DialogDescriptionProps, ["class"]);161 return (162 <DialogPrimitive.Description163 data-slot="dialog-description"164 class={cn("z-dialog-description", local.class)}165 {...others}166 />167 );168};169
170export {171 Dialog,172 DialogClose,173 DialogContent,174 DialogDescription,175 DialogFooter,176 DialogHeader,177 DialogOverlay,178 DialogPortal,179 DialogTitle,180 DialogTrigger,181};Here are the source code of all the examples from the preview page:
import { Button } from "~/components/ui/button";import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger,} from "~/components/ui/dialog";import { Field, FieldGroup, FieldLabel } from "~/components/ui/field";import { Input } from "~/components/ui/input";function DialogWithForm() { return ( <Example title="With Form" class="items-center justify-center"> <Dialog> <form> <DialogTrigger as={Button} variant="outline"> Edit Profile </DialogTrigger> <DialogContent> <DialogHeader> <DialogTitle>Edit profile</DialogTitle> <DialogDescription> Make changes to your profile here. Click save when you're done. Your profile will be updated immediately. </DialogDescription> </DialogHeader> <FieldGroup> <Field> <FieldLabel for="name-1">Name</FieldLabel> <Input id="name-1" name="name" value="Pedro Duarte" /> </Field> <Field> <FieldLabel for="username-1">Username</FieldLabel> <Input id="username-1" name="username" value="@peduarte" /> </Field> </FieldGroup> <DialogFooter> <DialogClose as={Button} variant="outline"> Cancel </DialogClose> <Button type="submit">Save changes</Button> </DialogFooter> </DialogContent> </form> </Dialog> </Example> );}import { For } from "solid-js";import { Button } from "~/components/ui/button";import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger,} from "~/components/ui/dialog";function DialogScrollableContent() { return ( <Example title="Scrollable Content" class="items-center justify-center"> <Dialog> <DialogTrigger as={Button} variant="outline"> Scrollable Content </DialogTrigger> <DialogContent> <DialogHeader> <DialogTitle>Scrollable Content</DialogTitle> <DialogDescription>This is a dialog with scrollable content.</DialogDescription> </DialogHeader> <div class="max-h-[70vh] overflow-y-auto"> <For each={Array.from({ length: 10 })}> {() => ( <p class="mb-4 leading-normal"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. </p> )} </For> </div> </DialogContent> </Dialog> </Example> );}import { For } from "solid-js";import { Button } from "~/components/ui/button";import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger,} from "~/components/ui/dialog";function DialogWithStickyFooter() { return ( <Example title="With Sticky Footer" class="items-center justify-center"> <Dialog> <DialogTrigger as={Button} variant="outline"> Sticky Footer </DialogTrigger> <DialogContent> <DialogHeader> <DialogTitle>Scrollable Content</DialogTitle> <DialogDescription>This is a dialog with scrollable content.</DialogDescription> </DialogHeader> <div class="max-h-[70vh] overflow-y-auto"> <For each={Array.from({ length: 10 })}> {() => ( <p class="mb-4 leading-normal"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. </p> )} </For> </div> <DialogFooter> <DialogClose as={Button} variant="outline"> Close </DialogClose> </DialogFooter> </DialogContent> </Dialog> </Example> );}import { Button } from "~/components/ui/button";import { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger,} from "~/components/ui/dialog";function DialogNoCloseButton() { return ( <Example title="No Close Button" class="items-center justify-center"> <Dialog> <DialogTrigger as={Button} variant="outline"> No Close Button </DialogTrigger> <DialogContent showCloseButton={false}> <DialogHeader> <DialogTitle>No Close Button</DialogTitle> <DialogDescription> This dialog doesn't have a close button in the top-right corner. </DialogDescription> </DialogHeader> <DialogFooter> <DialogClose as={Button} variant="outline"> Close </DialogClose> </DialogFooter> </DialogContent> </Dialog> </Example> );}import { Info } from "lucide-solid";import { createSignal } from "solid-js";import { Button } from "~/components/ui/button";import { Checkbox } from "~/components/ui/checkbox";import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger,} from "~/components/ui/dialog";import { Field, FieldContent, FieldDescription, FieldGroup, FieldLabel, FieldSeparator, FieldSet, FieldTitle,} from "~/components/ui/field";import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput,} from "~/components/ui/input-group";import { Kbd } from "~/components/ui/kbd";import { NativeSelect, NativeSelectOption } from "~/components/ui/native-select";import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue,} from "~/components/ui/select";import { Switch } from "~/components/ui/switch";import { Tabs, TabsContent, TabsList, TabsTrigger } from "~/components/ui/tabs";import { Textarea } from "~/components/ui/textarea";import { Tooltip, TooltipContent, TooltipTrigger } from "~/components/ui/tooltip";const spokenLanguages = [ { label: "Auto", value: "auto" }, { label: "English", value: "en" }, { label: "Spanish", value: "es" }, { label: "French", value: "fr" }, { label: "German", value: "de" }, { label: "Italian", value: "it" }, { label: "Portuguese", value: "pt" }, { label: "Russian", value: "ru" }, { label: "Chinese", value: "zh" }, { label: "Japanese", value: "ja" }, { label: "Korean", value: "ko" }, { label: "Arabic", value: "ar" }, { label: "Hindi", value: "hi" }, { label: "Bengali", value: "bn" }, { label: "Telugu", value: "te" }, { label: "Marathi", value: "mr" }, { label: "Kannada", value: "kn" }, { label: "Malayalam", value: "ml" },];
const voices = [ { label: "Samantha", value: "samantha" }, { label: "Alex", value: "alex" }, { label: "Fred", value: "fred" }, { label: "Victoria", value: "victoria" }, { label: "Tom", value: "tom" }, { label: "Karen", value: "karen" }, { label: "Sam", value: "sam" }, { label: "Daniel", value: "daniel" },];
const themes = [ { label: "Light", value: "light" }, { label: "Dark", value: "dark" }, { label: "System", value: "system" },];
const accents = [ { label: "Default", value: "default" }, { label: "Red", value: "red" }, { label: "Blue", value: "blue" }, { label: "Green", value: "green" }, { label: "Purple", value: "purple" }, { label: "Pink", value: "pink" },];
function DialogChatSettings() { const [tab, setTab] = createSignal("general"); const [theme, setTheme] = createSignal(themes[2]); const [accentColor, setAccentColor] = createSignal(accents[0]); const [spokenLanguage, setSpokenLanguage] = createSignal(spokenLanguages[1]); const [voice, setVoice] = createSignal(voices[0]);
return ( <Example title="Chat Settings" class="items-center justify-center"> <Dialog> <DialogTrigger as={Button} variant="outline"> Chat Settings </DialogTrigger> <DialogContent class="min-w-md"> <DialogHeader> <DialogTitle>Chat Settings</DialogTitle> <DialogDescription> Customize your chat settings: theme, accent color, spoken language, voice, personality, and custom instructions. </DialogDescription> </DialogHeader> <div class="flex flex-col gap-4"> <NativeSelect value={tab()} onChange={(e) => setTab(e.currentTarget.value)} class="w-full md:hidden" > <NativeSelectOption value="general">General</NativeSelectOption> <NativeSelectOption value="notifications">Notifications</NativeSelectOption> <NativeSelectOption value="personalization">Personalization</NativeSelectOption> <NativeSelectOption value="security">Security</NativeSelectOption> </NativeSelect> <Tabs value={tab()} onChange={setTab}> <TabsList class="hidden w-full md:flex"> <TabsTrigger value="general">General</TabsTrigger> <TabsTrigger value="notifications">Notifications</TabsTrigger> <TabsTrigger value="personalization">Personalization</TabsTrigger> <TabsTrigger value="security">Security</TabsTrigger> </TabsList> <div class="min-h-[450px] rounded-lg border p-4 [&_[data-slot=select-trigger]]:min-w-[125px]"> <TabsContent value="general"> <FieldSet> <FieldGroup> <Field orientation="horizontal"> <FieldLabel for="theme">Theme</FieldLabel> <Select options={themes} optionValue="value" optionTextValue="label" value={theme()} onChange={setTheme} itemComponent={(props) => ( <SelectItem item={props.item}>{props.item.rawValue.label}</SelectItem> )} > <SelectTrigger id="theme"> <SelectValue<(typeof themes)[number]>> {(state) => state.selectedOption().label} </SelectValue> </SelectTrigger> <SelectContent /> </Select> </Field> <FieldSeparator /> <Field orientation="horizontal"> <FieldLabel for="accent-color">Accent Color</FieldLabel> <Select options={accents} optionValue="value" optionTextValue="label" value={accentColor()} onChange={setAccentColor} itemComponent={(props) => ( <SelectItem item={props.item}>{props.item.rawValue.label}</SelectItem> )} > <SelectTrigger id="accent-color"> <SelectValue<(typeof accents)[number]>> {(state) => state.selectedOption().label} </SelectValue> </SelectTrigger> <SelectContent /> </Select> </Field> <FieldSeparator /> <Field orientation="responsive"> <FieldContent> <FieldLabel for="spoken-language">Spoken Language</FieldLabel> <FieldDescription> For best results, select the language you mainly speak. If it's not listed, it may still be supported via auto-detection. </FieldDescription> </FieldContent> <Select options={spokenLanguages} optionValue="value" optionTextValue="label" value={spokenLanguage()} onChange={setSpokenLanguage} itemComponent={(props) => ( <SelectItem item={props.item}>{props.item.rawValue.label}</SelectItem> )} > <SelectTrigger id="spoken-language"> <SelectValue<(typeof spokenLanguages)[number]>> {(state) => state.selectedOption().label} </SelectValue> </SelectTrigger> <SelectContent /> </Select> </Field> <FieldSeparator /> <Field orientation="horizontal"> <FieldLabel for="voice">Voice</FieldLabel> <Select options={voices} optionValue="value" optionTextValue="label" value={voice()} onChange={setVoice} itemComponent={(props) => ( <SelectItem item={props.item}>{props.item.rawValue.label}</SelectItem> )} > <SelectTrigger id="voice"> <SelectValue<(typeof voices)[number]>> {(state) => state.selectedOption().label} </SelectValue> </SelectTrigger> <SelectContent /> </Select> </Field> </FieldGroup> </FieldSet> </TabsContent> <TabsContent value="notifications"> <FieldGroup> <FieldSet> <FieldLabel>Responses</FieldLabel> <FieldDescription> Get notified when ChatGPT responds to requests that take time, like research or image generation. </FieldDescription> <FieldGroup data-slot="checkbox-group"> <Field orientation="horizontal"> <Checkbox id="push" defaultChecked disabled /> <FieldLabel for="push" class="font-normal"> Push notifications </FieldLabel> </Field> </FieldGroup> </FieldSet> <FieldSeparator /> <FieldSet> <FieldLabel>Tasks</FieldLabel> <FieldDescription> Get notified when tasks you've created have updates.{" "} <a href="#">Manage tasks</a> </FieldDescription> <FieldGroup data-slot="checkbox-group"> <Field orientation="horizontal"> <Checkbox id="push-tasks" /> <FieldLabel for="push-tasks" class="font-normal"> Push notifications </FieldLabel> </Field> <Field orientation="horizontal"> <Checkbox id="email-tasks" /> <FieldLabel for="email-tasks" class="font-normal"> Email notifications </FieldLabel> </Field> </FieldGroup> </FieldSet> </FieldGroup> </TabsContent> <TabsContent value="personalization"> <FieldGroup> <Field orientation="responsive"> <FieldLabel for="nickname">Nickname</FieldLabel> <InputGroup> <InputGroupInput id="nickname" placeholder="Broski" class="@md/field-group:max-w-[200px]" /> <InputGroupAddon align="inline-end"> <Tooltip> <TooltipTrigger as={InputGroupButton} size="icon-xs"> <Info /> </TooltipTrigger> <TooltipContent class="flex items-center gap-2"> Used to identify you in the chat. <Kbd>N</Kbd> </TooltipContent> </Tooltip> </InputGroupAddon> </InputGroup> </Field> <FieldSeparator /> <Field orientation="responsive" class="@2xl/field-group:flex-row @md/field-group:flex-col" > <FieldContent> <FieldLabel for="about">More about you</FieldLabel> <FieldDescription> Tell us more about yourself. This will be used to help us personalize your experience. </FieldDescription> </FieldContent> <Textarea id="about" placeholder="I'm a software engineer..." class="min-h-[120px] @2xl/field-group:min-w-[300px] @md/field-group:min-w-full" /> </Field> <FieldSeparator /> <FieldLabel> <Field orientation="horizontal"> <FieldContent> <FieldLabel for="customization">Enable customizations</FieldLabel> <FieldDescription> Enable customizations to make ChatGPT more personalized. </FieldDescription> </FieldContent> <Switch id="customization" defaultChecked /> </Field> </FieldLabel> </FieldGroup> </TabsContent> <TabsContent value="security"> <FieldGroup> <Field orientation="horizontal"> <FieldContent> <FieldLabel for="2fa">Multi-factor authentication</FieldLabel> <FieldDescription> Enable multi-factor authentication to secure your account. If you do not have a two-factor authentication device, you can use a one-time code sent to your email. </FieldDescription> </FieldContent> <Switch id="2fa" /> </Field> <FieldSeparator /> <Field orientation="horizontal"> <FieldContent> <FieldTitle>Log out</FieldTitle> <FieldDescription>Log out of your account on this device.</FieldDescription> </FieldContent> <Button variant="outline" size="sm"> Log Out </Button> </Field> <FieldSeparator /> <Field orientation="horizontal"> <FieldContent> <FieldTitle>Log out of all devices</FieldTitle> <FieldDescription> This will log you out of all devices, including the current session. It may take up to 30 minutes for the changes to take effect. </FieldDescription> </FieldContent> <Button variant="outline" size="sm"> Log Out All </Button> </Field> </FieldGroup> </TabsContent> </div> </Tabs> </div> </DialogContent> </Dialog> </Example> );}To use the Dialog component from within a Context Menu or Dropdown Menu, you must encase the Context Menu or
Dropdown Menu component in the Dialog component.
1<Dialog>2 <ContextMenu>3 <ContextMenuTrigger>Right click</ContextMenuTrigger>4 <ContextMenuContent>5 <ContextMenuItem>Open</ContextMenuItem>6 <ContextMenuItem>Download</ContextMenuItem>7 <DialogTrigger as={ContextMenuItem}>8 <span>Delete</span>9 </DialogTrigger>10 </ContextMenuContent>11 </ContextMenu>12 <DialogContent>13 <DialogHeader>14 <DialogTitle>Are you absolutely sure?</DialogTitle>15 <DialogDescription>16 This action cannot be undone. Are you sure you want to permanently17 delete this file from our servers?18 </DialogDescription>19 </DialogHeader>20 <DialogFooter>21 <Button type="submit">Confirm</Button>22 </DialogFooter>23 </DialogContent>24</Dialog>