Sheet
Slide-over panel from the edge of the screen. Install Sheet from the VLLNT UI registry with the shadcn CLI.
Slide-over panel from the edge of the screen. Part of the overlay family in VLLNT UI, it ships as a machine-readable registry entry — copy the source directly into your app with the shadcn CLI and own it, no runtime dependency on a component library.
Preview
Switch between light and dark to inspect the embedded Storybook preview.
Installation
Add Sheet to your project with the shadcn CLI. The source lands in your codebase, ready to adapt:
pnpm dlx shadcn@latest add https://ui.vllnt.ai/r/sheet.jsonSource
"use client";
import * as SheetPrimitive from "@radix-ui/react-dialog";
import { cva, type VariantProps } from "class-variance-authority";
import { X } from "lucide-react";
import { cn } from "../../lib/utils";
const Sheet = SheetPrimitive.Root;
const SheetTrigger = SheetPrimitive.Trigger;
const SheetClose = SheetPrimitive.Close;
const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = ({
className,
ref,
...props
}: React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay> & {
ref?: React.Ref<React.ComponentRef<typeof SheetPrimitive.Overlay>>;
}) => (
<SheetPrimitive.Overlay
className={cn(
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
className,
)}
{...props}
ref={ref}
/>
);
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
{
defaultVariants: {
side: "right",
},
variants: {
side: {
bottom:
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right:
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
},
},
},
);
type SheetContentProps = {} & React.ComponentPropsWithoutRef<
typeof SheetPrimitive.Content
> &
VariantProps<typeof sheetVariants>;
const SheetContent = ({
children,
className,
ref,
side = "right",
...props
}: SheetContentProps & {
ref?: React.Ref<React.ComponentRef<typeof SheetPrimitive.Content>>;
}) => (
<SheetPortal>
<SheetOverlay />
<SheetPrimitive.Content
className={cn(sheetVariants({ side }), className)}
ref={ref}
{...props}
>
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
<X className="size-4" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
{children}
</SheetPrimitive.Content>
</SheetPortal>
);
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className,
)}
{...props}
/>
);
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
SheetFooter.displayName = "SheetFooter";
const SheetTitle = ({
className,
ref,
...props
}: React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title> & {
ref?: React.Ref<React.ComponentRef<typeof SheetPrimitive.Title>>;
}) => (
<SheetPrimitive.Title
className={cn("text-lg font-semibold text-foreground", className)}
ref={ref}
{...props}
/>
);
SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = ({
className,
ref,
...props
}: React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description> & {
ref?: React.Ref<React.ComponentRef<typeof SheetPrimitive.Description>>;
}) => (
<SheetPrimitive.Description
className={cn("text-sm text-muted-foreground", className)}
ref={ref}
{...props}
/>
);
SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetOverlay,
SheetPortal,
SheetTitle,
SheetTrigger,
};
Stories
Explore every variant and state in the interactive Storybook:
Preview
Switch between light and dark to inspect the embedded Storybook preview.