Skip to main content
/
/
/
/
Profile picture

Profile picture

Top bar profile picture

Use .bf-nav-profile on a profile image to get a circular, bordered picture.

<img className="bf-nav-profile" src="..." />

Use it with <Nav.Group> to create a dropdown button.

<Nav.Group
  name={<img className="bf-nav-profile" src="..." alt="Profile menu" />}
>
  [dropdown content...]
</Nav.Group>

Then place it as the last sibling in the top prop of your <Nav>.

<Nav top={
  <>
    [other top bar items, if any...]
    <Nav.Group ... />
  </>
}>
Skip to main content
[dropdown content...]

Profile dropdown content

Inside <Nav.Group> you can use <section> to get spacing around sections of items, and <hr> for a horizontal line separator.

Also see <Nav> and useApplyColorMode() docs.

import useLocalStorageState from "use-local-storage-state";
import React, { useState } from "react";
import { faUser, faSignOutAlt } from "@fortawesome/free-solid-svg-icons";
import Nav from "@intility/bifrost-react/Nav";
import Checkbox from "@intility/bifrost-react/Checkbox";
import useApplyColorMode from "@intility/bifrost-react/hooks/useApplyColorMode";
import type { ColorMode } from "@intility/bifrost-react";

// Can be replaced by the component from the next example
const ProfilePicture = () => (
  <img
    className="bf-nav-profile"
    src="https://picsum.photos/id/152/100/100"
    alt=""
  />
);

export default function ProfilePictureDropdownDemo() {
  const [lang, setLang] = useState("English");

  // persist color mode state in local storage.
  // you might want to use a cookie or a database instead?
  const [colorMode, setColorMode] = useLocalStorageState<ColorMode>(
    "colorMode", // local storage key
    {
      defaultValue: "system",
    },
  );

  // keep document color mode in sync with state
  useApplyColorMode(colorMode);

  // If you're using create.intility.app template (@azure/msal-browser)
  //import instance from '~/auth'
  //const logout = () => instance.logoutRedirect()

  return (
    <div className="page-demo">
      <Nav
        logo="Demo App"
        top={
          <Nav.Group name={<ProfilePicture />}>
            <a href="#path">
              <Nav.Item icon={faUser}>My profile</Nav.Item>
            </a>
            <hr />
            <section>
              <Nav.Header>Language</Nav.Header>
              <Checkbox
                type="radio"
                label="English"
                name="language"
                checked={lang === "English"}
                onChange={() => setLang("English")}
              />
              <Checkbox
                type="radio"
                label="Norsk"
                name="language"
                checked={lang === "Norsk"}
                onChange={() => setLang("Norsk")}
              />
            </section>
            <section>
              <Nav.Header>Color mode</Nav.Header>
              <Checkbox
                type="radio"
                label="Light"
                name="color-mode"
                checked={colorMode === "light"}
                onChange={() => setColorMode("light")}
              />
              <Checkbox
                type="radio"
                label="Dark"
                name="color-mode"
                checked={colorMode === "dark"}
                onChange={() => setColorMode("dark")}
              />
              <Checkbox
                type="radio"
                label="System"
                name="color-mode"
                checked={colorMode === "system"}
                onChange={() => setColorMode("system")}
              />
            </section>
            <hr />
            <button
              type="button"
              onClick={() => {
                // logout() // from useAuth hook or msal instance
              }}
            >
              <Nav.Item icon={faSignOutAlt}>Sign out</Nav.Item>
            </button>
          </Nav.Group>
        }
      >
        Click the profile picture to show a dropdown with user-specific links,
        global app settings and a log out button.
      </Nav>
    </div>
  );
}

Authenticated user

The following code will fetch the current user's photo from Microsoft Graph, with a faUser icon as fallback.

You can use this custom <ProfilePicture> component in the name prop of the <Nav.Group>, as shown in the example above.

import useSWRImmutable from "swr/immutable";
// if you're using /src/auth/fetch.ts from create.intility.app template
import { authorizedFetch } from "~/auth";
import { faUser } from "@fortawesome/pro-solid-svg-icons";
import Icon from "@intility/bifrost-react/Icon";

const fetcher = (url: string) =>
  authorizedFetch(url)
    .then((r) => {
      if (!r.ok) throw new Error("Could not fetch photo from graph");
      return r.blob();
    })
    // createObjectURL creates a DOMString containing a URL representing the blob
    .then(URL.createObjectURL);

const ProfilePicture = () => {
  // The profile picture will rarely change between refreshes
  // https://swr.vercel.app/docs/revalidation#disable-automatic-revalidations
  const { data, error } = useSWRImmutable(
    "https://graph.microsoft.com/v1.0/me/photos/48x48/$value",
    fetcher,
  );

  if (!data || error) return <Icon icon={faUser} />;
  return <img className="bf-nav-profile" src={data} alt="Profile picture" />;
};

export default ProfilePicture;