Theme Switcher

Sheet

A container that overlays the current view from the edge of the screen. It is a lightweight way of allowing users to complete a task without losing contextual information of the view beneath it.

import { Button, IconButton } from "@ngrok/mantle/button";
import { Separator } from "@ngrok/mantle/separator";
import {
	Sheet,
	SheetActions,
	SheetBody,
	SheetClose,
	SheetCloseIconButton,
	SheetContent,
	SheetDescription,
	SheetFooter,
	SheetHeader,
	SheetTitle,
	SheetTitleGroup,
	SheetTrigger,
} from "@ngrok/mantle/sheet";
import { ListMagnifyingGlass } from "@phosphor-icons/react/ListMagnifyingGlass";
import { TerminalWindow } from "@phosphor-icons/react/TerminalWindow";
import { TrashSimple } from "@phosphor-icons/react/TrashSimple";

<Sheet>
	<SheetTrigger asChild>
		<Button type="button" appearance="filled">Open Sheet</Button>
	</SheetTrigger>
	<SheetContent>
		<SheetHeader>
			<SheetTitleGroup>
				<SheetTitle>Are you absolutely sure?</SheetTitle>
				<SheetActions>
					<IconButton appearance="ghost" type="button" icon={<TerminalWindow />} label="Start a Tunnel" />
					<IconButton appearance="ghost" type="button" icon={<ListMagnifyingGlass />} label="See Traffic" />
					<IconButton appearance="ghost" type="button" icon={<TrashSimple />} label="Delete" />
					<Separator orientation="vertical" className="h-[80%]" />
					<SheetCloseIconButton />
				</SheetActions>
			</SheetTitleGroup>
			<SheetDescription>
				This action cannot be undone. This will permanently delete your account and remove your data from our
				servers.
			</SheetDescription>
		</SheetHeader>
		<SheetBody className="space-y-4">
			<p>
				Lorem ipsum
			</p>
		</SheetBody>
		<SheetFooter>
			<SheetClose asChild>
				<Button type="button">Close</Button>
			</SheetClose>
		</SheetFooter>
	</SheetContent>
</Sheet>

Examples

Router or state management controlled Sheet

You can control when to render a Sheet with a router or via outside state management. This will allow you to open and close the Sheet programmatically without using a SheetTrigger.

import { Button } from "@ngrok/mantle/button";
import {
	Sheet,
	SheetActions,
	SheetBody,
	SheetClose,
	SheetCloseIconButton,
	SheetContent,
	SheetDescription,
	SheetFooter,
	SheetHeader,
	SheetTitle,
	SheetTitleGroup,
	SheetTrigger,
} from "@ngrok/mantle/sheet";
import { useNavigate } from "react-router";

// this is a react-router route module component export
export default function Component() {
	const navigate = useNavigate();

	return (
		<Sheet open onOpenChange={() => navigate("..")}>
			<SheetContent>
				<SheetHeader>
					<SheetTitleGroup>
						<SheetTitle>A controlled Sheet</SheetTitle>
						<SheetActions>
							<SheetCloseIconButton />
						</SheetActions>
					</SheetTitleGroup>
					<SheetDescription>
						This sheet is controlled by a router or state manager.
					</SheetDescription>
				</SheetHeader>
				<SheetBody>
					<p>
						Consequat do voluptate culpa fugiat consequat nostrud duis
						aliqua minim. Tempor voluptate cillum elit velit. Voluptate
						aliqua ipsum aliqua dolore in nisi ea fugiat aliqua velit
						proident amet.
					</p>
				</SheetBody>
				<SheetFooter>
					<SheetFooter>
						<SheetClose asChild>
							<Button type="button">Close</Button>
						</SheetClose>
					</SheetFooter>
				</SheetFooter>
			</SheetContent>
		</Sheet>
	);
}

Setting a preferred width of the Sheet

By default, a Sheet's content width is responsive with a default preferred width: the maximum width of the SheetContent when the window viewport is larger than the mobile breakpoint (sm). You can control the preferred width of the SheetContent by using the preferredWidth prop:

import { Button } from "@ngrok/mantle/button";
import {
	Sheet,
	SheetActions,
	SheetBody,
	SheetClose,
	SheetCloseIconButton,
	SheetContent,
	SheetFooter,
	SheetHeader,
	SheetTitle,
	SheetTitleGroup,
	SheetTrigger,
} from "@ngrok/mantle/sheet";

<Sheet>
	<SheetTrigger asChild>
		<Button type="button" appearance="filled">
			Open 800px wide Sheet
		</Button>
	</SheetTrigger>
	{/* using the 👇 `preferredWidth` prop */}
	<SheetContent preferredWidth="sm:max-w-[800px]">
		<SheetHeader>
			<SheetTitleGroup>
				<SheetTitle>
					Tempor pariatur fugiat fugiat cupidatat velit.
				</SheetTitle>
				<SheetActions>
					<SheetCloseIconButton />
				</SheetActions>
			</SheetTitleGroup>
		</SheetHeader>
		<SheetBody className="space-y-4">
			<p>
				Consequat do voluptate culpa fugiat consequat nostrud duis
				aliqua minim. Tempor voluptate cillum elit velit.
				Voluptate aliqua ipsum aliqua dolore in nisi ea fugiat
				aliqua velit proident amet.
			</p>
		</SheetBody>
		<SheetFooter>
			<SheetClose asChild>
				<Button type="button">Close</Button>
			</SheetClose>
			<Button type="button" appearance="filled">
				Save
			</Button>
		</SheetFooter>
	</SheetContent>
</Sheet>

API Reference

The Sheet components are built on top of Radix Dialog.

Sheet

The root component for a Sheet. Should compose the SheetTrigger and SheetContent. Acts as a stateful provider for the Sheet's open/closed state.

All props from Radix Dialog.Root.

SheetTrigger

The button trigger for a Sheet. Should be rendered as a child of the Sheet component. Renders an unstyled button by default, but can be customized with the asChild prop.

All props from Radix Dialog.Trigger.

SheetClose

The close button for a Sheet. Should be rendered as a child of the SheetContent component. Usually contained within the SheetFooter component. Renders an unstyled button by default, but can be customized with the asChild prop.

Radix Dialog.Close props.

SheetContent

The main container for a Sheet. Should be rendered as a child of the Sheet component. Renders on top of the overlay backdrop. Should contain the SheetHeader, SheetBody, and SheetFooter.

All props from Radix Dialog.Content, plus:

PropTypeDefaultDescription
preferredWidth
stringsm:max-w-[30rem]

The preferred width of the SheetContent as a tailwind max-w- class.

By default, a Sheet's content width is responsive with a default preferred width: the maxiumum width of the SheetContent when the window viewport is larger than the mobile breakpoint (sm).

side
  • top
  • bottom
  • left
  • right
right

The side of the screen from which the sheet will animate in from.

SheetCloseIconButton

An icon button that closes the Sheet when clicked. Should be rendered within the SheetHeader as a child of SheetActions.

Same props as the Mantle IconButton.

SheetBody

The body container for a Sheet. This is where you would typically place the main content of the sheet, such as forms or text. Should be rendered as a child of SheetContent.

All props from div.

SheetHeader

The header container for a Sheet. This is where you would typically place the title, description, and actions. Should be rendered as a child of SheetContent.

All props from div.

The footer container for a Sheet. This is where you would typically place close and submit buttons. Should be rendered as a child ofSheetContent.

All props from div.

SheetTitle

The title for a Sheet. Typically rendered as a child of SheetTitleGroup. Defaults to an h2 element, but can be changed via the asChild prop.

All props from Radix Dialog.Title.

SheetTitleGroup

A group container for the title and actions of a Sheet. Typically rendered as a child of SheetHeader.

All props from div.

SheetDescription

A description for a Sheet. Typically rendered as a child of SheetHeader.

All props from Radix Dialog.Description.

SheetActions

A group container for the actions of a Sheet. Typically rendered as a child of SheetTitleGroup.

All props from div.