Sheet
A dialog that slides from an edge of the viewport.
- Chromium
- Firefox
- WebKit
- WCAG 2.2 AA
Preview
import { Button } from "@moe-ui/registry/components/ui/button";
import { Input } from "@moe-ui/registry/components/ui/input";
import { Label } from "@moe-ui/registry/components/ui/label";
import {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetTitle,
SheetTrigger,
} from "@moe-ui/registry/components/ui/sheet";
import { Text } from "@moe-ui/registry/components/ui/text";
import { View } from "react-native";
export default function SheetPreview() {
return (
<Sheet>
<SheetTrigger asChild>
<Button variant="outline">
<Text>Open</Text>
</Button>
</SheetTrigger>
<SheetContent>
<SheetHeader>
<SheetTitle>Edit profile</SheetTitle>
<SheetDescription>
Make changes to your profile here. Click save when you’re done.
</SheetDescription>
</SheetHeader>
<View className="grid gap-4 py-4">
<View className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="name" className="text-right">
Name
</Label>
<Input
id="name"
defaultValue="Pedro Duarte"
className="col-span-3"
/>
</View>
<View className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="username" className="text-right">
Username
</Label>
<Input
id="username"
defaultValue="@peduarte"
className="col-span-3"
/>
</View>
</View>
<SheetFooter>
<SheetClose asChild>
<Button>
<Text>Save changes</Text>
</Button>
</SheetClose>
</SheetFooter>
</SheetContent>
</Sheet>
);
}
One command, your source
Installation
pnpm dlx @moe-ui/cli@beta add sheetUsage
The CLI installs editable source into your application. Import the component from your configured UI directory:
import { Sheet } from "@/components/ui/sheet";Variants and composition
Compound parts and variants remain regular source in your project, so you can change them without wrapping a package API.
Public API
The canonical source panel below lists every public export, dependency, and the complete implementation shipped by the registry.
Keyboard and accessibility
The trigger is keyboard reachable, Escape dismisses the surface, and focus returns to the trigger. Modal surfaces keep focus within the active layer.
Browser support
This beta is release-tested in Chromium, Firefox, and WebKit in light and dark themes. See the web compatibility matrix for the current gate.
Nothing hiddenCanonical source and public exports10 exports
SheetSheetCloseSheetContentSheetDescriptionSheetFooterSheetHeaderSheetOverlaySheetPortalSheetTitleSheetTrigger"use client";
import * as SheetPrimitive from "@rn-primitives/dialog";
import * as React from "react";
import { Platform, StyleSheet, View } from "react-native";
import Animated, { FadeIn, FadeOut } from "react-native-reanimated";
import { X } from "lucide-react-native";
import { cn } from "../../lib/utils";
const Sheet = SheetPrimitive.Root;
const SheetTrigger = SheetPrimitive.Trigger;
const SheetClose = SheetPrimitive.Close;
const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
>(({ className, ...props }, ref) => {
return (
<SheetPrimitive.Overlay
style={StyleSheet.absoluteFill}
className={cn(
"z-50 flex items-stretch justify-start bg-black/80 p-0",
className,
)}
{...props}
ref={ref}
>
{Platform.OS === "web" ? (
(props.children as React.ReactNode)
) : (
<Animated.View
entering={FadeIn.duration(150)}
exiting={FadeOut.duration(150)}
>
{props.children as React.ReactNode}
</Animated.View>
)}
</SheetPrimitive.Overlay>
);
});
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const SheetContent = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content> & {
portalHost?: string;
side?: "top" | "bottom" | "left" | "right";
}
>(({ className, children, portalHost, side = "right", ...props }, ref) => {
return (
<SheetPortal hostName={portalHost}>
<SheetOverlay>
<SheetPrimitive.Content
ref={ref}
className={cn(
"border-border bg-background z-50 ml-auto h-screen w-3/4 gap-4 border-l p-6 shadow-lg sm:max-w-sm web:cursor-default",
side === "right" && "border-l",
side === "bottom" && "mt-auto h-auto w-full border-t",
className,
)}
{...props}
>
{children}
<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 size={18} className="text-muted-foreground" />
<span className="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetOverlay>
</SheetPortal>
);
});
SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
...props
}: React.ComponentPropsWithoutRef<typeof View>) => (
<View
className={cn(
"flex flex-col space-y-2 text-center sm:text-left",
className,
)}
{...props}
/>
);
SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
...props
}: React.ComponentPropsWithoutRef<typeof View>) => (
<View
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Title
ref={ref}
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
));
SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef<typeof SheetPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
>(({ className, ...props }, ref) => (
<SheetPrimitive.Description
ref={ref}
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
));
SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
SheetClose,
SheetContent,
SheetDescription,
SheetFooter,
SheetHeader,
SheetOverlay,
SheetPortal,
SheetTitle,
SheetTrigger,
};