Anchored Auto Layout
npm

Hover or focus a box to measure it. Click its tag, or press ] and [, to pin one. Esc unpins.

    Legend
    • Anchor: a box with data-⚓️-name
    • Placed by anchors: out of flow
    • Gap from the anchor's edge, in px
    • Edges of the box you're inspecting

    Every tag, line and number here is itself placed by data-⚓️-* attributes. JS only measures.

    Compass menu

    A radial/compass action menu: four items placed above/after/below/before a hub with data-⚓️-side, opening out of the hub with data-⚓️-morph-from.

    Full page
    <main class="page">
      <header class="intro">
        <h1>Compass menu</h1>
        <p>
          Four items sit <code>above</code>, <code>after</code>, <code>below</code> and <code>before</code>
          the hub via <code>data-⚓️-side</code>, and open out of it with <code>data-⚓️-morph-from</code>.
          Pick one and it moves to the top: the menu reorders by changing side values.
          Arrow keys go in the direction of the side.
        </p>
        <label class="xray"><input type="checkbox" id="xray"> X-ray</label>
      </header>
    
      <section class="stage" data-⚓️-root>
        <button class="hub" id="hub" type="button" aria-haspopup="menu" aria-expanded="false" aria-controls="menu" data-⚓️-name="--hub">
          <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg>
          <span class="visually-hidden">Actions</span>
        </button>
    
        <ul class="menu" id="menu" role="menu" aria-label="Actions">
          <li class="item" role="none" hidden data-⚓️-to="--hub" data-⚓️-side="above" data-⚓️-align-x="center" data-⚓️-tween data-⚓️-morph-from data-⚓️-transition="morph">
            <button role="menuitem" type="button" data-action="Copied">
              <svg viewBox="0 0 24 24" aria-hidden="true"><rect x="8" y="8" width="12" height="12" rx="2"/><path d="M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2"/></svg>
              <span>Copy</span>
            </button>
          </li>
          <li class="item" role="none" hidden data-⚓️-to="--hub" data-⚓️-side="after" data-⚓️-align-y="center" data-⚓️-tween data-⚓️-morph-from data-⚓️-transition="morph">
            <button role="menuitem" type="button" data-action="Shared">
              <svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="6" cy="12" r="2.5"/><circle cx="18" cy="6" r="2.5"/><circle cx="18" cy="18" r="2.5"/><path d="M8.2 10.9l7.6-3.8M8.2 13.1l7.6 3.8"/></svg>
              <span>Share</span>
            </button>
          </li>
          <li class="item" role="none" hidden data-⚓️-to="--hub" data-⚓️-side="below" data-⚓️-align-x="center" data-⚓️-tween data-⚓️-morph-from data-⚓️-transition="morph">
            <button role="menuitem" type="button" data-action="Pinned">
              <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M12 17v5M8 3h8l-1 6 3 3v2H6v-2l3-3z"/></svg>
              <span>Pin</span>
            </button>
          </li>
          <li class="item" role="none" hidden data-⚓️-to="--hub" data-⚓️-side="before" data-⚓️-align-y="center" data-⚓️-tween data-⚓️-morph-from data-⚓️-transition="morph">
            <button role="menuitem" type="button" data-action="Deleted" class="danger">
              <svg viewBox="0 0 24 24" aria-hidden="true"><path d="M4 7h16M10 11v6M14 11v6M6 7l1 13h10l1-13M9 7V4h6v3"/></svg>
              <span>Delete</span>
            </button>
          </li>
        </ul>
    
        <p class="status" id="status" role="status"></p>
      </section>
    </main>

    data-⚓️-align-xdata-⚓️-align-ydata-⚓️-morph-fromdata-⚓️-namedata-⚓️-rootdata-⚓️-sidedata-⚓️-todata-⚓️-transitiondata-⚓️-tween

    Copied