NS Design System
v3.0.0 · 257 tokens

57Account menu

The signed-in end of the navbar: an avatar trigger opening a panel that states WHO you are before it offers anything to do. Signed out, the same slot is two buttons — quiet sign-in beside the one solid blue thing on the page.

Use it for

  • Every signed-in surface — the panel is where account, progress and sign-out live
  • Ghost Members: wrap it in {{#if @member}} and the signed-out pair in the {{else}}

Not for

  • A bare avatar with no name anywhere — an avatar is not an accessible name
  • Burying sign-out three levels deep; it is the one item people go looking for
  • Duplicating the whole site map inside it — that is the navbar's job

Signed out

Sign in is quiet, sign up is THE primary. Two primaries here is the most common navbar mistake in the wild — it makes the user choose between two equally loud things at the exact moment they know least.

markup
<div class="ns-topnav__auth">
  <a class="ns-btn ns-btn--quiet ns-btn--sm" href="#">Sign in</a>
  <a class="ns-btn ns-btn--primary ns-btn--sm" href="#">Start learning</a>
</div>

Signed in

Live: click the avatar. Identity, then progress, then actions, then sign out behind a hairline — the order is the order people look for them.

markup
<nav class="ns-topnav" aria-label="Account menu example">
  <a class="ns-topnav__brand" href="#"><img src="../assets/logo/favicon.svg" alt=""><span class="ns-topnav__brand-name">Namaste Salesforce</span></a>
  <div class="ns-topnav__actions">
    <div class="ns-usermenu">
      <button type="button" class="ns-usermenu__trigger" data-ns-menu aria-expanded="false" aria-controls="doc-account" aria-label="Account menu for Aarti Kulkarni">
        <span class="ns-avatar ns-avatar--sm" aria-hidden="true">AK</span>
        <span class="ns-usermenu__name">Aarti K.</span>
      </button>
      <div class="ns-usermenu__panel" id="doc-account">
        <div class="ns-usermenu__head">
          <span class="ns-avatar" aria-hidden="true">AK</span>
          <span class="ns-usermenu__identity">
            <span class="ns-usermenu__fullname">Aarti Kulkarni</span>
            <span class="ns-usermenu__email">aarti@example.com</span>
          </span>
          <span class="ns-usermenu__plan">Pro</span>
        </div>
        <div class="ns-usermenu__progress">
          <span class="ns-usermenu__progress-label"><span>Admin trail</span><span>64%</span></span>
          <progress class="ns-progress" value="64" max="100" aria-label="Admin trail progress">64%</progress>
        </div>
        <hr class="ns-menu__sep">
        <a class="ns-menu__item" href="#"><i class="ph ph-user" aria-hidden="true"></i> My learning</a>
        <a class="ns-menu__item" href="#"><i class="ph ph-bookmark-simple" aria-hidden="true"></i> Bookmarks</a>
        <a class="ns-menu__item" href="#"><i class="ph ph-seal-check" aria-hidden="true"></i> Certificates</a>
        <hr class="ns-menu__sep">
        <a class="ns-menu__item" href="#"><i class="ph ph-gear" aria-hidden="true"></i> Settings</a>
        <a class="ns-menu__item" href="#"><i class="ph ph-question" aria-hidden="true"></i> Help</a>
        <hr class="ns-menu__sep">
        <button type="button" class="ns-menu__item ns-menu__item--danger"><i class="ph ph-arrow-up-right" aria-hidden="true"></i> Sign out</button>
      </div>
    </div>
  </div>
</nav>

Triggers

Avatar only for a dense app bar; avatar plus short name where there is room — the name is what tells a shared-computer household which account they are about to post from. Photo, initials and a progress ring all fit the same disc (see Avatar).

markup
<div class="ns-usermenu">
  <button type="button" class="ns-usermenu__trigger" aria-expanded="false" aria-label="Account menu for Aarti Kulkarni">
    <span class="ns-avatar ns-avatar--sm" aria-hidden="true">AK</span>
  </button>
</div>
<div class="ns-usermenu">
  <button type="button" class="ns-usermenu__trigger" aria-expanded="false" aria-label="Account menu for Aarti Kulkarni">
    <span class="ns-avatar ns-avatar--sm" aria-hidden="true">AK</span>
    <span class="ns-usermenu__name">Aarti K.</span>
  </button>
</div>
<div class="ns-usermenu">
  <button type="button" class="ns-usermenu__trigger" aria-expanded="true" aria-label="Account menu for Ravi Sharma — expanded">
    <span class="ns-avatar-ring" style="--p:64"><span class="ns-avatar ns-avatar--sm" aria-hidden="true">RS</span></span>
    <span class="ns-usermenu__name">Ravi S.</span>
  </button>
</div>

Accessibility contract

  • The trigger names the account: aria-label="Account menu for Aarti Kulkarni", because the initials disc is aria-hidden
  • The identity block is real text, so a screen reader reads the account before the actions
  • Sign out is a <button> — it changes state, it does not navigate
  • Below lg the name is hidden visually; the accessible name on the trigger keeps it announced