ComponentsPickers

User picker

Assign or mention people and teams: task assignee, approvers, deal owner, reviewers, shift staff, share-with. A Record picker for people — avatars with presence, role line, “Assign to me”, deactivated users, teams that expand to their members, and an avatar-stack trigger for table cells.

Record picker components/user-picker.tsx, components/record-picker.tsx, components/avatar.tsxtheme · material · accent · density · font

Deactivated people stay listed but can't be picked.

Installation

$ pnpm add @vamos-ui/react

The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";

Usage

import { Field, UserPicker } from "@vamos-ui/react";

<Field label="Assignee">
  <UserPicker source={people} currentUserId={me.id} value={assigneeId} onValueChange={setAssigneeId} />
</Field>

For @mentions in comments, reuse PickerUser and the row look; the mention menu itself belongs to the Comment thread.

Examples

Avatar stack in a table

trigger="avatars" shows the people as a stack plus “+”. The button is named “Assignees of T-482: Priya Raman, Tom Hollis”.

TaskDueAssignees
T-482Migrate pricing page to new CMS blocksNov 14
T-487Q4 renewal emails for Growth planNov 18
T-491Fix SLA timer on reopened ticketsNov 21

People and teams

teams adds a Teams group. With getTeamMembers a team expands to its active members; without it the team id (team:<id>) is selected.

Unknown record

Pick a team to add all of its members.

Assign to me

currentUserId pins an “Assign to me” row and marks you with “(you)”.

#48213Waiting on us

Invoice INV-2042 was charged twice

Inline list (shift staff)

trigger="inline" keeps the list open in a side panel. max limits the positions.

Saturday, 07:00 – 15:00

1 of 3 positions filled

No results

No results

API

UserPicker

PropTypeDefault
source
People. An array is searched in memory (name, email, role; locale-folded) and sorted by name with the locale collator.
PickerUser[] | RecordSource<PickerUser>—
multiple
Pick many (value becomes string[]).
booleanfalse
value / defaultValue / onValueChange
Controlled or uncontrolled id(s).
as Record picker—
max
Multi: most people.
number—
trigger
Field box, avatar-stack button or an always-open list.
"field" | "avatars" | "inline""field"
currentUserId
Adds “Assign to me” and the “(you)” suffix.
string—
teams
Teams in their own group ({ id, name, memberCount }).
PickerTeam[] | RecordSource<PickerTeam>—
getTeamMembers
Resolve a picked team to people (deactivated members are skipped).
(team, signal) => Promise<PickerUser[]>—
maxAvatars
Avatars before “+N” in the avatar trigger.
number3
roleLabel
Role in the avatar trigger's accessible name.
string"Assignees"
selectedRecords
People for the initial value with a server source.
PickerUser[]—
size
Trigger size.
"sm" | "md" | "lg""md"
placeholder
Trigger text when empty.
string"Unassigned" / "Assign"
name / disabled / readOnly / invalid / required
As Record picker; also read from Field.
…—
labels
Built-in strings (namespace userPicker).
Partial<UserPickerLabels>—

PickerUser

PropTypeDefault
id / name
Identity and display name (initials come from it, locale-aware).
string—
email
Searchable; shown when there is no meta.
string—
avatarUrl
Photo; falls back to initials.
string | null—
status
Presence dot.
"online" | "away" | "busy" | "offline"—
meta
Role or department line.
string—
disabled
Deactivated: dimmed and not selectable, still shown when already assigned.
boolean—