"use client";
import type { ModalProps } from "@vortexlabs/vortex";
import {
Button,
Modal,
Placeholder,
Stack,
useSwitch,
} from "@vortexlabs/vortex";
type Props = Omit<ModalProps, "active" | "onClose"> & {
label?: string;
title?: string;
};
export const ModalExample = (props: Props) => {
const {
label = "Open modal",
title = "Modal title",
children,
...modalProps
} = props;
const { isOn, turnOn, turnOff } = useSwitch();
return (
<>
<Button size="sm" onClick={turnOn}>
{label}
</Button>
<Modal {...modalProps} active={isOn} onClose={turnOff}>
<Stack gap={4}>
<Modal.Dismissible closeAriaLabel="Close modal">
<Modal.Title>{title}</Modal.Title>
</Modal.Dismissible>
<Modal.Description>Modal description.</Modal.Description>
{children ?? <Placeholder height={16} />}
</Stack>
</Modal>
</>
);
};
export const Example = () => <ModalExample />;Features
- Blocks interaction behind the dialog.
- Connects the dialog to its title and description.
- Dims, blurs, or keeps the backdrop clear.
- Keeps focus inside and returns it on close.
Reference Links
WAI-ARIA modal dialog pattern
Modal.Dismissible
Wrap Modal.Title in Modal.Dismissible to align the close button. Without children, it sits in the top corner.
export const ModalDismissibleExample = () => {
const { isOn, turnOn, turnOff } = useSwitch();
return (
<Stack direction="row" gap={3} justify="center">
<ModalExample
label="Open long title"
width="24rem"
title="Review the changes to your project settings before saving them"
/>
<Button size="sm" onClick={turnOn}>
Open standalone
</Button>
<Modal active={isOn} onClose={turnOff} padding={{ xs: 4, md: 8 }}>
<Modal.Dismissible closeAriaLabel="Close modal" />
<Stack gap={4}>
<Modal.Title>Modal title</Modal.Title>
<Placeholder height={16} />
</Stack>
</Modal>
</Stack>
);
};Variants
Use variant to dim, blur, or clear the backdrop. A transparent backdrop still blocks interaction.
export const ModalVariantExample = () => (
<Stack direction="row" gap={3} justify="center">
<ModalExample variant="dim" label="Open dim" />
<ModalExample variant="blurred" label="Open blurred" />
<ModalExample variant="transparent" label="Open transparent" />
</Stack>
);Outside Clicks
Set disableCloseOnOutsideClick to ignore backdrop clicks. Escape and the close button still request dismissal.
<ModalExample disableCloseOnOutsideClick />Size and Padding
Set width and padding with breakpoint objects to adjust the panel across screen sizes.
export const ModalSizeExample = () => (
<Stack direction="row" gap={3} justify="center">
<ModalExample width="20rem" padding={3} label="Open compact" />
<ModalExample width="40rem" padding={6} label="Open spacious" />
<ModalExample
width={{ xs: "90%", sm: "36rem", md: "48rem" }}
padding={{ xs: 3, md: 6 }}
label="Open responsive"
/>
</Stack>
);Accessibility
Key
Description
TabShiftTab
Moves focus between controls inside the modal.
Escape
Calls
onClose with escape-key.Use
Modal.Title or ariaLabel to name the dialog.Set
closeAriaLabel on Modal.Dismissible.