Duck Primitives
Headless, accessibility-first React primitives. Shared Slot, Presence, Popper, and focus-scope load once, so Alert Dialog ships at 1.6 KB and Popover at 2.4 KB.
Unstyled primitives, shared internals
A headless, accessibility-first component library. Slot, Presence, Popper, and focus-scope are shared across every primitive, so each one stays small.
Shared internals
Alert Dialog: 1.6 KB. Popover: 2.4 KB. Shared Slot, Presence, Popper, and focus-scope load once across every primitive.
A11y built in
Every primitive ships with the right roles, states, and keyboard interactions. Compose them and ARIA is already wired.
Compound components
Compose `Root`, `Trigger`, `Content`, and `Portal` with scoped context. Each part owns its concern, no prop drilling.
Keyboard everything
Roving focus, type-ahead search, arrow-key navigation, and focus trapping. Same semantics across menus, dialogs, and selects.
Familiar API
Compound parts, `asChild`, `data-state` attributes. If you have used a headless primitive library before, the vocabulary is the same.
40+ primitives
Dialog, Popover, Select, Menu, Command, Calendar, Input OTP, Navigation Menu. All headless and unstyled.
Install
Import each primitive from its own subpath.
# Install
bun add @gentleduck/primitives
# Import any primitive
import { Root, Trigger, Portal, Content } from '@gentleduck/primitives/dialog'Free & open source
gentleduck is MIT licensed and will always be free and open source. Every package ships with full source access — fork it, modify it, own it.