Pokedex
Controllable primitives to build Pokédex UIs: search, domain filters, incremental pagination, and renderItem-based collections.
Bulbasaur (Japanese: フシギダネ Fushigidane) is a dual-type Grass/Poison Pokémon introduced in Generation I.
Charmander (Japanese: ヒトカゲ Hitokage) is a Fire-type Pokémon introduced in Generation I.
Squirtle (Japanese: カメール Kamēru) is a Water-type Pokémon introduced in Generation I.
Pikachu (Japanese: ピカチュウ Pikachū) is an Electric-type Pokémon introduced in Generation I.
Jigglypuff (Japanese: ポッポ Poppo) is a Normal/Fairy-type Pokémon introduced in Generation I.
Installation
Usage
The root filters items by comparing the normalized query against item.name, PokedexItems renders a responsive grid, and PokedexLoadMore manages its own labels. The component composes Radix UI primitives and shadcn/ui components (button, empty, input-group) under the hood. Data fetching is always the consumer's responsibility — you supply the items array; this component handles state and rendering.
Tip
Building a full Pokédex? Follow the step-by-step guide at Build a Pokédex.
Examples
Grid
PokedexItems renders a responsive grid by default; pageSize + PokedexLoadMore add incremental pagination.
Empty state
PokedexEmpty appears only when there are no matches; PokedexClear resets the search and disables itself automatically.
Count
PokedexCount accepts a render prop with visible, matched, and total for formatting the count display.
Controlled state
Each piece of state follows the value / defaultValue / onChange pattern, so you can sync search with the URL, a form, or external state.
Server-side filtering
If your items already arrive filtered (server-side search, external index), disable internal filtering with shouldFilter.
Data-aware filters
The filter shape (PokedexFilterState) covers generations, primary/secondary type, legendaries, and mythicals. Only your app knows which generation each Pokémon belongs to, so inject your own filterFn — or pre-filter and use shouldFilter={false}.
Infinite scroll
usePokedex() exposes the full context state. Wire loadMore to an IntersectionObserver instead of a button.
Accessibility
PokedexSearch is a standard text <input> — add your own aria-label or associate it with a <label>. The built-in clear button and PokedexClear expose accessible labels and disable themselves when there is nothing to clear.
Keyboard interactions
| Key | Description |
|---|---|
| Escape | Clears the search if there is text. When the query is already empty, the event continues to propagate (e.g., to close a containing dialog). |
API Reference
Pokedex
Root of the component set. Owns the search, filter, and pagination state, and exposes it through context to all subcomponents. query and filters follow the controlled/uncontrolled pattern. Also accepts all native <div> props.
| Prop | Type | Default |
|---|---|---|
items | T[] | [] |
getItemKey | item.name ?? index | |
getItemName | item.name | |
query | string | — |
defaultQuery | string | "" |
onQueryChange | — | |
filters | PokedexFilterState | — |
defaultFilters | PokedexFilterState | EMPTY_POKEDEX_FILTERS |
onFiltersChange | — | |
shouldFilter | boolean | true |
filterFn | matcher por query | |
pageSize | number | — |
loading | boolean | false |
asChild | boolean | false |
PokedexSearch
Search input bound to the context query, with a search icon and a built-in clear button (visible only when there is text). className is applied to the wrapper; all other props go to the <input>. Also accepts all native <input> props.
| Prop | Type | Default |
|---|---|---|
placeholder | string | "Buscar Pokémon…" |
onChange | — |
PokedexClear
Button that resets the search, the filters, or both. Disables itself automatically when there is nothing to clear. Also accepts all native <button> props.
| Prop | Type | Default |
|---|---|---|
clears | "all" | |
variant | "outline" | |
size | "sm" |
PokedexItems
Renders the visible items (including the pagination window) with a key resolved by getItemKey. Responsive grid by default; override className for any other layout (list, table, masonry). Also accepts all native <div> props.
| Prop | Type | Default |
|---|---|---|
renderItem | — | |
className | string | grid responsive 1→5 col |
asChild | boolean | false |
PokedexEmpty
Empty state. Only renders when there are no matches and loading is false. Compose its content with EmptyHeader, EmptyTitle, EmptyDescription, and EmptyContent. Exposes data-reason="no-match" when there is an active query or filters, and data-reason="no-items" when no items arrived at all. Also accepts all native <div> props.
PokedexLoadMore
Pagination button. Returns null when pageSize is unset or there are no matches; disables itself and exposes data-state="exhausted" when all results are shown. Also accepts all native <button> props.
| Prop | Type | Default |
|---|---|---|
children | ReactNode | "Load more" / "No more" |
variant | "default" | |
size | "default" |
PokedexCount
Result count display. Also accepts all native <span> props.
| Prop | Type | Default |
|---|---|---|
children | visible / matched | |
asChild | boolean | false |
usePokedex
Context access hook — must be used inside <Pokedex>. Generic: usePokedex<MyType>().
| Property | Type | Description |
|---|---|---|
| items | T[] | All items as supplied. |
| matchedItems | T[] | Items after filterFn (or items when shouldFilter is false). |
| visibleItems | T[] | Matches trimmed to the current pagination window. |
| query / queryNormalized | string | Raw query and normalized form (trimmed + lowercased). |
| setQuery | (query: string) => void | Updates the query. |
| filters | PokedexFilterState | Current filter state. |
| setFilters | (filters | updater) => void | Replaces or updates filters. |
| toggleGeneration / togglePrimaryType / toggleSecondaryType | (name: string) => void | Toggles a value in the corresponding list. |
| setGenerations | (names: string[]) => void | Replaces the generation selection (e.g., radio behavior). |
| setLegendaryOnly / setMythicalOnly | (value: boolean) => void | Enables or disables the flag. |
| clearFilters | () => void | Resets to EMPTY_POKEDEX_FILTERS. |
| hasActiveFilters | boolean | true when any filter is active. |
| pageSize | number | null | null when pagination is disabled. |
| visibleCount | number | Current window size. |
| hasMore | boolean | Whether more items remain to be shown. |
| loadMore | () => void | Expands the window by pageSize. |
| loading | boolean | The loading prop from the root. |
PokedexFilterState
EMPTY_POKEDEX_FILTERS is exported as the initial/reset value.
