Skip to content
Honor Society®Brand system

v0.6.4

Forms and controls

Dialog

A native modal for a short edit form or a confirm that keeps the member on the page.

Block
.hs-dialog
CSS
components/dialog.css (in /brand.css)
JS
components/dialog.js: load it only on a page with this component
Status
Decided
Decided in
Components round 2b
Markdown
/components/dialog.md

What it is

A native <dialog> opened with showModal(). Sizes: --sm 440px, default 560px, --lg 720px. Didot title, 40px round close button; the primary button first, then the secondary pill.

When to use

  • A short edit form that keeps the member on the page, such as “Edit academic record” on the profile. Use the default 560px width.
  • A confirm before the member loses work, such as “Leave without saving?”. Use --sm.
  • A long form or a photo editor. Use --lg.

When not to use

  • Body HTML for hs_html_page carries no <script>, so nothing can open the dialog. Put the content in the page.
  • For a message after an action, use a Callout on the page.
  • For legal or participation terms, use the Disclosure in its own band.
  • For a video, use the Video facade. It plays in place.

Rules

  • Markup: <dialog class="hs-dialog" id="ID" aria-labelledby="TITLE-ID"> holds .hs-dialog__header, .hs-dialog__body and .hs-dialog__footer. For a form, wrap the body and the footer in form.hs-dialog__form.
  • The header holds an h2.hs-dialog__title and a button.hs-dialog__close with data-hs-dialog-close.
  • Open it from <button type="button" data-hs-dialog-open="ID">. Every other closer carries data-hs-dialog-close. Load dialog.js.
  • In the footer, put the primary .hs-button.hs-button--sm first, then a .hs-button--secondary.hs-button--sm such as “Cancel”. Below 30rem the two stack full width, the primary on top.
  • Use the secondary pill only for the second action. A dialog has one primary button.

Accessibility

  • showModal() traps focus, closes on Escape and returns focus to the opener. dialog.js also closes the dialog on a backdrop click.
  • aria-labelledby points at the title. The close button carries aria-label="Close", and its icon carries aria-hidden="true" focusable="false".
  • The title is navy, 12.4:1 on white.
  • Without dialog.js the opener does nothing. The no-JS page must still give every answer, so the task needs a second route.
  • The fade and the 8px rise run only under prefers-reduced-motion: no-preference.

Variants

Dialog

Try the three buttons. Needs dialog.js.

Preview on white

Edit academic record

<button class="hs-button hs-button--secondary hs-button--sm" type="button" data-hs-dialog-open="edit-academic">Edit academic record</button>

<dialog class="hs-dialog" id="edit-academic" aria-labelledby="edit-academic-title">
  <header class="hs-dialog__header">
    <h2 class="hs-dialog__title" id="edit-academic-title">Edit academic record</h2>
    <button class="hs-dialog__close" type="button" aria-label="Close" data-hs-dialog-close>
      <svg class="hs-dialog__close-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true" focusable="false"><path d="M6 6l12 12M18 6 6 18"/></svg>
    </button>
  </header>
  <form class="hs-dialog__form" action="/user/profile/academic" method="post">
    <div class="hs-dialog__body">
      <div class="hs-form">
        <div class="hs-field">
          <label class="hs-label" for="dlg-school">School</label>
          <input class="hs-control" id="dlg-school" name="school" type="text" value="Sample College">
        </div>
        <div class="hs-field">
          <label class="hs-label" for="dlg-gpa">GPA <span class="hs-optional">(optional)</span></label>
          <input class="hs-control hs-control--short" id="dlg-gpa" name="gpa" type="text" inputmode="decimal" value="3.75">
        </div>
      </div>
    </div>
    <footer class="hs-dialog__footer">
      <button class="hs-button hs-button--sm" type="submit">Save</button>
      <button class="hs-button hs-button--secondary hs-button--sm" type="button" data-hs-dialog-close>Cancel</button>
    </footer>
  </form>
</dialog>