Build a custom flow for viewing a user's organization memberships
This guide will demonstrate how to use Clerk's API to build a custom flow for viewing the list of a user's organization memberships.
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 table.
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, useUser } from '@clerk/nextjs';
export const userMembershipsParams = {
memberships: {
pageSize: 5,
keepPreviousData: true,
},
};
// List of the user's organization memberships.
export const JoinedOrganizations = () => {
const { user } = useUser();
const { isLoaded, userMemberships } = useOrganizationList({
userMemberships: userMembershipsParams,
});
if (!isLoaded) {
return <>Loading</>;
}
return (
<>
<h1>Joined organizations</h1>
<table>
<thead>
<tr>
<th>Identifier</th>
<th>Organization</th>
<th>Joined</th>
<th>Role</th>
</tr>
</thead>
<tbody>
{userMemberships?.data?.map((mem) => (
<tr key={mem.id}>
<td>{mem.publicUserData.identifier}</td>
<td>{mem.organization.name}</td>
<td>{mem.createdAt.toLocaleDateString()}</td>
<td>{mem.role}</td>
</tr>
))}
</tbody>
</table>
<div>
<button
disabled={
!userMemberships?.hasPreviousPage || userMemberships?.isFetching
}
onClick={() => userMemberships?.fetchPrevious?.()}
>
Previous
</button>
<button
disabled={
!userMemberships?.hasNextPage || userMemberships?.isFetching
}
onClick={() => userMemberships?.fetchNext?.()}
>
Next
</button>
</div>
</>
);
};
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 table.
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>
<h2>Joined organizations</h2>
<table id="memberships_table">
<thead>
<tr>
<th>Identifier</th>
<th>Organization</th>
<th>Joined</th>
<th>Role</th>
</tr>
</thead>
<tbody id="memberships_table_body"></tbody>
</table>
<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 { data } = await clerk.user.getOrganizationMemberships();
const memberships = data;
memberships.map((membership) => {
const membershipTable = document.getElementById('memberships_table');
const row = membershipTable.insertRow();
row.insertCell().textContent = membership.publicUserData.identifier;
row.insertCell().textContent = membership.organization.name;
row.insertCell().textContent = membership.createdAt.toLocaleDateString();
row.insertCell().textContent = membership.role;
});
} 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 {
// If there is no active user, mount Clerk's <SignIn />
document.getElementById('app').innerHTML = `
<div id="sign-in"></div>
`;
const signInDiv = document.getElementById('sign-in');
clerk.mountSignIn(signInDiv);
}