CSC Design System Skills & Best Practices
CS
On this page

Proposed CSC Standards · 0.1.0

Dialogs and modals

A modal dialog for a short decision or a focused edit.

Interrupt the page for a task that must be finished or cancelled before returning.

What this describes

Default
Standard
Minimal
Drawer
Fullscreen
Bottom sheet

When to use

  • Confirming a destructive action.
  • Editing one record without leaving the list.
  • A short decision that needs a title and a description.

When not to use

  • Showing a page of content. Navigate instead.
  • A message that does not need a response. Use Alert or a toast.

Allowed variants

Standard

A centered confirm or review.

Hierarchy
Page overlay.
Use in
Short decisions.
Restriction
Keep Escape and a close button.
Accessibility
Focus is trapped.
Responsive
On a narrow screen the panel uses the viewport width minus padding.

Minimal

A shorter confirm.

Hierarchy
Narrower dialog.
Use in
Yes or no decisions.
Restriction
Still needs a title.
Accessibility
Same focus rules.
Responsive
Does not shrink below the action row.

Drawer

Edit a record beside the list.

Hierarchy
Side panel.
Use in
Record details.
Restriction
Do not use a drawer for a one-word confirm.
Accessibility
Same dialog semantics.
Responsive
On a narrow frame the drawer should cover the width instead of leaving a sliver of page.

Fullscreen

A workflow that needs the whole screen.

Hierarchy
Full viewport.
Use in
Multi-step tasks on small screens.
Restriction
Provide a way back.
Accessibility
Focus still starts in the dialog.
Responsive
This is the small-screen alternative to a cramped centered modal.

Bottom sheet

Quick actions from the bottom edge.

Hierarchy
Bottom panel.
Use in
A few actions, not a long form.
Restriction
Do not hide the actions below the fold.
Accessibility
Title and description remain.
Responsive
Sits on the bottom of the frame. Content scrolls inside the sheet.

Mandatory rules

MOD-001RequiredARIA

Move focus into the dialog and keep it there

While the dialog is open, Tab cycles inside it and focus returns to the trigger on close.

Implementation detail

The APG dialog pattern requires focus movement and a trap. Radix Dialog does this for Modal.

Use a dialog that moves focus inside and traps Tab. Do not use a positioned div unless it does the same.

Check: Open the dialog. The title or first control is focused. Tab does not reach the page behind it.

Source

MOD-002ConditionalARIA

Close on Escape unless the action is destructive

Escape closes a standard dialog. A destructive confirm does not dismiss on Escape or outside click.

Implementation detail

Accidental dismissal can cancel a warning the person has not read. The CSC destructive modal already prevents Escape and outside close.

A destructive confirm stays open on Escape and outside click. Other dialogs close on Escape.

Applies when: The dialog asks to delete or another irreversible action.

Check: Escape closes a standard dialog and does not close a destructive one.

Source

MOD-003RequiredARIA

Provide a name and a description

The dialog has Dialog.Title and Dialog.Description, which Modal already renders.

Implementation detail

aria-labelledby and aria-describedby come from those parts.

Do not remove the title. The description states what will happen.

Check: The accessibility name is the visible title.

Source

MOD-004RequiredFramework

Lock background scroll while a modal is open

The page behind the dialog does not scroll.

Implementation detail

Radix Dialog locks body scroll. A custom overlay that forgets this lets the page move under the dialog.

Lock body scroll while the dialog is open.

Check: With the dialog open, the background does not scroll.

MOD-005RecommendedProposed CSC convention

Choose the kind that matches the viewport

Drawer, fullscreen, and bottom sheet are the supported adaptations. Do not invent a fifth overlay.

Implementation detail

Proposed CSC Standard. kind="drawer" is a side panel, kind="sheet" is a bottom sheet, kind="fullscreen" covers small tasks that need the whole screen.

Use drawer for a record edit, sheet for quick actions, fullscreen for a multi-step workflow on a small screen.

Check: At 375px the chosen kind fits the viewport and its actions remain reachable.

MOD-006ProhibitedProposed CSC convention

Do not open a dialog on page load

A dialog opens from a person activating a trigger, not from the first render.

Implementation detail

Proposed CSC Standard. An auto-open dialog steals focus from the page heading.

Leave the dialog closed until the person activates a trigger.

Check: Loading the page leaves focus on the page, not inside a dialog.

Restrictions

  • MOD-002 Close on Escape unless the action is destructive. The dialog asks to delete or another irreversible action.
  • MOD-006 Do not open a dialog on page load. A dialog opens from a person activating a trigger, not from the first render.

Accessibility

  • Focus moves in and returns to the trigger.
  • Escape closes non-destructive dialogs.
  • Title and description are present.
  • Background content is inert while the dialog is open.

Responsive behavior

  • Centered dialogs keep 16px of viewport padding.
  • Prefer sheet or fullscreen under 480px when the form is taller than the viewport.
  • Action rows wrap. The primary action stays reachable.

Component states

Closed

Only the trigger is available.

Open

Focus is inside, background scroll is locked.

Destructive

Escape and outside click do not dismiss. The person chooses Delete or Cancel.

Correct implementation

Standard dialogCorrect implementation · TSX

A dialog element carries the title. Focus stays inside while it is open.

Imports: None. Dependencies: None. Rules: MOD-001, MOD-003.

export function ReviewAction() {
  return (
    <dialog open aria-labelledby="review-title">
      <h2 id="review-title">Review application</h2>
      <p>Check the details before you continue.</p>
      <button type="button">Close</button>
    </dialog>
  );
}
Destructive confirmAccessibility implementation · TSX

The warning stays until the person chooses. Escape does not dismiss a destructive confirm.

Imports: None. Dependencies: None. Rules: MOD-002.

export function DeleteConfirm() {
  return (
    <dialog open aria-labelledby="delete-title">
      <h2 id="delete-title">Delete record</h2>
      <p>This cannot be undone.</p>
      <button type="button" style={{ background: '#C41222', color: '#fff', borderRadius: 8 }}>Delete record</button>
      <button type="button">Cancel</button>
    </dialog>
  );
}

Incorrect implementation

Overlay without a dialogIncorrect implementation · TSX · Illustrative

A clickable div does not trap focus, name the dialog, or lock scroll.

Imports: None. Dependencies: None. Rules: MOD-001, MOD-004.

export function FakeDialog() {
  return <div onClick={() => {}}>Confirm</div>;
}

Common mistakes

  • A div overlay with no focus trap.
  • Auto-opening on load.
  • A destructive dialog that closes when the person clicks the scrim.

Testing checklist

Agent prompts for this component are in the AI Development Hub.