diff --git a/packages/clerk-js/sandbox/scenarios/index.ts b/packages/clerk-js/sandbox/scenarios/index.ts
index f906e8b43ad..b232d324123 100644
--- a/packages/clerk-js/sandbox/scenarios/index.ts
+++ b/packages/clerk-js/sandbox/scenarios/index.ts
@@ -1,3 +1,4 @@
export { UserButtonSignedIn } from './user-button-signed-in';
export { CheckoutAccountCredit } from './checkout-account-credit';
+export { OrgProfileSeatLimit } from './org-profile-seat-limit';
export { PricingTableSBB } from './pricing-table-sbb';
diff --git a/packages/clerk-js/sandbox/scenarios/org-profile-seat-limit.ts b/packages/clerk-js/sandbox/scenarios/org-profile-seat-limit.ts
new file mode 100644
index 00000000000..355fcb19db5
--- /dev/null
+++ b/packages/clerk-js/sandbox/scenarios/org-profile-seat-limit.ts
@@ -0,0 +1,74 @@
+import {
+ BillingService,
+ clerkHandlers,
+ EnvironmentService,
+ SessionService,
+ setClerkState,
+ type MockScenario,
+ UserService,
+ OrganizationService,
+} from '@clerk/msw';
+
+export function OrgProfileSeatLimit(): MockScenario {
+ const organization = OrganizationService.create({ maxAllowedMemberships: 10 });
+ const user = UserService.create();
+ user.organizationMemberships = [
+ {
+ object: 'organization_membership',
+ id: 'orgmem_3004mVaZrB4yD63C9KuwTMWNKbj',
+ public_metadata: {},
+ role: 'org:owner',
+ role_name: 'Owner',
+ permissions: [
+ 'org:applications:create',
+ 'org:applications:manage',
+ 'org:applications:delete',
+ 'org:billing:read',
+ 'org:billing:manage',
+ 'org:config:read',
+ 'org:config:manage',
+ 'org:global:read',
+ 'org:global:manage',
+ 'org:instances:create',
+ 'org:instances:manage',
+ 'org:instances:delete',
+ 'org:restrictions:read',
+ 'org:restrictions:manage',
+ 'org:secrets:manage',
+ 'org:users:imp',
+ 'org:sys_profile:manage',
+ 'org:sys_profile:delete',
+ 'org:sys_billing:read',
+ 'org:sys_billing:manage',
+ 'org:sys_domains:read',
+ 'org:sys_domains:manage',
+ 'org:sys_memberships:read',
+ 'org:sys_memberships:manage',
+ ],
+ created_at: 1752751315275,
+ updated_at: 1752751315275,
+ organization,
+ },
+ ];
+ const session = SessionService.create(user);
+ const plans = BillingService.createDefaultPlans();
+ const subscription = BillingService.createSubscription(plans[1]);
+
+ setClerkState({
+ environment: EnvironmentService.MULTI_SESSION,
+ session,
+ user,
+ organization,
+ billing: {
+ plans,
+ subscription,
+ },
+ });
+
+ return {
+ description: 'OrganizationProfile with a seat limit',
+ handlers: clerkHandlers,
+ initialState: { session, user, organization },
+ name: 'org-profile-seat-limit',
+ };
+}
diff --git a/packages/localizations/src/en-US.ts b/packages/localizations/src/en-US.ts
index 0d81f8920a9..324507302fc 100644
--- a/packages/localizations/src/en-US.ts
+++ b/packages/localizations/src/en-US.ts
@@ -474,6 +474,7 @@ export const enUS: LocalizationResource = {
start: {
headerTitle__general: 'General',
headerTitle__members: 'Members',
+ membershipSeatUsageLabel: '{{count}} of {{limit}} seats used',
profileSection: {
primaryButton: 'Update profile',
title: 'Organization Profile',
diff --git a/packages/msw/request-handlers.ts b/packages/msw/request-handlers.ts
index 3351ab3bf00..6958a8eea3e 100644
--- a/packages/msw/request-handlers.ts
+++ b/packages/msw/request-handlers.ts
@@ -1114,8 +1114,10 @@ export const clerkHandlers = [
const membership = (currentUser as any).organizationMemberships.find((m: any) => m.organization?.id === orgId);
if (membership) {
return createNoStoreResponse({
- data: [SessionService.serialize(membership)],
- total_count: 1,
+ response: {
+ data: [SessionService.serialize(membership)],
+ total_count: 1,
+ },
});
}
}
diff --git a/packages/shared/src/types/localization.ts b/packages/shared/src/types/localization.ts
index 0f3659e52fd..a4f47119d33 100644
--- a/packages/shared/src/types/localization.ts
+++ b/packages/shared/src/types/localization.ts
@@ -1022,6 +1022,7 @@ export type __internal_LocalizationResource = {
badge__manualInvitation: LocalizationValue;
start: {
headerTitle__members: LocalizationValue;
+ membershipSeatUsageLabel: LocalizationValue<'count' | 'limit'>;
headerTitle__general: LocalizationValue;
profileSection: {
title: LocalizationValue;
diff --git a/packages/ui/src/components/OrganizationProfile/OrganizationMembers.tsx b/packages/ui/src/components/OrganizationProfile/OrganizationMembers.tsx
index 2b05de8fad8..f82a72ed392 100644
--- a/packages/ui/src/components/OrganizationProfile/OrganizationMembers.tsx
+++ b/packages/ui/src/components/OrganizationProfile/OrganizationMembers.tsx
@@ -2,6 +2,7 @@ import { useOrganization } from '@clerk/shared/react';
import { useState } from 'react';
import { useFetchRoles } from '@/hooks/useFetchRoles';
+import { Users } from '@/icons';
import { Alert } from '@/ui/elements/Alert';
import { Animated } from '@/ui/elements/Animated';
import { Card } from '@/ui/elements/Card';
@@ -11,7 +12,7 @@ import { Tab, TabPanel, TabPanels, Tabs, TabsList } from '@/ui/elements/Tabs';
import { NotificationCountBadge, useProtect } from '../../common';
import { useEnvironment } from '../../contexts';
-import { Col, descriptors, Flex, localizationKeys } from '../../customizables';
+import { Box, Col, descriptors, Flex, Icon, localizationKeys, Text } from '../../customizables';
import { Action } from '../../elements/Action';
import { mqu } from '../../styledSystem';
import { ActiveMembersList } from './ActiveMembersList';
@@ -33,7 +34,7 @@ export const OrganizationMembers = withCardStateProvider(() => {
const [query, setQuery] = useState('');
const [search, setSearch] = useState('');
- const { membershipRequests, memberships, invitations } = useOrganization({
+ const { membershipRequests, memberships, invitations, organization } = useOrganization({
membershipRequests: isDomainsEnabled || undefined,
invitations: canManageMemberships || undefined,
memberships: canReadMemberships
@@ -57,6 +58,7 @@ export const OrganizationMembers = withCardStateProvider(() => {
elementDescriptor={descriptors.profilePage}
elementId={descriptors.profilePage.setId('organizationMembers')}
gap={4}
+ sx={theme => ({ paddingBottom: theme.space.$13 })}
>
@@ -173,6 +175,46 @@ export const OrganizationMembers = withCardStateProvider(() => {
+
+ {canReadMemberships && !!memberships?.count && organization && organization.maxAllowedMemberships > 0 ? (
+ ({
+ position: 'absolute',
+ bottom: 0,
+ left: 0,
+ right: 0,
+ backgroundColor: theme.colors.$colorBackground,
+ borderTop: `1px solid ${theme.colors.$borderAlpha100}`,
+ paddingInline: theme.space.$4,
+ height: theme.space.$13,
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ })}
+ >
+ ({
+ display: 'inline-flex',
+ alignItems: 'center',
+ gap: t.space.$2,
+ })}
+ >
+
+
+
+
+ ) : null}
);
});