Docs
Drawer
Drawer
A draggable dialog that is attached to any side of the viewport.
import { Button } from "@repo/tailwindcss/ui/button";
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerLabel,
DrawerTrigger,
} from "@repo/tailwindcss/ui/drawer";
import { createSignal } from "solid-js";
const DrawerDemo = () => {
const [goal, setGoal] = createSignal(350);
const onClick = (adjustment: number) => {
setGoal(Math.max(200, Math.min(400, goal() + adjustment)));
};
return (
<Drawer>
<DrawerTrigger as={Button} variant="outline">
Open Drawer
</DrawerTrigger>
<DrawerContent>
<div class="mx-auto w-full max-w-sm">
<DrawerHeader>
<DrawerLabel>Move Goal</DrawerLabel>
<DrawerDescription>Set your daily activity goal.</DrawerDescription>
</DrawerHeader>
<div class="p-4 pb-0">
<div class="flex items-center justify-center space-x-2">
<Button
variant="outline"
size="icon"
class="h-8 w-8 shrink-0 rounded-full"
onClick={() => onClick(-10)}
disabled={goal() <= 200}
>
<svg
class="h-4 w-4"
stroke-width="1.5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 12H18"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span class="sr-only">Decrease</span>
</Button>
<div class="flex-1 text-center">
<div class="text-7xl font-bold tracking-tighter">{goal()}</div>
<div class="text-[0.70rem] uppercase text-muted-foreground">
Calories/day
</div>
</div>
<Button
variant="outline"
size="icon"
class="h-8 w-8 shrink-0 rounded-full"
onClick={() => onClick(10)}
disabled={goal() >= 400}
>
<svg
class="h-4 w-4"
stroke-width="1.5"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6 12H12M18 12H12M12 12V6M12 12V18"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
<span class="sr-only">Increase</span>
</Button>
</div>
</div>
<DrawerFooter>
<Button>Submit</Button>
<DrawerClose as={Button} variant="outline">
Cancel
</DrawerClose>
</DrawerFooter>
</div>
</DrawerContent>
</Drawer>
);
};
export default DrawerDemo;
Installation
npx shadcn-solid@latest add drawer
Install the following dependencies:
npm install @corvu/drawer
Copy and paste the following code into your project:
import { cn } from "@/libs/cn";
import type {
ContentProps,
DescriptionProps,
DynamicProps,
LabelProps,
} from "@corvu/drawer";
import DrawerPrimitive from "@corvu/drawer";
import type { ComponentProps, ParentProps, ValidComponent } from "solid-js";
import { splitProps } from "solid-js";
export const Drawer = DrawerPrimitive;
export const DrawerTrigger = DrawerPrimitive.Trigger;
export const DrawerClose = DrawerPrimitive.Close;
type drawerContentProps<T extends ValidComponent = "div"> = ParentProps<
ContentProps<T> & {
class?: string;
}
>;
export const DrawerContent = <T extends ValidComponent = "div">(
props: DynamicProps<T, drawerContentProps<T>>,
) => {
const [local, rest] = splitProps(props as drawerContentProps, [
"class",
"children",
]);
const ctx = DrawerPrimitive.useContext();
return (
<DrawerPrimitive.Portal>
<DrawerPrimitive.Overlay
class="fixed inset-0 z-50 data-[transitioning]:transition-colors data-[transitioning]:duration-200"
style={{
"background-color": `hsl(var(--background) / ${0.8 * ctx.openPercentage()})`,
}}
/>
<DrawerPrimitive.Content
class={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-xl border bg-background after:absolute after:inset-x-0 after:top-full after:h-[50%] after:bg-inherit data-[transitioning]:transition-transform data-[transitioning]:duration-200 md:select-none",
local.class,
)}
{...rest}
>
<div class="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{local.children}
</DrawerPrimitive.Content>
</DrawerPrimitive.Portal>
);
};
export const DrawerHeader = (props: ComponentProps<"div">) => {
const [local, rest] = splitProps(props, ["class"]);
return (
<div
class={cn("grid gap-1.5 p-4 text-center sm:text-left", local.class)}
{...rest}
/>
);
};
export const DrawerFooter = (props: ComponentProps<"div">) => {
const [local, rest] = splitProps(props, ["class"]);
return (
<div class={cn("mt-auto flex flex-col gap-2 p-4", local.class)} {...rest} />
);
};
type DrawerLabelProps = LabelProps & {
class?: string;
};
export const DrawerLabel = <T extends ValidComponent = "h2">(
props: DynamicProps<T, DrawerLabelProps>,
) => {
const [local, rest] = splitProps(props as DrawerLabelProps, ["class"]);
return (
<DrawerPrimitive.Label
class={cn(
"text-lg font-semibold leading-none tracking-tight",
local.class,
)}
{...rest}
/>
);
};
type DrawerDescriptionProps = DescriptionProps & {
class?: string;
};
export const DrawerDescription = <T extends ValidComponent = "p">(
props: DynamicProps<T, DrawerDescriptionProps>,
) => {
const [local, rest] = splitProps(props as DrawerDescriptionProps, ["class"]);
return (
<DrawerPrimitive.Description
class={cn("text-sm text-muted-foreground", local.class)}
{...rest}
/>
);
};
Install the following dependencies:
npm install @corvu/drawer
Copy and paste the following code into your project:
import { cn } from "@/libs/cn";
import type {
ContentProps,
DescriptionProps,
DynamicProps,
LabelProps,
} from "@corvu/drawer";
import DrawerPrimitive from "@corvu/drawer";
import type { ComponentProps, ParentProps, ValidComponent } from "solid-js";
import { splitProps } from "solid-js";
export const Drawer = DrawerPrimitive;
export const DrawerTrigger = DrawerPrimitive.Trigger;
export const DrawerClose = DrawerPrimitive.Close;
type drawerContentProps<T extends ValidComponent = "div"> = ParentProps<
ContentProps<T> & {
class?: string;
}
>;
export const DrawerContent = <T extends ValidComponent = "div">(
props: DynamicProps<T, drawerContentProps<T>>,
) => {
const [local, rest] = splitProps(props as drawerContentProps, [
"class",
"children",
]);
const ctx = DrawerPrimitive.useContext();
return (
<DrawerPrimitive.Portal>
<DrawerPrimitive.Overlay
class="fixed inset-0 z-50 data-[transitioning]:(transition-colors duration-200)"
style={{
"background-color": `hsl(var(--background) / ${0.8 * ctx.openPercentage()})`,
}}
/>
<DrawerPrimitive.Content
class={cn(
"fixed inset-x-0 bottom-0 z-50 mt-24 flex h-auto flex-col rounded-t-xl border bg-background after:(absolute inset-x-0 top-full h-[50%] bg-inherit) data-[transitioning]:(transition-transform duration-200) md:select-none",
local.class,
)}
{...rest}
>
<div class="mx-auto mt-4 h-2 w-[100px] rounded-full bg-muted" />
{local.children}
</DrawerPrimitive.Content>
</DrawerPrimitive.Portal>
);
};
export const DrawerHeader = (props: ComponentProps<"div">) => {
const [local, rest] = splitProps(props, ["class"]);
return (
<div
class={cn("grid gap-1.5 p-4 text-center sm:text-left", local.class)}
{...rest}
/>
);
};
export const DrawerFooter = (props: ComponentProps<"div">) => {
const [local, rest] = splitProps(props, ["class"]);
return (
<div class={cn("mt-auto flex flex-col gap-2 p-4", local.class)} {...rest} />
);
};
type DrawerLabelProps = LabelProps & {
class?: string;
};
export const DrawerLabel = <T extends ValidComponent = "h2">(
props: DynamicProps<T, DrawerLabelProps>,
) => {
const [local, rest] = splitProps(props as DrawerLabelProps, ["class"]);
return (
<DrawerPrimitive.Label
class={cn(
"text-lg font-semibold leading-none tracking-tight",
local.class,
)}
{...rest}
/>
);
};
type DrawerDescriptionProps = DescriptionProps & {
class?: string;
};
export const DrawerDescription = <T extends ValidComponent = "p">(
props: DynamicProps<T, DrawerDescriptionProps>,
) => {
const [local, rest] = splitProps(props as DrawerDescriptionProps, ["class"]);
return (
<DrawerPrimitive.Description
class={cn("text-sm text-muted-foreground", local.class)}
{...rest}
/>
);
};
Usage
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerLabel,
DrawerTrigger
} from "@/components/ui/drawer";
<Drawer>
<DrawerTrigger>Open</DrawerTrigger>
<DrawerContent>
<DialogHeader>
<DrawerLabel>Are you sure absolutely sure?</DrawerLabel>
<DialogDescription>
This action cannot be undone. This will permanently delete your account and remove your data
from our servers.
</DialogDescription>
</DialogHeader>
</DrawerContent>
</Drawer>