Manage Member Roles
Learn how to manage member roles in an organization
Overview
Clerk provides the ability for the currently signed-in user to view all the organizations they are members of. In React and Next.js applications, this is done with the useOrganizationList()
hook, which returns organizationList
.
Organization administrators are able to manage the member roles within an organization. Admins can change the role of a member and also remove a member from an organization.
Usage
View all organizations the current user belongs to
1// Lists all organization the user is a member of.2// Each entry can be a link to a page to manage organization3// members.45// If you create a new Organization, this list will update automatically.6import { useOrganizationList } from "@clerk/nextjs";7import Link from "next/link";89const OrganizationList = () => {10const { organizationList, isLoaded } = useOrganizationList();1112if (!isLoaded) {13// Any loading state14return null;15}1617return (18<div>19<h2>Your organizations</h2>20{organizationList.length === 0 ? (21<div>You do not belong to any organizations yet.</div>22) : (23<ul>24{organizationList.map(({ organization }) => (25<li key={organization.id}>26<Link27href={`/organizations/${organization.id}`}28>29<a>{organization.name}</a>30</Link>31</li>32))}33</ul>34)}35</div>36);37};
1// Lists all organization the user is a member of.2// Each entry can be a link to a page to manage organization3// members.45// If you create a new Organization, this list will update automatically.6import { useOrganizationList } from "@clerk/clerk-react";78const OrganizationList = () => {9const { organizationList, isLoaded } = useOrganizationList();1011if (!isLoaded) {12// Any loading state13return null;14}1516return (17<div>18<h2>Your organizations</h2>19{organizationList.length === 0 ? (20<div>You do not belong to any organizations yet.</div>21) : (22<ul>23{organizationList.map(({ organization }) => (24<li key={organization.id}>25<a href={`/organizations/${organization.id}`}>{organization.name}</a>26</li>27))}28</ul>29)}30</div>31);32};
1<ul id="organizations_list"></ul>23<script>4const list = document.getElementById("organizations_list");5try {6const organizationMemberships = await window.Clerk.getOrganizationMemberships();7organizationMemberships.map((membership) => {8const li = document.createElement("li");9li.textContent = `${membership.organization.name} - ${membership.role}`;10list.appendChild(li);11});12} catch (err) {13console.error(err);14}15</script>16
Manage organization members
1// pages/organizations/[id].ts2import { useState, useEffect } from "react";3import { useOrganization } from "@clerk/nextjs";4import type { OrganizationMembershipResource } from "@clerk/types";56// View and manage active organization members, along with any7// pending invitations.8// Invite new members.9export default function Organization() {10const {11organization: currentOrganization,12membership,13isLoaded,14} = useOrganization();1516if (!isLoaded || !currentOrganization) {17return null;18}1920const isAdmin = membership.role === "admin";21return (22<>23<h1>Organization: {currentOrganization.name}</h1>24<MemberList />25{isAdmin && <InvitationList />}26</>27);28}2930// List of organization memberships. Administrators can31// change member roles or remove members from the organization.32function MemberList() {33const { membershipList, membership } = useOrganization({34membershipList: {},35});3637if (!membershipList) {38return null;39}4041const isCurrentUserAdmin = membership.role === "admin";4243return (44<div>45<h2>Organization members</h2>46<ul>47{membershipList.map((m) => (48<li key={m.id}>49{m.publicUserData.firstName} {m.publicUserData.lastName} <50{m.publicUserData.identifier}> :: {m.role}51{isCurrentUserAdmin && <AdminControls membership={m} />}52</li>53))}54</ul>55</div>56);57}5859function AdminControls({60membership,61}: {62membership: OrganizationMembershipResource;63}){64const [disabled, setDisabled] = useState(false);65const {66user: { id: userId },67} = useUser();6869if (membership.publicUserData.userId === userId) {70return null;71}7273const remove = async () => {74setDisabled(true);75await membership.destroy();76};7778const changeRole = async (role: MembershipRole) => {79setDisabled(true);80await membership.update({ role });81setDisabled(false);82};8384return (85<>86::{" "}87<button disabled={disabled} onClick={remove}>88Remove member89</button>{" "}90{membership.role === "admin" ? (91<button disabled={disabled} onClick={() => changeRole("basic_member")}>92Change to member93</button>94) : (95<button disabled={disabled} onClick={() => changeRole("admin")}>96Change to admin97</button>98)}99</>100);101};102103// List of organization pending invitations.104// You can invite new organization members and105// revoke already sent invitations.106function InvitationList() {107const { invitationList } = useOrganization();108109if (!invitationList) {110return null;111}112113const revoke = async (inv) => {114await inv.revoke();115};116117return (118<div>119<h2>Invite member</h2>120<InviteMember />121122<h2>Pending invitations</h2>123<ul>124{invitationList.map((i) => (125<li key={i.id}>126{i.emailAddress} <button onClick={() => revoke(i)}>Revoke</button>127</li>128))}129</ul>130</div>131);132}133134function InviteMember(){135const { organization } = useOrganization();136const [emailAddress, setEmailAddress] = useState("");137const [role, setRole] = useState<"basic_member" | "admin">("basic_member");138const [disabled, setDisabled] = useState(false);139140const onSubmit = async (e) => {141e.preventDefault();142setDisabled(true);143await organization.inviteMember({ emailAddress, role });144setEmailAddress("");145setRole("basic_member");146setDisabled(false);147};148149return (150<form onSubmit={onSubmit}>151<input152type="text"153placeholder="Email address"154value={emailAddress}155onChange={(e) => setEmailAddress(e.target.value)}156/>157<label>158<input159type="radio"160checked={role === "admin"}161onChange={() => {162setRole("admin");163}}164/>{" "}165Admin166</label>167<label>168<input169type="radio"170checked={role === "basic_member"}171onChange={() => {172setRole("basic_member");173}}174/>{" "}175Member176</label>{" "}177<button type="submit" disabled={disabled}>178Invite179</button>180</form>181);182};183
1import { useState, useEffect } from "react";2import { useOrganization } from "@clerk/clerk-react";3import type { OrganizationMembershipResource } from "@clerk/types";45// View and manage active organization members, along with any6// pending invitations.7// Invite new members.8export default function Organization() {9const {10organization: currentOrganization,11membership,12isLoaded,13} = useOrganization();1415if (!isLoaded || !currentOrganization) {16return null;17}1819const isAdmin = membership.role === "admin";20return (21<>22<h1>Organization: {currentOrganization.name}</h1>23<MemberList />24{isAdmin && <InvitationList />}25</>26);27}2829// List of organization memberships. Administrators can30// change member roles or remove members from the organization.31function MemberList() {32const { membershipList, membership } = useOrganization({33membershipList: {},34});3536if (!membershipList) {37return null;38}3940const isCurrentUserAdmin = membership.role === "admin";4142return (43<div>44<h2>Organization members</h2>45<ul>46{membershipList.map((m) => (47<li key={m.id}>48{m.publicUserData.firstName} {m.publicUserData.lastName} <49{m.publicUserData.identifier}> :: {m.role}50{isCurrentUserAdmin && <AdminControls membership={m} />}51</li>52))}53</ul>54</div>55);56}5758function AdminControls({59membership,60}: {61membership: OrganizationMembershipResource;62}){63const [disabled, setDisabled] = useState(false);64const {65user: { id: userId },66} = useUser();6768if (membership.publicUserData.userId === userId) {69return null;70}7172const remove = async () => {73setDisabled(true);74await membership.destroy();75};7677const changeRole = async (role: MembershipRole) => {78setDisabled(true);79await membership.update({ role });80setDisabled(false);81};8283return (84<>85::{" "}86<button disabled={disabled} onClick={remove}>87Remove member88</button>{" "}89{membership.role === "admin" ? (90<button disabled={disabled} onClick={() => changeRole("basic_member")}>91Change to member92</button>93) : (94<button disabled={disabled} onClick={() => changeRole("admin")}>95Change to admin96</button>97)}98</>99);100};101102// List of organization pending invitations.103// You can invite new organization members and104// revoke already sent invitations.105function InvitationList() {106const { invitationList } = useOrganization();107108if (!invitationList) {109return null;110}111112const revoke = async (inv) => {113await inv.revoke();114};115116return (117<div>118<h2>Invite member</h2>119<InviteMember />120121<h2>Pending invitations</h2>122<ul>123{invitationList.map((i) => (124<li key={i.id}>125{i.emailAddress} <button onClick={() => revoke(i)}>Revoke</button>126</li>127))}128</ul>129</div>130);131}132133function InviteMember(){134const { organization } = useOrganization();135const [emailAddress, setEmailAddress] = useState("");136const [role, setRole] = useState<"basic_member" | "admin">("basic_member");137const [disabled, setDisabled] = useState(false);138139const onSubmit = async (e) => {140e.preventDefault();141setDisabled(true);142await organization.inviteMember({ emailAddress, role });143setEmailAddress("");144setRole("basic_member");145setDisabled(false);146};147148return (149<form onSubmit={onSubmit}>150<input151type="text"152placeholder="Email address"153value={emailAddress}154onChange={(e) => setEmailAddress(e.target.value)}155/>156<label>157<input158type="radio"159checked={role === "admin"}160onChange={() => {161setRole("admin");162}}163/>{" "}164Admin165</label>166<label>167<input168type="radio"169checked={role === "basic_member"}170onChange={() => {171setRole("basic_member");172}}173/>{" "}174Member175</label>{" "}176<button type="submit" disabled={disabled}>177Invite178</button>179</form>180);181};182
1<ul id="memberships_list"></ul>2<ul id="invitations_list"></ul>34<form id="new_invitation">5<div>6<label>Email address</div>7<br />8<input type="email" name="email_address" />9</div>10<button>Invite</button>11</form>1213<script>14async function renderMemberships(organization, isAdmin) {15const list = document.getElementById("memberships_list");16try {17const memberships = await organization.getMembers();18memberships.map((membership) => {19const li = document.createElement("li");20li.textContent = `${membership.identifier} - ${membership.role}`;2122// Add administrative actions; update role and remove member.23if (isAdmin) {24const updateBtn = document.createElement("button");25updateBtn.textContent = "Change role";26updateBtn.addEventListener("click", async function(e) {27e.preventDefault();28const role = membership.role === "admin" ?29"basic_member" :30"admin";31await membership.update({ role });32});33li.appendChild(updateBtn);3435const removeBtn = document.createElement("button");36removeBtn.textContent = "Remove";37removeBtn.addEventListener("click", async function(e) {38e.preventDefault();39await currentOrganization.removeMember(membership.userId);40});41li.appendChild(removeBtn);42}4344// Add the entry to the list45list.appendChild(li);46});47} catch (err) {48console.error(err);49}50}5152async function renderInvitations(organization, isAdmin) {53const list = document.getElementById("invitations_list");54try {55const invitations = await organization.getPendingInvitations();56invitations.map((invitation) => {57const li = document.createElement("li");58li.textContent = `${invitation.emailAddress} - ${invitation.role}`;5960// Add administrative actions; revoke invitation61if (isAdmin) {62const revokeBtn = document.createElement("button");63revokeBtn.textContent = "Revoke";64revokeBtn.addEventListener("click", async function(e) {65e.preventDefault();66await invitation.revoke();67});68li.appendChild(revokeBtn);69}70// Add the entry to the list71list.appendChild(li);72});73} catch (err) {74console.error(err);75}76}7778async function init() {79// This is the current organization ID.80const organizationId = "org_XXXXXXX";81const organizationMemberships = await window.Clerk.getOrganizationMemberships()82const currentMembership = organizationMemberships.find(membership83=> membership.organization.id === organizationId);84const currentOrganization = currentMembership.organization;8586if (!currentOrganization) {87return;88}89const isAdmin = currentMembership.role === "admin";9091renderMemberships(currentOrganization, isAdmin);92renderInvitations(currentOrganization, isAdmin);9394if (isAdmin) {95const form = document.getElementById("new_invitation");96form.addEventListener("submit", async function(e) {97e.preventDefault();98const inputEl = form.getElementsByTagName("input");99if (!inputEl) {100return;101}102103try {104await currentOrganization.inviteMember({105emailAddress: inputEl.value,106role: "basic_member",107});108} catch (err) {109console.error(err);110}111});112}113}114115init();116</script>117