Skip to content
txbrendan/ui

Club Switcher

beta

The club you're in, with its kit flag, name, and your roles, that opens a menu of every club you belong to.

Preview

button

no kit

inline

Install

  1. 1. Add the registry to components.json, once per app. Without it, the shadcn CLI looks up @txbrendan in a public list that txbrendan/ui does not control.

    npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"
  2. 2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.

    npx shadcn@latest add @txbrendan/theme
  3. 3. Add the component.

    npx shadcn@latest add @txbrendan/club-switcher

Use it for

  • The top of an app's rail, for people in more than one club: a coach in one, a parent in another.
  • Give each club an id, its name, its kit colors for the TeamFlag, and your roles there, like "Coach · Admin".
  • Pressing it opens every club under it, with a check on the current one. Pass onJoin to end the menu with Join another club.
  • Pass value and onChange to control it, or defaultValue to start in a club. Without either it starts in the first.
  • Use inline to draw the open menu in a card or a doc, with no button.

Avoid it for

  • Drawing a club's crest. Its kit colors stand in for it. Brand logos are never drawn.
  • Someone in one club only. Show the club's name and flag as plain text.
  • Switching teams inside one club. Use a select or tabs.

Props

  • clubs

    Required. Every club you belong to. colors are CSS colors from your data, set only on the flag's own style.

    { id: string; name: string; colors?: [string, string]; pattern?: "hoops" | "halves" | "thirds" | "split"; role?: string }[]

  • value

    The club you're in. Controlled, with onChange.

    string

  • defaultValue

    The club you start in. Default the first.

    string

  • onChange

    Runs with the club's id when you switch.

    (id: string) => void

  • onJoin

    Offers "Join another club" at the end of the menu.

    () => void

  • inline

    Draws the open menu in the page's flow, with no button. Nothing closes it.

    boolean · default false

  • className

    Extra classes on the button, or on the menu with inline. Later classes win.

    string

Accessibility

  • The button is named by the club and your roles, and says it opens a menu.
  • The menu opens with focus on your club. The arrow keys move without wrapping, Home and End go to the ends, letters jump to a club, Enter switches, and Esc closes it and puts focus back.
  • Each club is a menuitemradio, checked for the one you're in. The check is drawn, not only colored.
  • Inline, the menu is one Tab stop that lands on your club, with the same keys. Nothing closes it.
  • The kit flag is hidden from screen readers, since the name beside it says the club.

Examples

At the top of a rail

<ClubSwitcher
  clubs={[
    { id: "rovers", name: "Rovers", colors: ["#1e3a8a", "#ffffff"], pattern: "hoops", role: "Coach · Admin" },
    { id: "saints", name: "Saints", colors: ["#b91c1c", "#111827"], role: "Parent of Ava" },
  ]}
  defaultValue="rovers"
  onChange={(id) => console.log("switch to", id)}
  onJoin={() => console.log("join")}
/>