Staaarter

Billing Family Plan Members

A member list for consumer or small-team plans where several people share one billing account. Each row shows an avatar, name, role, and status, the header tracks how many seats are left out of the plan's cap, and members other than the owner get a remove action. Built for account settings screens where the primary account holder manages who's on the plan.

By Staaarter Team
Billing
Updated July 2, 2026
Docs
Live preview

Docs

Installation

A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its avatar, badge, button dependencies and any missing npm packages, and installs them straight into your project.

npx shadcn add https://staaarter.com/r/billing-family-plan-members.json

Prefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/billing/billing57.tsx instead.

Usage

The file also exports billing57Demo, the exact props behind the preview above. Spread it to get a working section in one line, then replace it with your own data.

import { Billing57, billing57Demo } from "@/components/blocks/billing/billing57";

export default function Page() {
  return <Billing57 {...billing57Demo} />;
}

Props

PropTypeDefaultDescription
headingstring"Family plan members"Heading in the header.
descriptionstringnoneOptional supporting line under the heading.
membersFamilyMember[]noneRows rendered in the order given.
maxSeatsnumbernoneTotal seats on the plan, used to compute the seats-remaining badge and whether Invite is shown.
inviteLabelstring"Invite member"Label on the invite button.
inviteHrefstring"#"Link target for the invite button.
classNamestringnoneExtra classes for the outer container.

Types

interface FamilyMember {
  id: string;
  name: string;
  email: string;
  avatarUrl?: string;
  role: "owner" | "member";
  status: "active" | "invited";
  joinedLabel?: string;
}

Behavior notes

  • Seats remaining is maxSeats minus members.length, computed on every render, there's no separate seatsRemaining prop to keep in sync.
  • When seats are full, the Invite button is replaced with a plain sentence saying so, instead of a disabled button.
  • The owner's row never gets a remove action; every other member does, rendered as a next/link styled as an icon button, not a real delete.
  • Members without an avatarUrl fall back to initials generated from their name via the shared initialsFromName helper.
  • The invited badge and the remove action are purely presentational here, wire the remove link and the invite flow to your own backend and confirmation dialog for a real integration.

Frequently asked questions