Docs

Build a custom flow for switching organizations

Caution

This guide is for users who want to build a custom user interface using the Clerk API. To switch organizations using a prebuilt UI, you should use Clerk's <OrganizationSwitcher /> component.

This guide will demonstrate how to use Clerk's API to build a custom flow for switching between organizations.

The following example:

  • Uses the useOrganizationList() hook to get memberships, which is a list of the current user's organization memberships. memberships returns data, which is an array of OrganizationMembership objects.
  • Maps over the data array to display the user's organization memberships in a list.
  • Provides a button that calls setActive() to set the selected organization as the active organization.
  • Provides a button to load more organizations if there are more available. The data array is paginated and will only return the first 10 results, so the fetchNext() method is used to load more organizations if they are available.

This example is written for Next.js App Router but can be adapted for any React meta framework, such as Remix or Gatsby.

app/components/CustomOrganizationSwitcher.tsx
"use client"

import { useOrganizationList } from "@clerk/nextjs";

export const CustomOrganizationSwitcher = () => {
  const { isLoaded, setActive, userMemberships } = useOrganizationList({
    userMemberships: {
      infinite: true,
    },
  });

  if (!isLoaded) {
    return <p>Loading</p>;
  }

  return (
    <>
      <h1>Custom Organization Switcher</h1>
      <ul>
        {userMemberships.data?.map((mem) => (
          <li key={mem.id}>
            <span>{mem.organization.name}</span>
            <button
              onClick={() => setActive({ organization: mem.organization.id })}
            >
              Select
            </button>
          </li>
        ))}
      </ul>

      <button
        disabled={!userMemberships.hasNextPage}
        onClick={() => userMemberships.fetchNext()}
      >
        Load more organizations
      </button>
    </>
  );
};

The following example:

  1. Calls the getOrganizationMemberships() method to retrieve the list of organizations the current user is a part of. This method returns data, which is an array of OrganizationMembership objects.
  2. Maps over the data array to display the user's organization memberships in a list.
  3. Provides a button that calls setActive() to set the selected organization as the active organization.

Use the tabs to view the code necessary for the index.html and main.js files.

index.html
<!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <title>Clerk + JavaScript App</title>
    </head>
    <body>
      <div id="app"></div>

      <h1>Custom Organization Switcher</h1>
      <ul id="custom-org-switcher"></ul>

      <script
        type="module"
        src="/src/main.js"
        async
        crossorigin="anonymous"
      ></script>
    </body>
  </html>
main.js
import { Clerk } from '@clerk/clerk-js';

  const pubKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;

  if (!pubKey) {
    throw new Error('Add your VITE_CLERK_PUBLISHABLE_KEY to .env file');
  }

  const clerk = new Clerk('YOUR_PUBLISHABLE_KEY');
  await clerk.load();

  if (clerk.user) {
    // Check for an active organization
    if (clerk.organization) {
      const orgList = document.getElementById('custom-org-switcher');
      try {
        const { data } = await clerk.user.getOrganizationMemberships();
        const userMemberships = data;

        userMemberships.map((membership) => {
          const li = document.createElement('li');
          li.textContent = membership.organization.name;
          const button = document.createElement('button');
          button.textContent = 'Select';
          button.addEventListener('click', async function () {
            await clerk.setActive({ organization: membership.organization.id });
          });
          li.appendChild(button);
          orgList.appendChild(li);
        });
      } catch (err) {
        console.error(err);
      }
    } else {
      // If there is no active organization,
      // mount Clerk's <OrganizationSwitcher />
      // to allow the user to set an organization as active
      document.getElementById('app').innerHTML = `
        <h2>Select an organization to set it as active</h2>
        <div id="org-switcher"></div>
      `;

      const orgSwitcherDiv = document.getElementById('org-switcher');

      clerk.mountOrganizationSwitcher(orgSwitcherDiv);
    }
  } else {
    document.getElementById('app').innerHTML = `
      <div id="sign-in"></div>
    `;

    const signInDiv = document.getElementById('sign-in');

    clerk.mountSignIn(signInDiv);
  }

Feedback

What did you think of this content?