# People Picker

> People Picker for Share Access.

A shadcn/ui block from the [@flx](https://ui.flexnative.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/flx/share-access-2).

- Page, with a live preview: https://shadcn.exchange/r/flx/share-access-2
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/flx/share-access-2-light-98dc4d92d51d05b7.png
- Registry item: https://ui.flexnative.com/r/share-access-2.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://ui.flexnative.com/r/share-access-2.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `lucide-react`
- Registry items: `avatar`, `button`, `card`, `input`, `select`, `separator`

## Files

### `registry/intents/collaboration/share-access/share-access-2.tsx`

```tsx
'use client'

import { useState } from 'react'
import { Plus } from 'lucide-react'

import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import { Separator } from '@/components/ui/separator'
import {
  Select,
  SelectContent,
  SelectGroup,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select'

type Person = {
  id: string
  name: string
  email: string
  avatar: string
  role: string
  owner?: boolean
}

const INITIAL: Person[] = [
  {
    id: 'ada',
    name: 'Ada Lovelace',
    email: 'ada@acme.com',
    avatar:
      'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=128&h=128&fit=crop&crop=faces',
    role: 'owner',
    owner: true,
  },
  {
    id: 'grace',
    name: 'Grace Hopper',
    email: 'grace@acme.com',
    avatar:
      'https://images.unsplash.com/photo-1438761681033-6461ffad8d80?w=128&h=128&fit=crop&crop=faces',
    role: 'editor',
  },
  {
    id: 'alan',
    name: 'Alan Turing',
    email: 'alan@acme.com',
    avatar:
      'https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=128&h=128&fit=crop&crop=faces',
    role: 'viewer',
  },
]

export function ShareAccess2() {
  const [people, setPeople] = useState<Person[]>(INITIAL)
  const [email, setEmail] = useState('')
  const [inviteRole, setInviteRole] = useState('viewer')

  const invite = () => {
    const value = email.trim()
    if (!value) return
    const name = value.split('@')[0].replace(/[._]/g, ' ')
    setPeople((prev) => [
      ...prev,
      {
        id: value,
        name: name.replace(/\b\w/g, (c) => c.toUpperCase()),
        email: value,
        avatar: '',
        role: inviteRole,
      },
    ])
    setEmail('')
  }

  const setRole = (id: string, role: string) =>
    role === 'remove'
      ? setPeople((prev) => prev.filter((p) => p.id !== id))
      : setPeople((prev) => prev.map((p) => (p.id === id ? { ...p, role } : p)))

  return (
    <Card>
      <CardHeader>
        <CardTitle>Share with people</CardTitle>
      </CardHeader>
      <CardContent className="flex flex-col gap-4">
        <div className="flex flex-wrap gap-2">
          <Input
            type="email"
            placeholder="Add by email"
            className="min-w-[12rem] flex-1"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
            onKeyDown={(e) => e.key === 'Enter' && invite()}
          />
          <div className="flex gap-2">
            <Select
              value={inviteRole}
              onValueChange={(value) => setInviteRole(value ?? '')}
            >
              <SelectTrigger className="w-28">
                <SelectValue />
              </SelectTrigger>
              <SelectContent>
                <SelectGroup>
                  <SelectItem value="viewer">Viewer</SelectItem>
                  <SelectItem value="editor">Editor</SelectItem>
                </SelectGroup>
              </SelectContent>
            </Select>
            <Button size="icon" onClick={invite} aria-label="Invite">
              <Plus className="size-4" />
            </Button>
          </div>
        </div>

        <Separator />

        <div className="flex flex-col gap-3">
          {people.map((person) => (
            <div key={person.id} className="flex items-center gap-3">
              <Avatar className="size-8">
                <AvatarImage src={person.avatar} alt={person.name} />
                <AvatarFallback className="bg-muted text-xs">
                  {person.name
                    .split(' ')
                    .map((n) => n[0])
                    .join('')
                    .slice(0, 2)
                    .toUpperCase()}
                </AvatarFallback>
              </Avatar>
              <div className="flex min-w-0 flex-1 flex-col">
                <span className="truncate text-sm font-medium">
                  {person.name}
                </span>
                <span className="text-muted-foreground truncate text-xs">
                  {person.email}
                </span>
              </div>
              {person.owner ? (
                <span className="text-muted-foreground text-xs">Owner</span>
              ) : (
                <Select
                  value={person.role}
                  onValueChange={(v) => setRole(person.id, v ?? '')}
                >
                  <SelectTrigger size="sm" className="w-28 shrink-0">
                    <SelectValue />
                  </SelectTrigger>
                  <SelectContent>
                    <SelectGroup>
                      <SelectItem value="viewer">Viewer</SelectItem>
                      <SelectItem value="editor">Editor</SelectItem>
                      <SelectItem value="remove" className="text-destructive">
                        Remove
                      </SelectItem>
                    </SelectGroup>
                  </SelectContent>
                </Select>
              )}
            </div>
          ))}
        </div>
      </CardContent>
    </Card>
  )
}
```
