npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

jui-omnibar

v5.1.1

Published

Juniper omnibar web components

Readme

JUI Omnibar

A lightweight, framework-agnostic web component omnibar for Juniper products.

Includes:

  • Product switcher with a redirect modal that opens products in the same tab
  • Profile switcher with a redirect modal on the "Profile" link that opens Portal in a new tab
  • Image-based icons with automatic light/dark switching
  • Account-aware configuration
  • TypeScript definitions
  • Fully accessible popovers & keyboard support
  • No framework dependencies

Table of contents


Installation

NPM

npm install jui-omnibar
import "jui-omnibar/omnibar.css";
import "jui-omnibar";

CDN (Quick start)

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/omnibar.css" />

<script type="module">
  import "https://cdn.jsdelivr.net/npm/[email protected]/dist/omnibar.js";
</script>

Pin to a specific version in production rather than using latest.


Usage

The tag itself, with its account attributes:

<jui-omnibar product="MIS" account="Highlands Academy" account-type="school" home="/"></jui-omnibar>
const omnibar = document.querySelector("jui-omnibar");

End-to-end example

Attributes only cover the product/account name shown in the bar itself — the product switcher, profile switcher, and nav icons are configured imperatively via JS properties. Here's everything wired together in one minimal page; see Configuration and Nav action icons below for the full option set each one supports.

<jui-omnibar
  id="omnibar"
  product="MIS"
  account="Highlands Academy"
  account-type="school"
  home="/"
></jui-omnibar>
const omnibar = document.getElementById("omnibar");

omnibar.productSwitcher = {
  current_product: "MIS",
  products: [
    { id: "mis", title: "MIS", href: "/mis", active: true },
    { id: "comms-hub", title: "Comms Hub", href: "/comms-hub" },
  ],
};

omnibar.profileSwitcher = {
  user_name: "Joe Bloggs",
  account: "Highlands Academy",
  account_type: "school",
  logout: () => {
    window.location.href = "/logout";
  },
};

// Nav icons are all optional — omit any of these to hide them
omnibar.help = "/help";
omnibar.inbox = "/inbox";
omnibar.inboxCount = 4;

Icons

All icons are provided as image URLs — the component no longer accepts inline SVG strings. Supply a light-mode URL and an optional dark-mode URL. The correct variant is shown automatically when data-theme="dark" is set on <body>.

{
  icon:      "/icons/my-icon.svg",       // shown in light mode
  icon_dark: "/icons/my-icon-dark.svg",  // shown in dark mode (optional)
}

If icon_dark is omitted, the single icon image is used in both modes.

Bundled icons

The package ships a set of icons at dist/icons/ (also available on the CDN). These are used internally and can be referenced directly if needed:

dist/icons/
  help.svg / help-dark.svg
  products.svg / products-dark.svg
  menu.svg / menu-dark.svg
  search.svg / search-dark.svg
  inbox.svg / inbox-dark.svg
  bookmarks.svg / bookmarks-dark.svg
  gainsight.svg / gainsight-dark.svg
  logout.svg / logout-dark.svg
  profile-action.svg / profile-action-dark.svg
  external-link.svg / external-link-dark.svg
  portal.svg / portal-dark.svg
  admin.svg / admin-dark.svg
  comms-hub.svg / comms-hub-dark.svg
  events.svg / events-dark.svg
  mis.svg / mis-dark.svg
  sonar-lite.svg / sonar-lite-dark.svg
  theme-toggle.svg / theme-toggle-dark.svg
  account-school.svg / account-school-dark.svg
  account-trust.svg / account-trust-dark.svg
  arrow-open.svg / arrow-open-dark.svg
  swap.svg / swap-dark.svg
  switch-account.svg / switch-account-dark.svg
  zendesk.svg / zendesk-dark.svg

Configuration

Product Switcher

current_product matches against title, not id.

omnibar.productSwitcher = {
  current_product: "MIS",
  help_href: "https://help.example.com",
  marketplace_href: "https://example.com/marketplace",   // shows a "Juniper Marketplace" footer button in the product switcher; omit to hide it
  products: [
    {
      id: "mis",
      title: "MIS",
      icon:            "/icons/mis.svg",
      icon_dark:       "/icons/mis-dark.svg",
      icon_colour:     "/icons/logo-mis.svg",
      product_gradient: "linear-gradient(135deg, #F45162 0%, #9E112F 100%)",
      href: "/mis",
      switch_account: false,
      active: true,
      data_tag: "product-mis",   // optional; rendered as data-tag on the product's link (e.g. for Gainsight targeting). Renders `data-tag=""` when unset — see "Data tags" below.
    },
    {
      id: "comms-hub",
      title: "Comms Hub",
      icon:            "/icons/comms-hub.svg",
      icon_dark:       "/icons/comms-hub-dark.svg",
      icon_colour:     "/icons/logo-comms-hub.svg",
      product_gradient: "linear-gradient(135deg, #00B1FA 0%, #005BE3 100%)",
      href: "/comms-hub",
      switch_account: true,   // shows "Available on other account" label
      active: false,
    },
  ],
};

Clicking a non-active product shows a redirect modal (countdown spinner, Cancel button, ESC to cancel) and then navigates to its href in the same tab once the countdown elapses. Clicking the active product does nothing (it's already open).

Each product carries its own brand identity via two independent, optional fields:

  • product_gradient — a CSS background-image value (typically a linear-gradient(...)) used as the background of that product's icon tile in the product switcher list and its redirect modal. Products without one fall back to the default purple gradient. The active product's product_gradient is also used as the text-fill color of the product name next to the logo (via background-clip: text).
  • icon_colour — a full-color logo image (no light/dark split, no background tile) shown next to the product name in the top-left of the omnibar for the active product. This is a separate field from icon/icon_dark (which drive the switcher list icons, forced to white on top of the gradient tile) — omit icon_colour to show no icon there.

The top-left of the omnibar is actually two separate links: the Juniper logo goes to the home attribute (tooltip "Go back to Portal"), and the product name/icon goes to the product-home attribute, defaulting to "/" — the home of the app you're currently in (tooltip "{product} Home").

When marketplace_href is set, a "Juniper Marketplace" button appears in the footer of the product switcher dropdown and opens the link in a new tab.

Pending products

A product can be marked temporarily unavailable with pending_until — it still appears in the list, but at reduced opacity with a "Pending" badge, and can't be clicked or navigated to.

{
  id: "sonar",
  title: "Sonar",
  href: "/sonar",
  pending_until: Math.floor(Date.now() / 1000) + 5 * 60,   // pending for the next 5 minutes
}
  • A number (Unix seconds since epoch — not JS milliseconds) auto-clears once that time passes — the item flips back to normal on its own, no page reload or config update needed.
  • true marks it pending indefinitely, until you update the config yourself (useful when you don't have — or don't want to compute — an exact expiry time).
  • Omit it, or leave it falsy, for a normal product.

Profile Switcher

If user_img is omitted, the avatar shows the user's initials (derived from user_name) on a joinup-purple background instead of an image.

omnibar.profileSwitcher = {
  user_name: "Joe Bloggs",
  user_img:  "https://...",   // omit to show initials instead
  account:      "Highlands Academy",
  account_type: "school",   // "school" | "trust" — controls the icon shown next to the account name

  product_title:       "MIS",
  product_icon:        "/icons/mis.svg",
  product_icon_dark:   "/icons/mis-dark.svg",
  product_icon_colour: "/icons/logo-mis.svg",   // overrides the active product's icon_colour, same as product_icon does for icon/icon_dark
  product_gradient: "linear-gradient(135deg, #F45162 0%, #9E112F 100%)",   // overrides the active product's product_gradient for the profile menu's icon tile; falls back to the default purple gradient

  logout: () => {
    console.log("Logout clicked");
  },

  actions: [
    {
      id:        "profile",
      label:     "Profile",
      icon:      "/icons/profile-action.svg",
      icon_dark: "/icons/profile-action-dark.svg",
      href:      "/portal/profile",
      data_tag:  "profile-action",   // optional; rendered as data-tag on the action's element (e.g. for Gainsight targeting). Renders `data-tag=""` when unset — see "Data tags" below.

      // Only rendered when the current product isn't "Portal" — see
      // "Redirect modal" below.
      badge:          "Open in portal",
      badge_icon:     "/icons/external-link.svg",
      badge_icon_dark:"/icons/external-link-dark.svg",

      modal_title:       "Portal",
      modal_description: "This will open Portal in a new tab",
      modal_delay:       3000,
      modal_icon:        "/icons/portal.svg",
      modal_icon_dark:   "/icons/portal-dark.svg",

      // Force-skip the redirect modal even outside Portal. You normally
      // don't need to set this — the modal already skips itself
      // automatically whenever the omnibar's current product is "Portal".
      skip_redirect_modal: false,
    },
    {
      id:        "custom",
      label:     "Custom action",
      icon:      "/icons/custom.svg",
      icon_dark: "/icons/custom-dark.svg",
      onSelect: ({ action }) => {
        console.log(action.id);
      },
    },
  ],

  other_accounts: [
    {
      id:   "magna",
      name: "Magna Academy",
      href: "/switch/magna",
      type: "school",
      data_tag: "other-account-magna",   // optional; rendered as data-tag on the account's link. Renders `data-tag=""` when unset — see "Data tags" below.
    },
  ],
};

Actions behaviour

| Property | Behaviour | | --- | --- | | href | Renders action as <a> | | no href | Renders action as <button> | | id: "profile" + href, current product isn't "Portal" | Shows the badge and a redirect modal before opening a new tab | | id: "profile" + href, current product is "Portal" | No badge; navigates like a normal same-tab link, no modal | | id: "profile" + href + skip_redirect_modal: true | No badge; navigates like a normal same-tab link, no modal, regardless of current product | | onSelect | Custom callback fired on click |


Redirect modal

Both switchers show a loading modal whenever navigating to a different app — the product switcher for any non-active product, the profile switcher for its "profile" action.

// Profile action
{
  id:                "profile",
  href:              "/portal/profile",
  modal_title:       "Portal",
  modal_description: "This will open Portal in a new tab",
  modal_delay:       3000,          // ms before redirect
  modal_icon:        "/icons/portal.svg",
  modal_icon_dark:   "/icons/portal-dark.svg",
}
  • Countdown spinner shown during delay
  • Cancel button stops the redirect
  • ESC key also cancels
  • Product switcher: after the countdown, navigates to the product's href in the same tab. Not configurable per-product (fixed 3s delay, no badge, no skip option) — switching apps always needs the loading state, and there's no "already there" case to skip it for.
  • Profile switcher: after the countdown, opens href in a new tab — the current tab is left as-is so your workflow there isn't lost. The "profile" action's badge and modal are both skipped automatically whenever the omnibar's current product (productSwitcher.current_product / profileSwitcher.product_title) is "Portal", since the link then just leads back into the app that's already open and can navigate in the same tab with no loading state. Set skip_redirect_modal: true on the "profile" action to force-skip the modal (but not the badge) in other products too.

Nav action icons

Other than the product switcher and profile switcher, every icon in the omnibar nav is optional: it only renders when you provide a value, and is hidden when left null/unset. Each one accepts either:

  • a string — renders the icon as an <a href="..."> opening in a new tab, or
  • a function — renders the icon as a <button> that calls your callback with { component } on click

They appear in the nav in this order (right to left, i.e. closest to the profile switcher first):

| Order | Property | Tooltip | Notes | | --- | --- | --- | --- | | 1 (rightmost) | help | "Help" | Falls back to productSwitcher.help_href, then a default Juniper help URL, when unset — so Help is effectively always shown unless you override getHelpHref behaviour by setting one of those | | 2 | gainsight | "Take a tour" | | | 3 | zendesk | "Contact Support" | | | 4 | inbox | "Inbox" | Supports a count badge via inboxCount | | 5 | bookmarks | "Bookmarks" | Supports a count badge via bookmarksCount | | 6 (leftmost) | search | "Search" | |

// Link
omnibar.inbox = "/inbox";

// Button with a callback
omnibar.gainsight = ({ component }) => {
  // trigger your Gainsight integration
};

// Hide any of them
omnibar.zendesk = null;

Each icon renders with a fixed data-tag value (e.g. for Gainsight targeting) — see Data tags. These are not consumer-overridable.

inboxCount and bookmarksCount show a small count badge on the corner of the Inbox/Bookmarks icon. Set to 0, null, or leave unset to hide the badge; counts above 99 display as "99+".

omnibar.inbox = "/inbox";
omnibar.inboxCount = 4;

omnibar.bookmarks = "/bookmarks";
omnibar.bookmarksCount = 0;   // badge hidden

Other accounts

other_accounts: [
  {
    id:   "account-id",
    name: "Magna Academy",
    href: "/switch",
    type: "school",   // "school" | "trust"
  },
];

Hidden when the array is empty. A long list scrolls internally past a handful of accounts, with a fade cue at the bottom to hint there's more — and if the menu as a whole doesn't fit the window's height, it scrolls too.


Data tags

Every clickable element in the omnibar renders a data-tag attribute (used for analytics/Gainsight targeting).

Most elements — the nav icon buttons, the logo/home link, the burger button, the product/profile switcher toggle buttons, the marketplace footer link, the Logout button, and the redirect modals' Cancel buttons — render a fixed data-tag value baked into this package. These are not consumer-overridable, so tracking stays stable across every embed:

| Element | data-tag | | --- | --- | | Logo link (home attribute) | omnibar_home_link+ba42e2f0-8777-4a46-9f70-6501bb4812b7 | | Product name link next to the logo | omnibar_product_name_link+89660215-77e0-4ba4-9371-8e72e1782fcd | | Help nav button | omnibar_help_link+3a256eca-ff3c-439b-ade5-647651ac61c0 | | Take a tour (Gainsight) nav button | omnibar_take_a_tour_icon+0565f03e-2265-439f-aa10-0f0ab5e8dee8 | | Contact Support (Zendesk) nav button | omnibar_contact_support_icon+594117b8-5858-44b5-9e85-ce41bfab1221 | | Bookmarks nav button | omnibar_add_bookmark+41981642-cfae-4f43-9ef4-6beb4dd4b78d | | Inbox nav button | omnibar_inbox_link+9a0d0dd5-a366-431b-972c-ab0aa49e91f4 | | Search nav button | super_search_trigger_button+6fbe4c5d-1887-4ca7-9c69-c973c2864738 | | Product switcher search input | product_switcher_search_input+05f0994c-2018-452d-a9fa-163850cb3dc5 | | Burger/mobile menu button | omnibar_menu_toggle_button+e8367ccb-3c1f-478a-837c-c8c376776323 | | Product switcher toggle button | omnibar_app_switcher_button+2b10755e-2ac6-43b2-9219-699913a660ff | | Profile switcher toggle button (avatar) | omnibar_account_button+6e18c400-1465-470a-820b-b454ef7443d4 | | "Juniper Marketplace" footer link | product_switcher_marketplace_footer_link+e35bbbfc-1d4f-4a90-86f2-0556f8b66e23 | | Product/profile redirect modal Cancel button | product_switcher_redirect_modal_cancel_button+b54ffe13-e4d1-4f69-9fbe-6bad6253e8a8 / profile_switcher_redirect_modal_cancel_button+fe23ab5e-4691-4af3-9281-fd223fe5a544 | | Logout button | profile_switcher_logout_button+a56538a2-0bfc-45fd-b83f-9793d126e3d8 |

API-driven items fall back to a shared default data-tag and can be overridden per-item by setting data_tag on the relevant item:

  • productSwitcher.products[].data_tag (product switcher dropdown items) — default product_switcher_list_item_link+4ec911d1-15ad-4c86-b18e-2ebc54766290
  • profileSwitcher.actions[].data_tag (profile dropdown actions, e.g. "Profile") — default profile_switcher_action_item+335ff918-b63b-4a19-92fa-0c3d31c1deb5
  • profileSwitcher.other_accounts[].data_tag (other-account links) — default profile_switcher_other_accounts_link+ecbcd8f6-ffa3-4c6a-865d-433f117b1c9f

Attributes

| Attribute | Description | | -------------- | ----------------------------------------------------------- | | product | Current product name | | account | Current account name | | account-type | "school" (default) or "trust" — icon shown next to the account name | | home | Juniper logo link href ("Go back to Portal") | | product-home | Product name/icon link href ("{product} Home") — defaults to "/" | | environment | "demo", "staging", or "dev" (case-insensitive — "Demo"/"DEMO" also match) — shows a matching badge next to the account name. Any other value (or unset) shows no badge. |


Events

omnibar.addEventListener("jui:menu-toggle", (event) => {
  console.log(event.detail); // { source: "burger", component }
});

omnibar.addEventListener("jui:profile-action", (event) => {
  console.log(event.detail.action); // the action object
});

omnibar.addEventListener("jui:logout", () => {
  console.log("Logout fired");
});

Dark mode

Dark mode is activated by setting data-theme="dark" on <body>:

document.body.setAttribute("data-theme", "dark");

All icon icon_dark variants switch automatically — no JavaScript required.


Styling

import "jui-omnibar/omnibar.css";

Key CSS variables:

:root {
  --j-o-color-brand-primary:   #271a38;
  --j-o-color-brand-secondary: #814af4;
  --j-o-font-family: "Inter", sans-serif;
}

Loading strategy (avoiding layout jank)

<jui-omnibar> is a plain custom element with position: fixed, so once it renders it never causes a layout shift in the rest of the page — but if its script/CSS load after the rest of your app, you'll see it pop in a moment later, which reads as jarring. The fix in every framework is the same: get the omnibar's script and stylesheet loading before/independently of your app framework's bundle, not bundled inside it.

The package ships a jui-omnibar:not(:defined) rule in omnibar.css that renders an empty bar in the header's exact final position, size, and background color the instant the stylesheet loads — before the component's JS has even finished loading. As long as the stylesheet is a normal blocking <link rel="stylesheet"> in <head> (not injected late, not deferred), there's a correctly-colored bar on first paint, and the real content simply appears inside it once the script runs — no pop-in, no shift.

<!-- In <head>, not bundled with your app JS -->
<link rel="stylesheet" href="/path/to/omnibar.css" />
<link rel="modulepreload" href="/path/to/omnibar.js" />

modulepreload (or <link rel="preload" as="script"> for non-module builds) tells the browser to fetch the script at high priority in parallel with everything else, without executing it yet — it still executes wherever your actual <script type="module">/import is, but the network round-trip is no longer on the critical path.

Vanilla HTML

Put the tag and its assets directly in the HTML — nothing to coordinate:

<head>
  <link rel="stylesheet" href="/dist/omnibar.css" />
</head>
<body>
  <jui-omnibar product="MIS" account="Highlands Academy"></jui-omnibar>

  <script type="module" src="/dist/omnibar.js"></script>
  <script type="module">
    document.querySelector("jui-omnibar").profileSwitcher = {
      /* ... */
    };
  </script>
</body>

Vue

The jank usually comes from the omnibar being written inside a .vue component, so it only appears once Vue's own bundle has downloaded, parsed, and mounted. Instead, put <jui-omnibar> directly in index.html, outside #app, so it's real DOM from the first byte — Vue never needs to render it:

<!-- index.html -->
<link rel="stylesheet" href="/dist/omnibar.css" />
<script type="module" src="/dist/omnibar.js"></script>

<body>
  <jui-omnibar id="omnibar" product="MIS"></jui-omnibar>
  <div id="app"></div>
</body>

Then configure it imperatively once your data is ready, rather than through a template — onMounted (or even earlier, a plugin/main.js top-level call) is fine since the element itself is already on screen and doesn't need Vue to exist for that:

// main.js, or a small composable
onMounted(() => {
  document.getElementById("omnibar").profileSwitcher = {
    user_name: store.user.name,
    // ...
  };
});

If you tell Vue to ignoredElements: [/^jui-/] (Vue 3 app.config.compilerOptions.isCustomElement) you can still place <jui-omnibar> inside a .vue template and bind props reactively (:profile-switcher="...") — that's fine for configuring it, just keep the tag itself, its script, and its stylesheet outside anything that's lazy-loaded or behind a route-level code-split chunk.

React

Same principle: declare the element in your static HTML shell (public/index.html for CRA, index.html for Vite, or the root layout for Next.js), not inside a component that only renders after React hydrates.

<!-- public/index.html -->
<link rel="stylesheet" href="/dist/omnibar.css" />
<script type="module" src="/dist/omnibar.js"></script>
<body>
  <jui-omnibar id="omnibar"></jui-omnibar>
  <div id="root"></div>
</body>
// index.jsx / App.jsx — set props as early as possible
useLayoutEffect(() => {
  const omnibar = document.getElementById("omnibar");
  omnibar.profileSwitcher = { user_name: user.name /* ... */ };
}, [user]);

useLayoutEffect over useEffect here just avoids one extra paint between mount and prop assignment — not critical, but free. If you'd rather manage it fully inside React (e.g. an SSR/Next.js app where you don't control a separate static shell), keep the <link>/<script> tags in <Head> and render <jui-omnibar> as the very first element in your root layout rather than nested inside a client-only bundle or a lazy route.

Laravel / Blade

This is the easiest case: Blade renders on the server, so the omnibar can be in the very first HTML response with real user data already filled in — no client-side JS framework needs to exist first.

{{-- layout.blade.php, in <head> --}}
<link rel="stylesheet" href="{{ asset('vendor/jui-omnibar/omnibar.css') }}">
<script type="module" src="{{ asset('vendor/jui-omnibar/omnibar.js') }}"></script>

{{-- immediately after <body> opens --}}
<jui-omnibar
  product="{{ $currentProduct }}"
  account="{{ $account->name }}"
  account-type="{{ $account->type }}"
></jui-omnibar>

<script type="module">
  document.querySelector("jui-omnibar").profileSwitcher = @json([
    'user_name' => $user->name,
    'account' => $account->name,
    // ...
  ]);
</script>

Because everything here is server-rendered and inline, there's no client-side bundle to wait for at all — the :not(:defined) skeleton only covers the brief gap while omnibar.js itself downloads and parses.


Package structure

dist/
  omnibar.js
  product-switcher.js
  profile-switcher.js
  icons.js
  omnibar.css
  omnibar.d.ts
  icons/
    *.svg           (light mode)
    *-dark.svg      (dark mode)

Development

npm run build

Accessibility

  • Keyboard navigation (ESC closes menus and modals)
  • Focus management on close
  • ARIA roles, labels, and expanded states
  • Screen reader announcements for loading states

Security

All consumer-supplied strings (product/action/account titles, user names, badge text, etc.) are HTML-escaped before rendering — safe to pass through values you haven't sanitized yourself.

Every href/icon URL (product.href, action.href, other_accounts[].href, icon/icon_dark/modal_icon/user_img, etc.) is passed through an allowlist: relative URLs and http:/https:/mailto:/tel: are permitted, everything else (javascript:, data:, and other script-executing schemes) is replaced with #.


Migration from v3.0.x

All SVG string props have been replaced with image URL props:

| Before (v3.0.x) | After (v3.1.0) | | --- | --- | | icon_svg: "<svg>...</svg>" | icon: "/path/to/icon.svg" + optional icon_dark | | badge_icon_svg | badge_icon + badge_icon_dark | | product_icon_svg | product_icon + product_icon_dark | | modal_icon_svg | modal_icon + modal_icon_dark |


Migration from v3.x (v4.0.0)

  • omnibar.uservoice has been removed. There is no direct replacement — it was a single-purpose href-only button. If you still need a link to an external feedback tool, repurpose one of the new nav action icons (e.g. omnibar.search, omnibar.inbox, or omnibar.bookmarks) with your URL as the value.
  • gainsight and zendesk now also accept a string (rendered as a link) in addition to a callback function — existing callback usage is unaffected.
  • Nav icon order changed. Right to left it's now: Profile, Product switcher, Help, Take a tour, Contact Support, Inbox, Bookmarks, Search. help is a new top-level property (previously only configurable via productSwitcher.help_href, which still works as a fallback).

Migration from v4.x (v5.0.0)

  • The product name/icon area next to the logo no longer renders from icon/icon_dark. It now requires a new, separate icon_colour field (a full-color logo image, no background tile) on the active product — set it in productSwitcher.products[] (or override directly via profileSwitcher.product_icon_colour). If you don't add icon_colour, that icon simply won't render — there's no fallback to icon/icon_dark, since those are a different visual treatment (forced white on a gradient tile, meant for the switcher list) than the full-color logo this area now shows.
  • New optional product_gradient field on each product — a CSS background-image value used for that product's icon tile in the switcher list/redirect modal and the active product's name text color. Products without one keep rendering with the previous default purple gradient, so this part is backwards-compatible.

License

MIT