logo

Aki UI

アキ ウイ

Team Selector

チームセレクター

A stepper that shows what it is counting: the avatars are all laid out from the start and fade in as the number rises, so nothing reflows while you press. The count sits in an output↗↗ that announces itself politely, and the digits slide in the direction you stepped. At the ends the buttons are marked aria-disabled↗↗ rather than disabled — they stay focusable and reachable, and a press shakes the row instead of doing nothing silently, which is the difference between a refusal and a dead control. The whole thing is a fieldset so the legend names the group. Avatars are monograms drawn from the names; pass avatarUrl to use pictures. Adapted from Kokonut UI↗↗ under the MIT licence.

Team size
2
members

Installation

Install the following dependencies:1

npm install framer-motionnpm install lucide-react

Copy and paste the following code into a new component file:2

"use client"

/**
* Adapted for Aki UI from Kokonut UI's Team Selector.
* Original author: @dorianbaffier — https://kokonutui.com
* Copyright (c) 2025 kokonutUI, MIT License.
* https://github.com/kokonut-labs/kokonutui
*
* Reworked here onto the local palette, with motion/react swapped for
* framer-motion, the DiceBear avatar requests replaced by local monograms,

How to use it3

"use client"

import { TeamSelector } from "@/components/ui/team-selector"

export default function Page() {
return (
<TeamSelector
members={[
{ id: "alex", name: "Alex Rivera" },
{ id: "blair", name: "Blair Kim" },

Props

TeamSelector

NameDefaultDescription
members4 monograms

{ id: string, name: string, avatarUrl?: string }[]

The roster; its length is the maximum

defaultValue1

number

Count on mount, clamped to the roster

onChange—

(size: number) => void

Called with the new count on every step

label"Team size"

string

Legend of the fieldset

darkfalse

boolean

Render the dark palette