Build a custom flow for switching organizations
This guide will demonstrate how to use the Clerk API to build a custom flow for switching between organizations.
Two examples are provided: one for a paginated list and one for an infinite list.
The following examples:
- Use the
useOrganizationList()
hook to getmemberships
, which is a list of the current user's organization memberships.memberships
returnsdata
, which is an array ofOrganizationMembership
objects. - Map over the
data
array to display the user's organization memberships in a table, providing a button that callssetActive()
to set the selected organization as the active organization.- If there are no organizations, the
<CreateOrganization />
component (custom-flow version, not the Clerk component) is rendered to allow the user to create an organization.
- If there are no organizations, the
The difference between the two examples is the parameters passed to the useOrganizationList()
hook in order to determine how the list is paginated.
- The "Paginated list" example provides a button to load more organizations if there are more available. The
data
array is paginated and will only return the first 5 results, so thefetchNext()
method is used to load more organizations if they are available. - The "Infinite list" example sets the
infinite
option totrue
to enable infinite results.
This example is written for Next.js App Router but can be adapted for any React-based framework.
'use client'
import { useAuth, useOrganizationList } from '@clerk/nextjs'
import CreateOrganization from '../components/create-organization' // See /docs/custom-flows/create-organizations for this component
// List user's organization memberships
export default function JoinedOrganizations() {
const { isLoaded, setActive, userMemberships } = useOrganizationList({
userMemberships: {
// Set pagination parameters
pageSize: 5,
keepPreviousData: true,
},
})
const { orgId } = useAuth()
if (!isLoaded) {
return <p>Loading...</p>
}
return (
<>
<h1>Joined organizations</h1>
{userMemberships?.data?.length > 0 && (
<>
<table>
<thead>
<tr>
<th>Identifier</th>
<th>Organization</th>
<th>Joined</th>
<th>Role</th>
<th>Set as active org</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>
<td>
{orgId === mem.organization.id ? (
<button onClick={() => setActive({ organization: mem.organization.id })}>
Set as active
</button>
) : (
<p>Currently active</p>
)}
</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>
</>
)}
{userMemberships?.data?.length === 0 && (
<div>
<p>No organizations found</p>
<CreateOrganization />
</div>
)}
</>
)
}
Feedback
Last updated on