diff --git a/apps/v4/content/docs/components/base/drawer.mdx b/apps/v4/content/docs/components/base/drawer.mdx index 0b46bcbb000..ab5f0086545 100644 --- a/apps/v4/content/docs/components/base/drawer.mdx +++ b/apps/v4/content/docs/components/base/drawer.mdx @@ -122,6 +122,25 @@ You can combine the `Dialog` and `Drawer` components to create a responsive dial +### Non-modal Drawer + +By default, the Drawer traps focus inside when open and blocks interaction with the rest of the page. To allow users to focus inputs or interact with elements outside the drawer while it remains open, set `modal={false}` on `` and `showOverlay={false}` on ``. + + + +```tsx showLineNumbers + + + + + + {/* ... */} + + +``` + +`modal={false}` disables vaul's focus trap so keyboard focus can leave the drawer freely. `showOverlay={false}` removes the backdrop so the rest of the page remains fully visible and clickable. + ## RTL To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl). diff --git a/apps/v4/content/docs/components/radix/drawer.mdx b/apps/v4/content/docs/components/radix/drawer.mdx index b70f39079d3..3d7431f3f1d 100644 --- a/apps/v4/content/docs/components/radix/drawer.mdx +++ b/apps/v4/content/docs/components/radix/drawer.mdx @@ -122,6 +122,25 @@ You can combine the `Dialog` and `Drawer` components to create a responsive dial +### Non-modal Drawer + +By default, the Drawer traps focus inside when open and blocks interaction with the rest of the page. To allow users to focus inputs or interact with elements outside the drawer while it remains open, set `modal={false}` on `` and `showOverlay={false}` on ``. + + + +```tsx showLineNumbers + + + + + + {/* ... */} + + +``` + +`modal={false}` disables vaul's focus trap so keyboard focus can leave the drawer freely. `showOverlay={false}` removes the backdrop so the rest of the page remains fully visible and clickable. + ## RTL To enable RTL support in shadcn/ui, see the [RTL configuration guide](/docs/rtl). diff --git a/apps/v4/examples/__index__.tsx b/apps/v4/examples/__index__.tsx index 6bda3d78c04..f2285b4310a 100644 --- a/apps/v4/examples/__index__.tsx +++ b/apps/v4/examples/__index__.tsx @@ -2217,6 +2217,19 @@ export const ExamplesIndex: Record> = { return { default: mod.default || mod[exportName] } }), }, + "drawer-non-modal": { + name: "drawer-non-modal", + filePath: "examples/radix/drawer-non-modal.tsx", + component: React.lazy(async () => { + const mod = await import("./radix/drawer-non-modal") + const exportName = + Object.keys(mod).find( + (key) => + typeof mod[key] === "function" || typeof mod[key] === "object" + ) || "drawer-non-modal" + return { default: mod.default || mod[exportName] } + }), + }, "drawer-rtl": { name: "drawer-rtl", filePath: "examples/radix/drawer-rtl.tsx", @@ -7874,6 +7887,19 @@ export const ExamplesIndex: Record> = { return { default: mod.default || mod[exportName] } }), }, + "drawer-non-modal": { + name: "drawer-non-modal", + filePath: "examples/base/drawer-non-modal.tsx", + component: React.lazy(async () => { + const mod = await import("./base/drawer-non-modal") + const exportName = + Object.keys(mod).find( + (key) => + typeof mod[key] === "function" || typeof mod[key] === "object" + ) || "drawer-non-modal" + return { default: mod.default || mod[exportName] } + }), + }, "drawer-rtl": { name: "drawer-rtl", filePath: "examples/base/drawer-rtl.tsx", diff --git a/apps/v4/examples/base/drawer-non-modal.tsx b/apps/v4/examples/base/drawer-non-modal.tsx new file mode 100644 index 00000000000..fdefa96c5c5 --- /dev/null +++ b/apps/v4/examples/base/drawer-non-modal.tsx @@ -0,0 +1,55 @@ +"use client" + +import * as React from "react" + +import { Button } from "@/styles/base-nova/ui/button" +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/styles/base-nova/ui/drawer" +import { Input } from "@/styles/base-nova/ui/input" +import { Label } from "@/styles/base-nova/ui/label" + +export function DrawerNonModal() { + const [open, setOpen] = React.useState(false) + + return ( +
+
+ + +
+ + + + + + + Non-modal Drawer + + You can still interact with content outside this drawer. + + +
+ + +
+ + + + + +
+
+
+ ) +} diff --git a/apps/v4/examples/radix/drawer-non-modal.tsx b/apps/v4/examples/radix/drawer-non-modal.tsx new file mode 100644 index 00000000000..7b93050d2c0 --- /dev/null +++ b/apps/v4/examples/radix/drawer-non-modal.tsx @@ -0,0 +1,55 @@ +"use client" + +import * as React from "react" + +import { Button } from "@/styles/radix-nova/ui/button" +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/styles/radix-nova/ui/drawer" +import { Input } from "@/styles/radix-nova/ui/input" +import { Label } from "@/styles/radix-nova/ui/label" + +export function DrawerNonModal() { + const [open, setOpen] = React.useState(false) + + return ( +
+
+ + +
+ + + + + + + Non-modal Drawer + + You can still interact with content outside this drawer. + + +
+ + +
+ + + + + +
+
+
+ ) +} diff --git a/apps/v4/public/r/styles/base-luma/drawer.json b/apps/v4/public/r/styles/base-luma/drawer.json index e286adaecae..aeb92deb08e 100644 --- a/apps/v4/public/r/styles/base-luma/drawer.json +++ b/apps/v4/public/r/styles/base-luma/drawer.json @@ -7,7 +7,7 @@ "files": [ { "path": "registry/base-luma/ui/drawer.tsx", - "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Drawer as DrawerPrimitive } from \"vaul\"\n\nimport { cn } from \"@/registry/base-luma/lib/utils\"\n\nfunction Drawer({\n ...props\n}: React.ComponentProps) {\n return \n}\n\nfunction DrawerTrigger({\n ...props\n}: React.ComponentProps) {\n return \n}\n\nfunction DrawerPortal({\n ...props\n}: React.ComponentProps) {\n return \n}\n\nfunction DrawerClose({\n ...props\n}: React.ComponentProps) {\n return \n}\n\nfunction DrawerOverlay({\n className,\n ...props\n}: React.ComponentProps) {\n return (\n \n )\n}\n\nfunction DrawerContent({\n className,\n children,\n ...props\n}: React.ComponentProps) {\n return (\n \n \n \n