TeamSwitcher

The workspace picker at the top of an app sidebar — current team's avatar and name in the trigger, the rest in a dropdown under it. Three weights via `variant`, a `collapsed` state that drops to just the avatar, and room for a "Create team" action below the list. `UserMenu` is its opposite number at the sidebar's foot.

vue
<UiTeamSwitcher :teams="..." />

Options

One block per prop — what it does, and what it looks like set.

Teams

required

teams is the list to choose between. Each one needs a label; an avatar is drawn from the team's initials when you don't supply one, so a bare list of names already renders something sensible. The first team is what shows until a selection is made.

Model value

modelValue is the selected team's value, falling back to its label where there isn't one. Bind it with v-model when something else needs to know which team is current — leave it off entirely and the switcher tracks the selection itself, which is what every other example here does.

Selected: Vue

Variant

variant is how much the trigger asserts itself. subtle gives it a surface and a ring, so it reads as a control in its own right — right for a sidebar header, where it's the first thing on the page. soft keeps the fill and drops the ring; ghost shows nothing until you hover it, which suits a switcher sitting among other quiet chrome.

subtle

soft

ghost

State

state mirrors a parent Sidebar's slot prop of the same name. collapsed drops the name and the caret and centers the avatar, which is all that fits at icon width — hand it straight through from the sidebar's header slot and the switcher shrinks with everything else.

Items

items are extra menu groups under the list of teams, each behind its own divider — the actions that belong to the switcher rather than to any one team. They're plain DropdownMenu items, so icons, colors, shortcuts and nested children all work as they do there.


Examples

The component in real use: compositions that answer "how do I build X with this", rather than one prop at a time.

Descriptions and shortcut hints — a second line per team, and `kbds` on their rows

description shows under the name in the trigger; kbds renders a shortcut hint on that team's menu row. The hint is display only — nothing here binds ⌘1, that part is yours.

In a `Sidebar` header — the composition it was pulled out of

state comes straight from the sidebar's header slot, so the switcher collapses along with everything else. Both ends run ghost here — the sidebar card is already a surface, and a second one inside it just adds edges. UserMenu is the same trigger doing the same job at the other end.


API Reference

Generated from the component's source — props, slots and emits as the component actually declares them.

Props

Prop
Type
Default
Description
teamsrequired
Team[]
—
The teams to choose between. The first is what's shown until something is selected.
string
—
The selected team's `value` (or its `label`, when it has no `value`). Bind it with `v-model`, or leave it off and the switcher tracks the selection itself.
"subtle" | "soft" | "ghost"
'subtle'
The trigger's visual weight. `subtle` gives it a surface and a ring of its own, `soft` a fill without the ring, and `ghost` nothing at all until it's hovered.
"expanded" | "collapsed"
'expanded'
Matches a parent `Sidebar`'s `state` slot prop — `collapsed` drops the name and caret and centers the avatar, which is all that fits at icon width.
DropdownMenuItem[][]
—
Extra menu groups shown under the list of teams, each rendered below a divider — where a "Create team" or "Team settings" action belongs.

Slots

Slot
default
Receives `{ team, open, state }`.

Emits

Event
Payload
Description
update:modelValue
[value: string]
—
select
[team: Team]
Fired with the whole team, for when the value alone isn't enough to act on.

Types

ts
type Variant = "subtle" | "soft" | "ghost";
ts
interface Team {
    /**
     * What `v-model` identifies this team by. Falls back to `label`, which is enough whenever the
     * names are unique.
     */
    value?: string;

    /** The team's name, shown in the trigger and on its menu row. */
    label: string;

    /**
     * The avatar shown beside the name, in the trigger and the menu alike. Omit it and the team's
     * initials are drawn from `label`.
     */
    avatar?: {
        src?: string;
        alt?: string;
        firstName?: string;
        lastName?: string;
        shape?: "circle" | "square";
    };

    /** A quieter second line under the name in the trigger — a plan, a role, an environment. */
    description?: string;

    /** Shortcut hint rendered on this team's menu row. Display only; binding the key is yours. */
    kbds?: Array<string | { value?: string }>;

    /** Greys the row out and stops it being selected. */
    disabled?: boolean;
}
ts
interface DropdownMenuItem {
    label?: string;

    /**
     * The row's icon: an icon name, or `{ name, color, fill }` to also tint just the icon
     * (independent of `color`, which tints the whole row) or render its filled variant.
     */
    icon?: string | MenuItemIcon;
    status?: "online" | "offline" | "away" | "dnd" | "busy";
    avatar?: {
        src?: string;
        alt?: string;
        firstName?: string;
        lastName?: string;
        status?: "online" | "offline" | "away" | "dnd" | "busy";
        shape?: "circle" | "square";
    };
    badge?: {
        text?: number | string;
        color?: "primary" | "secondary" | "success" | "warning" | "error" | "info" | "pending" | "neutral";
    };
    kbds?: Array<string | { value?: string }>;
    type?: "link" | "label" | "separator" | "checkbox";
    color?: "error" | "primary" | "secondary" | "success" | "info" | "warning" | "pending" | "neutral";
    checked?: boolean;
    disabled?: boolean;
    onSelect?: (e: Event) => void;
    onUpdateChecked?: (checked: boolean) => void;
    children?: DropdownMenuItem[] | DropdownMenuItem[][];
    class?: any;
    to?: string;
    target?: string;
}