Modal
Modal is a neobrutalist React component from Cruise UI. A dialog with a --primary title bar, for confirmations and short forms. Install it with npx shadcn@latest add @cruiseui/modal.
Install
Terminal
npx shadcn@latest add @cruiseui/modalFirst time? Installation shows the one-off components.json setup (the @cruiseui registry) and how to turn the theme on.
Example
Corners
"use client";
import { useState } from "react";
import { CruiseButton } from "@/components/cruise/button";
import { CruiseModal } from "@/components/cruise/modal";
export default function ModalExample() {
const [open, setOpen] = useState(false);
return (
<CruiseModal
open={open}
onOpenChange={setOpen}
title="Cancel this order?"
trigger={<CruiseButton variant="secondary">Cancel order</CruiseButton>}
footer={
<>
<CruiseButton variant="secondary" onClick={() => setOpen(false)}>
Keep order
</CruiseButton>
<CruiseButton variant="danger" onClick={() => setOpen(false)}>
Cancel order
</CruiseButton>
</>
}
>
Your rider hasn't left yet, so you won't be charged.
</CruiseModal>
);
}
<div class="drawer-backdrop"></div>
<div role="dialog" aria-modal="true" aria-labelledby="m-title" class="brutal" style="position: fixed; top: 50%; left: 50%; z-index: 61; width: min(90vw, 28rem); transform: translate(-50%, -50%); box-shadow: var(--shadow-lg); overflow: hidden">
<div class="on-primary" style="padding: 12px 20px; border-bottom: var(--border-w) solid var(--ink)">
<h2 id="m-title" style="margin: 0">Cancel this order?</h2>
</div>
<div style="padding: 20px">
<p>Your rider hasn't left yet, so you won't be charged.</p>
<button type="button" class="brutal btn btn-secondary">Keep order</button>
<button type="button" class="brutal btn on-primary">Cancel order</button>
</div>
</div>Needs theme.css. Interactive parts (menus, tabs, drawers) also need the script in the spec for that component.
When to use it
When to use
Confirming something (delete, cancel order) or a short focused task.
When not to
Long content or navigation (use a page or a Drawer). Never use alert() or confirm().
Props
CruiseModal
| Prop | Type | Default | Description |
|---|---|---|---|
title | ReactNode | — | — |
children | ReactNode | — | — |
trigger? | ReactElement<unknown, string | JSXElementConstructor<any>> | — | Element that opens the modal, e.g. <Button>. Omit when controlled. |
footer? | ReactNode | — | Buttons along the bottom. |
open? | boolean | — | — |
onOpenChange? | ((open: boolean) => void) | — | — |
initialFocus? | RefObject<HTMLElement | null> | — | Element to focus when the modal opens; defaults to the first focusable. |
Accessibility
- Focus moves into the dialog and back to the trigger on close.
- Esc and the close button both close it.