> ## Documentation Index
> Fetch the complete documentation index at: https://auth0-actions-modules-ga.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Manage an Organization Member on Web

> View and manage an individual organization member's profile and assigned roles in a two-tab layout with full lifecycle controls.

export const ReleaseStageNotice = ({feature, stage, plans, contact, terms}) => {
  const stageTextMap = {
    "beta": "Beta",
    "ea": "Early Access"
  };
  const stageText = stageTextMap[stage] || "a product release stage";
  const prsLink = "/docs/troubleshoot/product-lifecycle/product-release-stages";
  const linkify = (text, url) => {
    return <a href={url} target="_blank" rel="noreferrer" class="link">{text}</a>;
  };
  const includeDetails = (plans, contact, terms) => {
    const hasDetails = terms || plans || contact;
    if (!hasDetails) return null;
    return <span data-as="p">
            {plans && <>This feature is available for {linkify(`${plans} plans`, "https://auth0.com/pricing")}. </>}
            {contact && "To participate, contact " + contact + ". "}
            {terms && <>By using this feature, you agree to the applicable Free Trial terms in Okta's {linkify("Master Subscription Agreement", "https://www.okta.com/legal")}.</>}
        </span>;
  };
  return <Warning>
            <span data-as="p">
                <strong>The {feature} feature is in {linkify(stageText, prsLink)}.</strong>
            </span>

            {includeDetails(plans, contact, terms)}
        </Warning>;
};

export const ComponentLoader = props => {
  const detectTheme = () => {
    if (typeof document === "undefined") return "light";
    const html = document.documentElement;
    const colorScheme = html.style.colorScheme || window.getComputedStyle(html).colorScheme;
    if (colorScheme) return colorScheme === "dark" ? "dark" : "light";
    const isDarkMode = window?.localStorage?.getItem?.("isDarkMode");
    const prefersDark = window.matchMedia?.("(prefers-color-scheme: dark)").matches;
    const shouldBeDark = isDarkMode === "dark" || isDarkMode !== "light" && prefersDark;
    return shouldBeDark ? "dark" : "light";
  };
  const [theme, setTheme] = useState(detectTheme);
  useEffect(() => {
    if (typeof document === "undefined") return;
    setTheme(detectTheme());
    const observer = new MutationObserver(() => setTheme(detectTheme()));
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["style", "class", "data-theme", "data-theme-preference"]
    });
    return () => observer.disconnect();
  }, []);
  const lang = {
    i18n: {
      currentLanguage: props.lang || "en-US"
    }
  };
  return <div style={{
    minHeight: "400px",
    marginTop: "40px",
    background: theme === "light" ? "rgb(var(--gray-950)/.03)" : "rgb(255 255 255/.1)",
    alignItems: "center",
    justifyContent: "center",
    position: "relative",
    backgroundSize: "16px 16px",
    borderRadius: "10px",
    boxShadow: "0 1px 4px 0 rgba(16,30,54,0.04)",
    display: "flex",
    flexDirection: "column"
  }}>
      <div style={{
    minWidth: "320px",
    width: "96.5%",
    maxWidth: "1200px",
    margin: "12px 12px 0",
    background: theme === "light" ? "#ffffff" : "#101011",
    borderRadius: "10px",
    boxShadow: "0 2px 8px 0 rgba(16,30,54,0.04)",
    padding: "24px",
    minHeight: "400px"
  }} data-uc-component={props.componentSelector} data-uc-props={JSON.stringify(lang)}>
        <div aria-label="Loading" role="status" style={{
    position: "absolute",
    top: "50%",
    left: "50%",
    transform: "translate(-50%, -50%)",
    zIndex: 1,
    display: "flex",
    alignItems: "center",
    justifyContent: "center"
  }}>
          <svg width={40} height={40} viewBox="0 0 50 50" style={{
    display: "block"
  }}>
            <circle cx="25" cy="25" r="20" fill="none" stroke="#8A94A6" strokeWidth="5" strokeDasharray="90 150" strokeLinecap="round">
              <animateTransform attributeName="transform" type="rotate" from="0 25 25" to="360 25 25" dur="1s" repeatCount="indefinite" />
            </circle>
          </svg>
        </div>
      </div>
      <div style={{
    width: "100%",
    textAlign: "center",
    color: theme === "light" ? "#6B7280" : "#ffffff",
    fontSize: "12px",
    marginTop: "8px",
    marginBottom: "8px",
    letterSpacing: "0.01em",
    fontWeight: 400
  }}>
        {props.componentPreviewText}
      </div>
    </div>;
};

<ReleaseStageNotice feature="Auth0 Universal Components" stage="ea" terms="true" contact="Auth0 Support" />

The `OrganizationMemberDetail` component provides a unified interface to view and manage an individual [organization](/docs/manage-users/organizations) member's profile and assigned roles.

<ComponentLoader componentSelector="organization-member-detail" componentPreviewText="Preview of the Organization Member Detail component" />

<Tabs>
  <Tab title="React">
    ## Setup requirements

    <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
      **Auth0 Configuration Required**—Ensure your tenant is configured with the My Organization API. [View setup guide →](/docs/get-started/universal-components/web/components/build-delegated-admin#configure-auth0-dashboard)
    </Callout>

    ## Installation

    ```bash pnpm wrap lines theme={null}
    pnpm add @auth0/universal-components-react
    ```

    ## Get started

    Pass a `userId` from your route to the component. Wire `onBack` to your router so the back button returns to the member list.

    ```tsx wrap lines theme={null}
    import { OrganizationMemberDetail } from "@auth0/universal-components-react";
    import { useNavigate, useParams } from "react-router-dom";

    export function MemberDetailPage() {
      const { userId } = useParams<{ userId: string }>();
      const navigate = useNavigate();

      return (
        <OrganizationMemberDetail
          userId={userId!}
          onBack={() => navigate("/members")}
        />
      );
    }
    ```

    <Accordion title="Full integration example">
      ```tsx lines theme={null}
      import React from "react";
      import { OrganizationMemberDetail } from "@auth0/universal-components-react";
      import { Auth0Provider } from "@auth0/auth0-react";
      import { Auth0ComponentProvider } from "@auth0/universal-components-react/spa";
      import { useNavigate, useParams, useSearchParams } from "react-router-dom";
      import { auditLog } from "./lib/audit-log";

      function MemberDetailPage() {
        const { userId } = useParams<{ userId: string }>();
        const [searchParams] = useSearchParams();
        const navigate = useNavigate();
        const initialTab = searchParams.get("tab") === "roles" ? "roles" : "details";

        return (
          <div className="max-w-3xl mx-auto p-6">
            <OrganizationMemberDetail
              userId={userId!}
              initialTab={initialTab}
              onBack={() => navigate("/members")}
              removeFromOrganizationAction={{
                onBefore: (removedUserId) =>
                  window.confirm(`Remove member ${removedUserId} from the organization?`),
                onAfter: (removedUserId) => {
                  auditLog.record({ action: "member_removed", userId: removedUserId });
                },
              }}
              assignRolesAction={{
                onAfter: ({ userId, roleIds }) => {
                  auditLog.record({ action: "roles_assigned", userId, roleIds });
                },
              }}
              removeRolesAction={{
                onAfter: ({ userId, roleIds }) => {
                  auditLog.record({ action: "roles_removed", userId, roleIds });
                },
              }}
              customMessages={{
                member: {
                  detail: {
                    back_button: "Back to Members",
                    roles: { assign_button: "Assign Roles" },
                  },
                },
              }}
              styling={{
                variables: {
                  light: { "--color-primary": "#4f46e5" },
                  dark: { "--color-primary": "#818cf8" },
                },
                classes: {
                  "OrganizationMemberDetail-root": "max-w-3xl mx-auto",
                },
              }}
            />
          </div>
        );
      }

      export default function App() {
        const domain = "YOUR_TENANT.auth0.com";
        const clientId = "YOUR_CLIENT_ID";

        return (
          <Auth0Provider
            domain={domain}
            clientId={clientId}
            authorizationParams={{ redirect_uri: window.location.origin }}
          >
            <Auth0ComponentProvider>
              <MemberDetailPage />
            </Auth0ComponentProvider>
          </Auth0Provider>
        );
      }
      ```
    </Accordion>
  </Tab>

  <Tab title="Next.js">
    ## Setup requirements

    <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
      **Auth0 Configuration Required**—Ensure your tenant is configured with the My Organization API. [View setup guide →](/docs/get-started/universal-components/web/components/build-delegated-admin#configure-auth0-dashboard)
    </Callout>

    ## Installation

    ```bash pnpm wrap lines theme={null}
    pnpm add @auth0/universal-components-react
    ```

    ## Get started

    ```tsx wrap lines theme={null}
    // app/members/[userId]/page.tsx
    "use client";

    import { OrganizationMemberDetail } from "@auth0/universal-components-react";
    import { useRouter, useParams } from "next/navigation";

    export default function MemberDetailPage() {
      const { userId } = useParams<{ userId: string }>();
      const router = useRouter();

      return (
        <OrganizationMemberDetail
          userId={userId}
          onBack={() => router.push("/members")}
        />
      );
    }
    ```

    <Accordion title="Full integration example">
      ```tsx lines theme={null}
      // app/layout.tsx
      import { Auth0ComponentProvider } from "@auth0/universal-components-react/rwa";

      export default function RootLayout({ children }: { children: React.ReactNode }) {
        return (
          <html lang="en">
            <body>
              <Auth0ComponentProvider
                mode="proxy"
                domain="YOUR_TENANT.auth0.com"
                proxyConfig={{ baseUrl: "/api/auth" }}
              >
                {children}
              </Auth0ComponentProvider>
            </body>
          </html>
        );
      }
      ```

      ```tsx lines theme={null}
      // app/members/[userId]/page.tsx
      "use client";

      import React from "react";
      import { OrganizationMemberDetail } from "@auth0/universal-components-react";
      import { useRouter, useParams, useSearchParams } from "next/navigation";
      import { auditLog } from "@/lib/audit-log";

      export default function MemberDetailPage() {
        const { userId } = useParams<{ userId: string }>();
        const searchParams = useSearchParams();
        const router = useRouter();
        const initialTab = searchParams.get("tab") === "roles" ? "roles" : "details";

        return (
          <div className="max-w-3xl mx-auto p-6">
            <OrganizationMemberDetail
              userId={userId}
              initialTab={initialTab}
              onBack={() => router.push("/members")}
              removeFromOrganizationAction={{
                onBefore: (memberId) =>
                  window.confirm(`Remove member ${memberId} from the organization?`),
                onAfter: (memberId) => {
                  auditLog.record({ action: "member_removed", userId: memberId });
                  router.push("/members");
                },
              }}
              assignRolesAction={{
                onAfter: ({ userId, roleIds }) => {
                  auditLog.record({ action: "roles_assigned", userId, roleIds });
                },
              }}
              removeRolesAction={{
                onAfter: ({ userId, roleIds }) => {
                  auditLog.record({ action: "roles_removed", userId, roleIds });
                },
              }}
              customMessages={{
                member: {
                  detail: {
                    back_button: "Back to Members",
                    roles: { assign_button: "Assign Roles" },
                  },
                },
              }}
              styling={{
                variables: {
                  light: { "--color-primary": "#4f46e5" },
                  dark: { "--color-primary": "#818cf8" },
                },
              }}
            />
          </div>
        );
      }
      ```
    </Accordion>
  </Tab>

  <Tab title="shadcn">
    ## Setup requirements

    <Callout icon="file-lines" color="#0EA5E9" iconType="regular">
      **Auth0 Configuration Required**—Ensure your tenant is configured with the My Organization API. [View setup guide →](/docs/get-started/universal-components/web/components/build-delegated-admin#configure-auth0-dashboard)
    </Callout>

    ## Installation

    Install the component via the shadcn CLI using the GitHub Registry:

    ```bash wrap lines theme={null}
    npx shadcn@latest add auth0/auth0-ui-components/react/my-organization/organization-member-detail
    ```

    This installs the React component source code into `src/components/auth0/my-organization/` along with dependencies and `@auth0/universal-components-core`.

    ## Get started

    ```tsx wrap lines theme={null}
    import { OrganizationMemberDetail } from "@/components/auth0/my-organization/organization-member-detail";
    import { useNavigate, useParams } from "react-router-dom";

    export function MemberDetailPage() {
      const { userId } = useParams<{ userId: string }>();
      const navigate = useNavigate();

      return (
        <OrganizationMemberDetail
          userId={userId!}
          onBack={() => navigate("/members")}
        />
      );
    }
    ```

    <Accordion title="Full integration example">
      ```tsx lines theme={null}
      import React from "react";
      import { OrganizationMemberDetail } from "@/components/auth0/my-organization/organization-member-detail";
      import { Auth0Provider } from "@auth0/auth0-react";
      import { Auth0ComponentProvider } from "@auth0/universal-components-react/spa";
      import { useNavigate, useParams, useSearchParams } from "react-router-dom";
      import { auditLog } from "./lib/audit-log";

      function MemberDetailPage() {
        const { userId } = useParams<{ userId: string }>();
        const [searchParams] = useSearchParams();
        const navigate = useNavigate();
        const initialTab = searchParams.get("tab") === "roles" ? "roles" : "details";

        return (
          <div className="max-w-3xl mx-auto p-6">
            <OrganizationMemberDetail
              userId={userId!}
              initialTab={initialTab}
              onBack={() => navigate("/members")}
              removeFromOrganizationAction={{
                onBefore: (removedUserId) =>
                  window.confirm(`Remove member ${removedUserId} from the organization?`),
                onAfter: (removedUserId) => {
                  auditLog.record({ action: "member_removed", userId: removedUserId });
                  navigate("/members");
                },
              }}
              assignRolesAction={{
                onAfter: ({ userId, roleIds }) => {
                  auditLog.record({ action: "roles_assigned", userId, roleIds });
                },
              }}
              removeRolesAction={{
                onAfter: ({ userId, roleIds }) => {
                  auditLog.record({ action: "roles_removed", userId, roleIds });
                },
              }}
              customMessages={{
                member: {
                  detail: {
                    back_button: "Back to Members",
                    roles: { assign_button: "Assign Roles" },
                  },
                },
              }}
              styling={{
                variables: {
                  light: { "--color-primary": "#4f46e5" },
                  dark: { "--color-primary": "#818cf8" },
                },
              }}
            />
          </div>
        );
      }

      export default function App() {
        const domain = "YOUR_TENANT.auth0.com";
        const clientId = "YOUR_CLIENT_ID";

        return (
          <Auth0Provider
            domain={domain}
            clientId={clientId}
            authorizationParams={{ redirect_uri: window.location.origin }}
          >
            <Auth0ComponentProvider>
              <MemberDetailPage />
            </Auth0ComponentProvider>
          </Auth0Provider>
        );
      }
      ```
    </Accordion>
  </Tab>
</Tabs>

## Props

### Required props

| Prop     | Type     | Description                                                              |
| :------- | :------- | :----------------------------------------------------------------------- |
| `userId` | `string` | Auth0 user ID of the member to display (for example, `auth0\|64abc...`). |

***

### Display props

Display props control how the component renders without affecting its behavior. Use these to hide sections or enable read-only mode.

| Prop         | Type                   | Description                                                                                                                                                        |
| :----------- | :--------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `hideHeader` | `boolean`              | Hide the component header section (title and description). In the current Early Access release, this prop does not hide the Member Detail header. Default: `false` |
| `readOnly`   | `boolean`              | Disable role management and member-removal actions. Default: `false`                                                                                               |
| `initialTab` | `'details' \| 'roles'` | The tab to display initially. Deep link here using router query parameters. Default: `'details'`                                                                   |

***

### Action props

Action props handle user interactions. Use lifecycle hooks (`onBefore`, `onAfter`) to integrate with your application's routing and analytics.

| Prop                           | Type                      | Description                                        |
| :----------------------------- | :------------------------ | :------------------------------------------------- |
| `onBack`                       | `() => void`              | Back button click handler.                         |
| `removeFromOrganizationAction` | `ComponentAction<string>` | Remove member action.                              |
| `assignRolesAction`            | `ComponentAction`         | Assign roles. Hooks receive `{ userId, roleIds }`. |
| `removeRolesAction`            | `ComponentAction`         | Remove roles. Hooks receive `{ userId, roleIds }`. |

**onBack**

**Type:** `() => void`

Fires when selecting the header back button and automatically after member removal. Wire this callback to your router to return to the member list.

```tsx wrap lines theme={null}
<OrganizationMemberDetail userId={userId} onBack={() => navigate("/members")} />
```

**removeFromOrganizationAction**

**Type:** `ComponentAction<string>`

Controls member removal from the organization (membership only; does not delete the user profile from the Auth0 user store). After a successful membership removal, the component invokes the action callback and `onBack`. Do not rely on ordering if `onAfter` performs asynchronous work.

* `onBefore(userId)` confirms before removal. Return `false` to cancel.
* `onAfter(userId)` runs after removal.

```tsx wrap lines theme={null}
<OrganizationMemberDetail
  userId={userId}
  onBack={() => navigate("/members")}
  removeFromOrganizationAction={{
    onBefore: (memberId) =>
      window.confirm(`Remove member ${memberId} from the organization?`),
    onAfter: (memberId) => {
      auditLog.record({ action: "member_removed", userId: memberId });
    },
  }}
/>
```

**assignRolesAction**

**Type:** `ComponentAction<{ userId: string; roleIds: string[] }>`

Fires after assigning roles from the roles tab. Role selections are capped at 10 roles per assignment request, and an individual member can have up to 50 total roles assigned. Both hooks receive `{ userId, roleIds }`.

* `onBefore({ userId, roleIds })` validates selection. Return `false` to cancel.
* `onAfter({ userId, roleIds })` writes to an audit log or refreshes role badges.

```tsx wrap lines theme={null}
<OrganizationMemberDetail
  userId={userId}
  assignRolesAction={{
    onAfter: ({ userId, roleIds }) => {
      auditLog.record({ action: "roles_assigned", userId, roleIds });
    },
  }}
/>
```

**removeRolesAction**

**Type:** `ComponentAction<{ userId: string; roleIds: string[] }>`

Fires when removing assigned roles from the roles table (supports up to 10 roles per removal request). Both hooks receive `{ userId, roleIds }`.

* `onBefore({ userId, roleIds })` confirms before removing roles. Return `false` to cancel.
* `onAfter({ userId, roleIds })` refreshes state or audit logs.

```tsx wrap lines theme={null}
<OrganizationMemberDetail
  userId={userId}
  removeRolesAction={{
    onBefore: ({ roleIds }) =>
      window.confirm(`Remove ${roleIds.length} role(s)?`),
    onAfter: ({ userId, roleIds }) => {
      auditLog.record({ action: "roles_removed", userId, roleIds });
    },
  }}
/>
```

***

### Customization props

| Prop             | Type                                                | Description                        |
| :--------------- | :-------------------------------------------------- | :--------------------------------- |
| `customMessages` | `Partial<OrganizationMemberDetailMessages>`         | Copy and text overrides.           |
| `styling`        | `ComponentStyling<OrganizationMemberDetailClasses>` | CSS variables and class overrides. |

**customMessages**

Override bundled component text. Every field is optional and falls back to the built-in default.

<Accordion title="Common message groups">
  **member.detail**—Core views and tabs

  * `back_button`, `tabs.details`, `tabs.roles`

  **member.detail.user\_details**—Profile display

  * `title`, `name`, `email`, `phone_number`, `created_at`, `last_login`

  **member.detail.actions.remove\_from\_organization**—Removal action and dialog

  * `title`, `description`, `button`
  * `modal.title`, `modal.description`, `modal.cancel_button`, `modal.confirm_button`
  * `success`

  **member.detail.roles**—Roles tab and table

  * `title`, `description`, `assign_button`
  * `roles_selected`, `roles_selected_plural`, `max_selection_message`, `searching_message`
  * `table.name`, `table.description`, `table.empty_message`, `table.remove_button_label`

  **member.detail.roles.assign\_modal**—Role assignment modal

  * `title`, `description`
  * `roles_label`, `roles_placeholder`
  * `submit_button`, `cancel_button`, `no_roles_available`

  **member.detail.roles.remove\_confirm**—Role removal confirmation dialog

  * `title`, `title_plural`, `description`, `description_plural`
  * `confirm_button`, `cancel_button`

  **member.detail.error**—API errors

  * `fetch_failed`, `fetch_roles_failed`, `remove_from_organization_failed`, `assign_role_failed`, `remove_role_failed`
</Accordion>

```tsx wrap lines theme={null}
<OrganizationMemberDetail
  userId={userId}
  customMessages={{
    member: {
      detail: {
        back_button: "Back to Members",
        tabs: { details: "Profile", roles: "Permissions" },
        roles: {
          assign_button: "Add Permission",
          table: { empty_message: "No permissions assigned yet." },
        },
        actions: {
          remove_from_organization: {
            title: "Remove from Organization",
            button: "Remove",
            modal: {
              title: "Remove Member",
              confirm_button: "Yes, Remove",
            },
          },
        },
      },
    },
  }}
/>
```

***

**styling**

Customize appearance with CSS variables and class overrides. Variables support `light`, `dark`, and `common` scopes. Class overrides target named slots inside the component tree.

<Accordion title="Available styling options">
  **Variables**—CSS custom properties

  * `common`—Applied to all themes
  * `light`—Light theme only
  * `dark`—Dark theme only

  **Classes**—Targeted element class overrides

  * `OrganizationMemberDetail-root`
  * `OrganizationMemberDetail-header`
  * `OrganizationMemberDetail-tabs`
  * `OrganizationMemberDetail-detailsTab`
  * `OrganizationMemberDetail-rolesTab`
  * `MemberRemoveFromOrgModal-dialogContent`
  * `OrganizationMemberRemoveRoleModal-dialogContent`
  * `OrganizationMemberAssignRolesModal-dialogContent`
</Accordion>

```tsx wrap lines theme={null}
<OrganizationMemberDetail
  userId={userId}
  styling={{
    variables: {
      light: { "--color-primary": "#4f46e5" },
      dark: { "--color-primary": "#818cf8" },
    },
    classes: {
      "OrganizationMemberDetail-root": "max-w-3xl mx-auto",
      "OrganizationMemberDetail-header": "mb-6",
      "OrganizationMemberDetail-rolesTab": "mt-4",
    },
  }}
/>
```

***

## Advanced customization

### Available hooks

These hooks provide the underlying logic without any UI. Use them to build completely custom interfaces while leveraging the Auth0 API integration.

| Hook                          | Description                                                                               |
| :---------------------------- | :---------------------------------------------------------------------------------------- |
| `useOrganizationMemberDetail` | Member, role, modal, and interaction state for building a custom member detail interface. |
