# Modal A dialog overlay component for displaying focused content that requires user attention or interaction. Supports a title, description, action buttons, and optional form wrapping. Controlled via an imperative ref with `open()` and `close()` methods. ```tsx demo import { Button } from "@tenstorrent/vesper/button"; import { Modal, useModal } from "@tenstorrent/vesper/modal"; export default function ModalDemo() { const modal = useModal(); return ( <> Additional content can be placed here. ); } ``` ## Options | Prop | Type | Description | Default | | --------------------- | ----------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ------- | | `title` | `string` | The title text displayed in the modal header. Used for `aria-labelledby`. **Required.** | — | | `description` | `string` | A description displayed below the title. Used for `aria-describedby`. **Required.** | — | | `width` | `number \| string` | The width of the modal container. A number is interpreted as pixels. | `452` | | `maxHeight` | `number \| string` | The maximum height of the modal container. A number is interpreted as pixels. | `640` | | `buttons` | `ButtonProps[]` | An optional array of button props for action buttons. The last button defaults to `"primary"` variant; others default to `"tertiary"`. | — | | `buttonsAlignment` | `"start" \| "end" \| "fill" \| "between"` | Controls the horizontal alignment of the action buttons. | `"end"` | | `ref` | `Ref` | A ref exposing imperative `open()` and `close()` methods. | — | | `closeOnClickOutside` | `boolean` | When `true`, clicking the backdrop closes the modal. | `false` | | `form` | `FormProps` | When provided, wraps the modal content in a `
` element with the given form attributes. | — | | `children` | `ReactNode` | The content displayed inside the modal body. | — | All other props are forwarded to the underlying `` element. A `Modal` always blocks interaction with the rest of the page while it is open. When the user should be able to keep working with the content behind the panel, reach for [the `Sheet` component](./sheet.mdx) in `popover` mode instead. ## Examples ### Opening and closing a modal A `Modal` renders closed, and is opened imperatively. The `useModal` hook returns everything needed for this: a `ref` to pass to the modal, plus `open()` and `close()` functions: ```tsx demo import { Button } from "@tenstorrent/vesper/button"; import { Modal, useModal } from "@tenstorrent/vesper/modal"; export default function BasicModal() { const modal = useModal(); return ( <> You can start exploring features right away. ); } ``` `Modal` renders a native ``, so an open modal traps focus, blocks interaction with the rest of the page, and closes when the user presses `Escape`. The close button in the header closes it too. ### Action buttons Pass an array of button props to `buttons` to render action buttons along the bottom of the modal. The last button defaults to the `primary` variant and the rest default to `tertiary`, which can be overridden with the `variant` prop: ```tsx demo import { Button } from "@tenstorrent/vesper/button"; import { Modal, useModal } from "@tenstorrent/vesper/modal"; export default function ModalWithButtons() { const modal = useModal(); return ( <> ); } ``` Buttons are aligned to the end of the modal by default. Use `buttonsAlignment` to lay them out differently; use `"start"` to render buttons towards the left edge of the modal, `"between"` to space buttons as far apart from each other as possible, or `"fill"` to have buttons occupy as much available space as possible: ```tsx demo import { Button } from "@tenstorrent/vesper/button"; import { Modal, useModal } from "@tenstorrent/vesper/modal"; export default function ModalButtonsAlignment() { const modal = useModal(); return ( <> ); } ``` ### Sizing A modal is `452px` wide and at most `640px` tall by default. Pass `width` and `maxHeight` to change that, either as numbers (interpreted as pixels) or as any CSS length string: ```tsx demo import { Button } from "@tenstorrent/vesper/button"; import { Modal, useModal } from "@tenstorrent/vesper/modal"; export default function WideModal() { const modal = useModal(); return ( <> Content taller than the modal scrolls within its body, keeping the header and action buttons in place. ); } ``` ### Closing on click outside Clicking the backdrop does nothing by default, which keeps users from dismissing a modal by accident. Pass `closeOnClickOutside` to allow users to dismiss a modal by clicking the backdrop: ```tsx demo import { Button } from "@tenstorrent/vesper/button"; import { Modal, useModal } from "@tenstorrent/vesper/modal"; export default function DismissibleModal() { const modal = useModal(); return ( <> This modal can be dismissed by clicking the backdrop behind it. ); } ``` ### Usage in forms Passing the `form` prop wraps the modal's contents in a `` element, so the action buttons can submit it natively with `type="submit"`, and native validation runs before the submit handler fires: ```tsx demo import { useState } from "react"; import { Button } from "@tenstorrent/vesper/button"; import { Modal, useModal } from "@tenstorrent/vesper/modal"; import { TextInput } from "@tenstorrent/vesper/text-input"; import { Typography } from "@tenstorrent/vesper/typography"; export default function FormModal() { const modal = useModal(); const [submitted, setSubmitted] = useState(null); return (
{submitted && ( Created project: {submitted} )} { event.preventDefault(); const data = new FormData(event.currentTarget); setSubmitted(String(data.get("name") ?? "")); modal.close(); }, }} buttons={[ { children: "Cancel", type: "button", onClick: modal.close }, { children: "Create", type: "submit" }, ]} >
); } ``` > [!NOTE] > > Buttons rendered inside a `form` default to `type="submit"`, so give any button that should not submit an explicit `type="button"`, as the cancel button above does.