App Switcher

<sl-app-switcher> | SlAppSwitcher
Since 1.1.16 stable

App switcher provides a trigger button in the application header that opens a panel of links. On desktop the panel appears as a dropdown, while on tablet/mobile it slides in from the left inside an <sl-drawer>.

sl-app-switcher renders a complete switchable-app panel that includes its own trigger buttons. On desktop viewports (>989 px) it wraps the panel in an sl-dropdown; on tablet and mobile it uses a slide-in sl-drawer. The component closes automatically when the user resizes across the breakpoint.

Add entries by slotting sl-app-tile elements. Tiles in the default slot form the primary section; tiles in the secondary slot form a second section shown under the optional secondary-label heading. The divider appears only when both sections have content. Preview tiles use href="#" placeholders; their default navigation is prevented to avoid jumping to the top of the page.

<sl-app-switcher id="switcher-basic" secondary-label="Integrations" mobile-header-img-url="/assets/images/hub24.svg">
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
  <sl-app-tile label="myHUB" href="#" icon-src="/assets/images/logo-icon-myhub.svg"></sl-app-tile>
  <sl-app-tile label="Class" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>
  <sl-app-tile label="NowInfinity" href="#" icon-src="/assets/images/logo-icon-ni.svg"></sl-app-tile>

  <sl-app-tile slot="secondary" label="Chrome" href="#" icon-src="/assets/images/chrome.png"></sl-app-tile>
  <sl-app-tile slot="secondary" label="Firefox" href="#" icon-src="/assets/images/firefox.png"></sl-app-tile>
  <sl-app-tile slot="secondary" label="Edge" href="#" icon-src="/assets/images/edge.png"></sl-app-tile>
</sl-app-switcher>
<script>
  document.addEventListener(
    'click',
    event => {
      const tile = event.composedPath().find(
        element => element instanceof Element && element.matches('sl-app-tile[href="#"]')
      );
      if (tile) event.preventDefault();
    },
    true
  );
</script>

Examples

Primary Only

Leave the secondary slot empty to show only the primary section without a heading or divider.

<sl-app-switcher id="switcher-apps-only">
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
  <sl-app-tile label="myHUB" href="#" icon-src="/assets/images/logo-icon-myhub.svg"></sl-app-tile>
  <sl-app-tile label="Class" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>
</sl-app-switcher>

Few Tiles

The desktop panel keeps a two-column minimum, so one or two tiles don’t collapse it into a narrow strip. With three or more tiles it expands to three columns. Adjust --app-switcher-tile-size to scale the standard tile width the panel lays out against.

<sl-app-switcher id="switcher-two-tiles">
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
</sl-app-switcher>

Tile Size Is Standardised

The switcher standardises slotted tiles to the medium presentation, so a tile’s own size attribute is ignored inside the switcher. Here the second tile sets size="large" but still matches the others.

<sl-app-switcher id="switcher-size-normalised">
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile size="large" label="Class" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>
  <sl-app-tile label="myHUB" href="#" icon-src="/assets/images/logo-icon-myhub.svg"></sl-app-tile>
</sl-app-switcher>

Tiles in a row share the same height, so the icons and primary labels stay aligned even when only some tiles have a sub-label.

<sl-app-switcher id="switcher-sublabels-mixed">
  <sl-app-tile label="HUB24" sub-label="Platform" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
  <sl-app-tile label="Class" sub-label="SMSF" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>
</sl-app-switcher>

Secondary Section

Put tiles in the secondary slot and set secondary-label to add a labelled second section.

<sl-app-switcher id="switcher-ints-only" secondary-label="Integrations">
  <sl-app-tile slot="secondary" label="Chrome" href="#" icon-src="/assets/images/chrome.png"></sl-app-tile>
  <sl-app-tile slot="secondary" label="Firefox" href="#" icon-src="/assets/images/firefox.png"></sl-app-tile>
  <sl-app-tile slot="secondary" label="Edge" href="#" icon-src="/assets/images/edge.png"></sl-app-tile>
</sl-app-switcher>

Scrolling

The desktop panel caps its height at 800px. When the combined sections exceed that, the panel scrolls internally instead of growing taller.

<sl-app-switcher id="switcher-scroll" secondary-label="Integrations">
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
  <sl-app-tile label="myHUB" href="#" icon-src="/assets/images/logo-icon-myhub.svg"></sl-app-tile>
  <sl-app-tile label="Class" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>
  <sl-app-tile label="NowInfinity" href="#" icon-src="/assets/images/logo-icon-ni.svg"></sl-app-tile>
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
  <sl-app-tile label="myHUB" href="#" icon-src="/assets/images/logo-icon-myhub.svg"></sl-app-tile>
  <sl-app-tile label="Class" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>
  <sl-app-tile label="NowInfinity" href="#" icon-src="/assets/images/logo-icon-ni.svg"></sl-app-tile>
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
  <sl-app-tile label="myHUB" href="#" icon-src="/assets/images/logo-icon-myhub.svg"></sl-app-tile>
  <sl-app-tile label="Class" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>
  <sl-app-tile label="NowInfinity" href="#" icon-src="/assets/images/logo-icon-ni.svg"></sl-app-tile>
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
  <sl-app-tile label="myHUB" href="#" icon-src="/assets/images/logo-icon-myhub.svg"></sl-app-tile>

  <sl-app-tile slot="secondary" label="Chrome" href="#" icon-src="/assets/images/chrome.png"></sl-app-tile>
  <sl-app-tile slot="secondary" label="Firefox" href="#" icon-src="/assets/images/firefox.png"></sl-app-tile>
  <sl-app-tile slot="secondary" label="Edge" href="#" icon-src="/assets/images/edge.png"></sl-app-tile>
</sl-app-switcher>

Use the footer slot to pin content — such as a button — to the bottom-left of the desktop panel.

Manage integrations
<sl-app-switcher id="switcher-footer" secondary-label="Integrations">
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
  <sl-app-tile label="myHUB" href="#" icon-src="/assets/images/logo-icon-myhub.svg"></sl-app-tile>
  <sl-app-tile label="Class" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>
  <sl-app-tile label="NowInfinity" href="#" icon-src="/assets/images/logo-icon-ni.svg"></sl-app-tile>

  <sl-app-tile slot="secondary" label="Chrome" href="#" icon-src="/assets/images/chrome.png"></sl-app-tile>
  <sl-app-tile slot="secondary" label="Firefox" href="#" icon-src="/assets/images/firefox.png"></sl-app-tile>
  <sl-app-tile slot="secondary" label="Edge" href="#" icon-src="/assets/images/edge.png"></sl-app-tile>

  <sl-button slot="footer" size="small" variant="secondary">
    Manage integrations
    <sl-icon slot="suffix" name="arrow-right"></sl-icon>
  </sl-button>
</sl-app-switcher>

Keep Open on Select

Selecting a primary or secondary tile closes the panel by default. Add stay-open-on-select to keep the panel open after a tile is selected.

<sl-app-switcher id="switcher-stay-open" stay-open-on-select secondary-label="Integrations">
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
  <sl-app-tile label="Class" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>

  <sl-app-tile slot="secondary" label="Chrome" href="#" icon-src="/assets/images/chrome.png"></sl-app-tile>
  <sl-app-tile slot="secondary" label="Firefox" href="#" icon-src="/assets/images/firefox.png"></sl-app-tile>
</sl-app-switcher>

Mobile Header Image

Use the mobile-header-img-url attribute to display a logo or branding image in the top-left corner of the mobile drawer header.

<sl-app-switcher id="switcher-mobile-header" mobile-header-img-url="/assets/images/hub24.svg">
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
  <sl-app-tile label="Class" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>
</sl-app-switcher>

Dark Trigger

Add the dark attribute when the trigger sits on a dark surface (e.g. a dark app header) — it makes the trigger icon light. The panel is a separate surface and stays light; control its background independently with --app-switcher-panel-bg.

app logo
<sl-app-header-hds>
  <img slot="app-logo" src="/dist/images/hub24_logo_primary_reverse.svg" alt="app logo" />
  <sl-app-switcher slot="app-switcher" dark id="switcher-header" secondary-label="Integrations" mobile-header-img-url="/assets/images/hub24.svg">
    <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
    <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
    <sl-app-tile label="Class" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>

    <sl-app-tile slot="secondary" label="Chrome" href="#" icon-src="/assets/images/chrome.png"></sl-app-tile>
    <sl-app-tile slot="secondary" label="Firefox" href="#" icon-src="/assets/images/firefox.png"></sl-app-tile>
    <sl-app-tile slot="secondary" label="Edge" href="#" icon-src="/assets/images/edge.png"></sl-app-tile>
  </sl-app-switcher>
</sl-app-header-hds>

Dark Panel

Add the panel-dark attribute to darken the panel. Slotted tiles are set to a dark scheme automatically; a tile with an explicit mode keeps its own.

<sl-app-switcher panel-dark secondary-label="Integrations">
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="Stays light" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>

  <sl-app-tile slot="secondary" label="Chrome" href="#" icon-src="/assets/images/chrome.png"></sl-app-tile>
  <sl-app-tile slot="secondary" label="Firefox" href="#" icon-src="/assets/images/firefox.png"></sl-app-tile>
</sl-app-switcher>

Open by Default

Set the open attribute or property to open the panel on first render.

<sl-app-switcher id="switcher-open" open>
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
</sl-app-switcher>

Controlling Programmatically

Use the show() and hide() methods to open and close the panel from JavaScript. The example below binds Alt + A as a keyboard shortcut to toggle the switcher.

Press Alt + A to toggle the app switcher.

<sl-app-switcher id="switcher-kbd">
  <sl-app-tile label="HUB24" href="#" icon-src="/assets/images/logo-icon-hub.svg"></sl-app-tile>
  <sl-app-tile label="myprosperity" href="#" icon-src="/assets/images/logo-icon-myp.svg"></sl-app-tile>
  <sl-app-tile label="Class" href="#" icon-src="/assets/images/logo-icon-class.svg"></sl-app-tile>
</sl-app-switcher>
<p style="margin-top: 12px; font-size: 14px; color: var(--hds-color-fg-subtle);">
  Press <kbd>Alt</kbd> + <kbd>A</kbd> to toggle the app switcher.
</p>
<script>
  const switcher = document.getElementById('switcher-kbd');
  document.addEventListener('keydown', e => {
    if (e.altKey && e.key === 'a') {
      e.preventDefault();
      switcher.open ? switcher.hide() : switcher.show();
    }
  });
</script>

Animation

Hovering over an app tile applies a background color transition using --sl-transition-fast. The same transition is applied to the trigger icon.

  • Desktop dropdown: uses a 100ms ease animation.
  • Mobile drawer: slides in from the start edge using the drawer’s default open/close animation.

Slots

Name Description
(default) sl-app-tile entries for the primary section.
secondary sl-app-tile entries for the secondary section, shown under an optional heading.
footer Content pinned to the bottom-left of the panel (e.g. a button).

Learn more about using slots.

Properties

Name Description Reflects Type Default
open When true, the desktop dropdown or mobile drawer is open. boolean false
dark Styles the trigger for a dark surface (e.g. a dark app header). boolean false
panelDark
panel-dark
Darkens the panel and sets slotted tiles to a dark scheme (tiles with an explicit mode are left alone). boolean false
mobileHeaderImgUrl
mobile-header-img-url
Optional image URL rendered in the left side of the mobile/tablet drawer header. string | undefined -
secondaryLabel
secondary-label
Optional heading for the secondary section. When empty, no heading is shown. string ''
emptyText
empty-text
Message shown when no app tiles are slotted. string 'Connect at least one application.'
stayOpenOnSelect
stay-open-on-select
Keeps the panel open after a tile is selected. boolean false
updateComplete A read-only promise that resolves when the component has finished updating.

Learn more about attributes and properties.

Events

Name React Event Description Event Detail
sl-show Emitted when the panel opens (either the desktop dropdown or mobile drawer). -
sl-hide Emitted when the panel closes. -

Learn more about events.

Methods

Name Description Arguments
show() Opens the desktop dropdown or mobile drawer. -
hide() Closes the desktop dropdown or mobile drawer. -

Learn more about methods.

Custom Properties

Name Description Default
--app-switcher-trigger-color Colour of the trigger icon.
--app-switcher-trigger-bg-open Background of the trigger when open / hovered / focused.
--app-switcher-panel-bg Background of the dropdown / drawer panel.

Learn more about customizing CSS custom properties.

Parts

Name Description
base The component’s base wrapper.
drawer The slide-in / full-screen drawer panel (tablet & mobile only).
close-button The drawer close button (tablet & mobile only).
dropdown The dropdown panel (desktop only).
grid The wrapper for the grid of app/integration items.

Learn more about customizing CSS parts.