VSN.jsGitHub ↗

COOKBOOK / LIVE EXAMPLE

Modal Dialog example with VSN.js

Real markup. Real VSN. Try it below.

← All examples · Open full screen ↗

View example source
<section id="modal-example" class="example-card cookbook-example">
  <header class="cookbook-heading">
    <div>
      <p class="cookbook-eyebrow">Behavior cookbook</p>
      <h1>Dialog / modal</h1>
      <p class="cookbook-lede">
        State controls visibility while event flags handle Escape and backdrop clicks.
      </p>
    </div>
    <span class="cookbook-badge">state + events</span>
  </header>

  <div class="cookbook-stage">
    <div class="cookbook-toolbar">
      <button
        id="modal-launch"
        class="btn"
        type="button"
        vsn-on:click="openDialog(self);"
      >
        Open dialog
      </button>
      <p class="cookbook-status">
        State: <strong vsn-bind:from="status">Closed</strong>
      </p>
    </div>
    <p class="cookbook-note">
      <code>vsn-show</code> hides the backdrop semantically without removing it from the DOM.
      The close function restores focus to the launch button.
    </p>
  </div>

  <div
    id="modal-backdrop"
    class="cookbook-modal"
    role="presentation"
    vsn-show="open"
    vsn-on:click!self="closeDialog();"
  >
    <div
      id="modal-dialog"
      class="cookbook-dialog"
      role="dialog"
      aria-modal="true"
      aria-labelledby="modal-title"
      tabindex="-1"
    >
      <header class="cookbook-dialog-heading">
        <div>
          <p class="cookbook-eyebrow">A stateful overlay</p>
          <h2 id="modal-title">Edit the message</h2>
        </div>
        <button class="icon-button" type="button" aria-label="Close dialog" vsn-on:click="closeDialog();">
          ×
        </button>
      </header>

      <form class="cookbook-form" vsn-on:submit!prevent="saveDialog();">
        <label class="cookbook-field">
          <span>Message</span>
          <input type="text" autofocus vsn-bind="message" />
        </label>
        <div class="cookbook-actions">
          <button class="btn secondary" type="button" vsn-on:click="closeDialog();">Cancel</button>
          <button class="btn" type="submit">Save</button>
        </div>
      </form>
    </div>
  </div>
</section>

<script type="text/vsn">
  #modal-example {
    open: false;
    status: "Closed";
    message: "Keep the dialog behavior close to the markup.";
    lastFocus: null;

    openDialog(ele) {
      open = true;
      status = "Open";
      lastFocus = ele;
    }

    closeDialog() {
      open = false;
      status = "Closed";
      lastFocus && lastFocus.focus();
    }

    saveDialog() {
      open = false;
      status = "Saved";
      lastFocus && lastFocus.focus();
    }

    on keyup!escape() {
      open ? closeDialog() : null;
    }
  }
</script>