# Staff picker screen

> Step two of a booking flow: an Any available card and a card per professional with photo, rating and next free time. One accent ring springs from card to card, its edges on different springs so it stretches toward the pick.

- Type: Component (screens)
- Access: Pro
- Page: https://goodui.dev/native/components/staff-picker-screen
- Markdown: https://goodui.dev/native/components/staff-picker-screen.md
- Registry item: https://goodui.dev/native/r/staff-picker-screen.json
- Dependencies: react-native-reanimated
- Keywords: react native staff picker, choose stylist screen, select professional booking, any available staff, barber picker, therapist selection, expo booking flow

## When to use

- Letting people choose who they book with: a stylist, barber, therapist, trainer, tutor or doctor.
- Offering a no-preference option that books the first free person.
- Showing who cannot take the picked services without hiding them.

## When not to use

- A long searchable directory of people: use a list with search-bar.
- Picking several people at once: use checkbox rows.
- Choosing what to book: use service-picker-screen.

## Installation

With the shadcn CLI (needs a components.json in the Expo app), then `npx expo install --fix` so native dependencies match your Expo SDK. The foundation comes along the first time.

```bash
npx shadcn@latest add @goodui-native-pro/staff-picker-screen
npx expo install --fix
```

Pro: add `"@goodui-native-pro": { "url": "https://goodui.dev/native/r/pro/{name}.json", "headers": { "Authorization": "Bearer ${GOODUI_LICENSE_KEY}" } }` to the `registries` of components.json and put your license key in .env.local.

The component lands in `components/goodui-native/staff-picker-screen/` and imports the foundation from `components/goodui-native/foundation/` with relative paths; it also installs avatar, button, rating, service-picker-screen.

## Usage

```tsx
import { router, Stack, useLocalSearchParams } from "expo-router";
import { useState } from "react";
import { StaffPickerScreen } from "@/components/goodui-native/staff-picker-screen/staff-picker-screen";
import type { BookingService, BookingStaff } from "@/components/goodui-native/service-picker-screen/booking-types";
import { useMenu } from "@/lib/booking"; // your data

export default function StaffRoute() {
  const params = useLocalSearchParams<{ services: string }>();
  const { services, staff } = useMenu() as { services: BookingService[]; staff: BookingStaff[] };
  const picked = services.filter((s) => params.services?.split(",").includes(s.id));
  const [staffId, setStaffId] = useState<string | null>(null);
  return (
    <>
      <Stack.Screen options={{ headerShown: false }} />
      <StaffPickerScreen
        staff={staff}
        services={picked}
        value={staffId}
        onValueChange={setStaffId}
        onBack={() => router.back()}
        onContinue={(id) => router.push({ pathname: "/book/time", params: { ...params, staff: id ?? "any" } })}
      />
    </>
  );
}
```

## Examples

### Sample salon, no props

```tsx
<StaffPickerScreen />
```

### Named professional required

```tsx
<StaffPickerScreen staff={doctors} services={[consultation]} allowAny={false} title="Choose your doctor" />
```

## API reference

### StaffPickerScreen

`import { StaffPickerScreen } from "@/components/goodui-native/staff-picker-screen/staff-picker-screen";`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `staff` | `BookingStaff[]` | `sampleStaff` | Everyone who can be booked. People who do not perform every picked service show dimmed at the end. |
| `services` | `BookingService[]` | `[sampleServices[0]]` | The services picked on the previous step. They filter the staff and fill the summary line. |
| `value` | `string \| null` | – | Picked staff id (controlled). `null` is "Any available". Pair it with `onValueChange`. |
| `defaultValue` | `string \| null` | `null` | Starting pick when uncontrolled. Default `null` ("Any available"). |
| `onValueChange` | `(staffId: string \| null) => void` | – | Called with the picked staff id, or `null` for "Any available". |
| `onContinue` | `(staffId: string \| null) => unknown` | – | Continue button, with the picked id (`null` = anyone). Return a promise to show pending, success and error. |
| `onBack` | `() => void` | – | Shows a back button in the top bar. |
| `allowAny` | `boolean` | `true` | Hide the "Any available" card when every booking needs a named person. Default `true` (shown). |
| `step` | `BookingStep \| null` | `{ current: 2, total: 4 }` | Step of the booking flow in the top bar. `null` hides it. Default step 2 of 4. |
| `title` | `string` | `"Choose a professional"` | Headline. Default "Choose a professional". |
| `locale` | `string` | – | BCP 47 locale for days and times. Defaults to the device locale. |
| `hour12` | `boolean` | – | Force a 12 or 24 hour clock. Defaults to the locale's. |
| `style` | `StyleProp<ViewStyle>` | – | Style for the outer container. |
| `testID` | `string` | – | Identifier for end-to-end tests. |

## Accessibility

- The cards form a radiogroup; each card is a radio with checked and disabled state (aria-checked and aria-disabled on the web).
- On native a card reads as one sentence: name, role, rating with review count, next free time. The web names it from its visible text; avatars are hidden from screen readers.
- A new pick is announced ("Maya Patel selected").
- People who do not perform the picked services stay listed under a header, dimmed and disabled, with the reason in text.

## Motion

- One accent ring travels between cards. The edge in the direction of travel moves on the snappy spring and the other on the smooth spring, so the ring stretches toward the new card and settles.
- Cards sink to 0.98 on touch down; the check in the picked card draws itself in.
- Reduced motion: the ring jumps to the new card and fades in, cards do not scale, the check shows complete.

## Haptics

- select when the pick changes
- tap on Continue (Button)

## Performance

- The ring's position and height are shared values driven on the UI thread; card positions are measured once and only re-read when a card's size really changes (react-native-web reports layout on every render).

## Notes for AI

- Pass the services picked on the previous step; staff are filtered by each service's staffIds and the rest are shown disabled.
- value and onContinue use null for Any available. Map it to your API's 'any' option.
- nextFree on each BookingStaff is a Date; the screen formats it as Today, Tomorrow or a short date plus time.
- Avatars come in through BookingStaff.avatar (URL or image source); initials show without one.
- Hide the navigator header (headerShown: false); the screen draws its own top bar.

## Related

- [Service picker screen](https://goodui.dev/native/components/service-picker-screen.md): Step one of a booking flow: the menu in sticky category sections with duration and price, add-ons that spring up as chips once a matching service is picked, and a total that rolls with every change above the Continue button. Also ships the booking data model shared by every booking screen.
- [Booking time screen](https://goodui.dev/native/components/booking-time-screen.md): Step three of a booking flow: a week strip, the day's times grouped by morning, afternoon and evening for the chosen professional, a time zone note, and a summary that springs up from the bottom with the time rolling in on every pick.
- [Avatar](https://goodui.dev/native/components/avatar.md): A photo that fades in over initials on a color picked from the name, with a presence dot and a story ring whose accent arc sweeps in when there is something new and away once seen; AvatarGroup stacks people with a +N counter and fans out on tap.
- [Rating](https://goodui.dev/native/components/rating.md): Stars (or any symbol) you tap or drag across: the fill sweeps from the old rating to the new one and every symbol it crosses pops on its own beat; half steps optional, and a read-only variant shows exact fractions with a value and a count.
- [Segmented control](https://goodui.dev/native/components/segmented-control.md): Two to five views of the same thing with an elastic highlight that stretches toward the new segment, can be dragged, and ticks at every boundary. Includes a billing toggle.

## Guidance for AI tools

Staff picker screen: Step two of a booking flow: an Any available card and a card per professional with photo, rating and next free time. One accent ring springs from card to card, its edges on different springs so it stretches toward the pick. Use only the documented props. Keep accessibility, reduced motion and both color schemes intact when adapting it.

Full library index: https://goodui.dev/native/llms.txt
