šŸ“ Sign Up | šŸ” Log In

← Root | ↑ Up

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │ šŸ“„ shadcn/directory/clerk/clerk-docs/guides/development/custom-flows/organizations/organization-switcher │ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

╔══════════════════════════════════════════════════════════════════════════════════════════════╗
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘

title: Build a custom flow for switching organizations description: Learn how to use the Clerk API to build a custom flow for switching between organizations.

<Include src="_partials/custom-flows-callout" />

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

<Tabs items={["Next.js", "JavaScript"]}> <Tab> Two examples are provided: one for a paginated list and one for an infinite list.

The following examples:

1. Use the [`useOrganizationList()`](/docs/reference/hooks/use-organization-list) hook to get `memberships`, which is a list of the current user's organization memberships. `memberships` returns `data`, which is an array of [`OrganizationMembership`](/docs/reference/javascript/types/organization-membership) objects.
1. Map over the `data` array to display the user's organization memberships in a table, providing a button that calls `setActive()` to set the selected organization as the [active organization](!active-organization).
   - If there are no organizations, the [`<CreateOrganization />` component (custom-flow version, not the Clerk component)](/docs/guides/development/custom-flows/organizations/create-organizations) is rendered to allow the user to create an organization.

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 the `fetchNext()` method is used to load more organizations if they are available.
- The "Infinite list" example sets the `infinite` option to `true` to enable infinite results.

This example is written for Next.js App Router but can be adapted for any React-based framework.

<CodeBlockTabs options={["Paginated list", "Infinite list"]}>
  ```jsx {{ filename: 'app/components/CustomOrganizationSwitcher.tsx', collapsible: true }}
  'use client'

  import { useAuth, useOrganizationList } from '@clerk/nextjs'
  import CreateOrganization from '../components/create-organization' // See /docs/guides/development/custom-flows/organizations/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>
        )}
      </>
    )
  }
  ```

  ```jsx {{ filename: 'app/components/CustomOrganizationSwitcher.tsx', collapsible: true }}
  'use client'

  import { useAuth, useOrganizationList } from '@clerk/nextjs'
  import CreateOrganization from '../components/create-organization' // See /docs/guides/development/custom-flows/organizations/create-organizations for this component

  // List user's organization memberships
  export default function JoinedOrganizations() {
    const { isLoaded, setActive, userMemberships } = useOrganizationList({
      userMemberships: {
        // Set pagination parameters
        infinite: 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>
        )}
        {userMemberships?.data?.length === 0 && (
          <div>
            <p>No organizations found</p>
            <CreateOrganization />
          </div>
        )}
      </>
    )
  }
  ```
</CodeBlockTabs>
</Tab> <Tab> The following example:
1. Calls the [`getOrganizationMemberships()`](/docs/reference/javascript/user#get-organization-memberships) method to retrieve the list of organizations the current user is a part of. This method returns `data`, which is an array of [`OrganizationMembership`](/docs/reference/javascript/types/organization-membership) objects.
1. Maps over the `data` array to display the user's organization memberships in a list, providing a button that calls [`setActive()`](/docs/reference/javascript/clerk#set-active) 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.

<CodeBlockTabs options={["index.html", "main.js"]}>
  ```html {{ filename: 'index.html', collapsible: true }}
  <!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>
        <thead>
          <tr>
            <th>Identifier</th>
            <th>Organization</th>
            <th>Joined</th>
            <th>Role</th>
            <th>Set as active org</th>
          </tr>
        </thead>
        <tbody id="memberships-table-body"></tbody>
      </table>

      <div id="create-organization-container" hidden>
        <h1>Create an organization</h1>
        <form id="create-organization">
          <label for="name">Name</label>
          <input id="name" name="name" />
          <button>Create organization</button>
        </form>
      </div>

      <script type="module" src="/src/main.js" async crossorigin="anonymous"></script>
    </body>
  </html>
  ```

  ```js {{ filename: 'main.js', collapsible: true }}
  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('{{pub_key}}')
  await clerk.load()

  if (clerk.isSignedIn) {
    // 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-body')
        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

        // Set as active organization
        const addBtn = document.createElement('button')
        addBtn.textContent = 'Set as active'
        addBtn.addEventListener('click', async function (e) {
          e.preventDefault()

          await clerk
            .setActive({ organization: membership.organization.id })
            .then((res) => {
              console.log('Set as active:', res)
            })
            .catch((err) => {
              // See https://clerk.com/docs/guides/development/custom-flows/error-handling
              // for more info on error handling
              console.error(JSON.stringify(err, null, 2))
            })
        })
        row.insertCell().appendChild(addBtn)
      })
    } else {
      // If there is no active organization,
      // render a form to create an organization
      document.getElementById('create-organization-container').removeAttribute('hidden')
      const form = document.getElementById('create-organization')

      form.addEventListener('submit', function (e) {
        e.preventDefault()

        const inputEl = document.getElementById('name')

        if (!inputEl) {
          // ... handle empty input
          return
        }

        clerk
          .createOrganization({ name: inputEl.value })
          .then((res) => console.log(res))
          .catch((error) => console.log('An error occurred:', error))
      })
    }
  } else {
    // If there is no active user, mount Clerk's <SignIn />
    // or add your sign-in custom flow
    document.getElementById('app').innerHTML = `
      <div id="sign-in"></div>
    `

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

    clerk.mountSignIn(signInDiv)
  }
  ```
</CodeBlockTabs>
</Tab> </Tabs>
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•

← Root | ↑ Up