Build a custom flow for switching organizations
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 getmemberships
, which is a list of the current user's organization memberships.memberships
returnsdata
, which is an array ofOrganizationMembership
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 thefetchNext()
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.
"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:
- Calls the
getOrganizationMemberships()
method to retrieve the list of organizations the current user is a part of. This method returnsdata
, which is an array ofOrganizationMembership
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.
Use the tabs to view the code necessary for the index.html
and main.js
files.
<!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>
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);
}