Capxul Docs
Reference

CapxulOrgMember

One root that owns what a member may do in an organization, plus the two parts a screen places in its own layout.

CapxulOrgMember answers one question: what may this member do in this organization? It draws nothing. You place its named parts where you want them and you draw everything yourself.

The two facts behind it are the two the backend actually enforces — managePeople and spend. Payroll is spending. Approving an invoice is spending. There are no other capabilities and no verb aliases.

Import

import { CapxulOrgMember } from "@capxul/sdk-react";

Usage

"use client";

import { CapxulOrgMember } from "@capxul/sdk-react";

function RecipientsHeader({ orgId }: { orgId: string | undefined }) {
  return (
    <CapxulOrgMember orgId={orgId}>
      <CapxulOrgMember.Can do="managePeople">
        {({ allowed, reason }) => (
          <button disabled={!allowed} title={reason === null ? undefined : DENIED[reason]}>
            Invite recipient
          </button>
        )}
      </CapxulOrgMember.Can>
    </CapxulOrgMember>
  );
}

Every screen places a subset. A payroll page places .Can do="spend" and nothing else. A dashboard places .Standing plus both facts. An invoice sheet places .Can twice with different do values.

Props

orgId accepts OrgId | string | undefined. When it is undefined the root starts no read at all and refuses immediately, so a screen rendered before an organization is selected never spins.

.Can

Takes what the person wants to do and hands back one finished slice.

{
  allowed: boolean;
  isLoading: boolean;
  reason: CanReason;
}

It fails closed: allowed is false until the read settles.

reason is a CODE from a closed list, never a sentence. Your application owns every refusal sentence and maps the code to it.

reasonWhen you get it
"loading"the read has not settled
"no-permission"the read settled and the member lacks the fact
"org-unavailable"no orgId was given, or the read failed
nullexactly when allowed is true

A member who is not part of the organization reads as "org-unavailable": the backend refuses the read rather than returning a member who holds nothing.

One part serves every denial idiom. Use allowed for a disabled control, add reason for a tooltip, branch on allowed to swap a whole surface, or return null to make a button vanish.

.Standing

{
  standing: "loading" | "unavailable" | "active" | "restricted";
  roleLabel: string | null;
}

Map standing to your own copy with a lookup. The classification runs in this order, and the order matters:

Test, in orderstanding
the read has not settled"loading"
the read failed, or no orgId was given"unavailable"
the member's role has no label"unavailable"
the member holds either capability"active"
the member holds neither"restricted"

Because the role test runs before the capability test, standing === "active" guarantees roleLabel is not null. Your active branch never needs a fallback word.

Rules

  • A part used outside <CapxulOrgMember> throws.
  • There is no companion hook. The component is the one way in, so no second surface can drift from it.
  • The read is shared: React Query serves one org(id).me() to every part on the page.

Client method

The component stands on client.org(orgId).me().

On this page