Usage

Everything you need to drop pokenav into a React app. Prefer picking sprites visually? Use the playground and copy the config it generates.

Install

npm install pokenav

react and react-dom(>=18) are peer dependencies. Import the stylesheet once, anywhere in your app — in the Next.js App Router, your root layout:

import 'pokenav/styles.css';

Minimal example

The smallest config that renders: a position, an orientation, and some items. Every other field has a default.

import { Pallet } from 'pokenav';
import 'pokenav/styles.css';

<Pallet
  position="left"
  orientation="vertical"
  items={[
    { label: 'Home', href: '/', pokemonId: 133 },
    { label: 'Work', href: '/work', pokemonId: 81 },
    { label: 'Contact', href: '/contact', pokemonId: 185 },
  ]}
  activeHref={pathname}
/>
Live — rendered from the config on the left

activeHrefis a plain string you supply — the component compares it to each item's href and imports no router. Use usePathname() in the App Router, useRouter().pathname in Pages, useLocation().pathname in React Router, or your own scroll-spy.

NavConfig reference

PropTypeDefaultDescription
position'left' | 'center' | 'right'Which edge the trail anchors to. Also sets which side labels and the pokéball button sit on; center follows left there.
orientation'vertical' | 'horizontal'Which axis the trail runs along. Independent of position.
itemsNavItem[]One node per item, in trail order.
themeNavTheme{}Optional styling. See below.

NavItem

FieldTypeDescription
labelstringVisible label, and the section half of the sprite's alt text.
hrefstringLink destination, and what activeHref is compared against.
pokemonIdnumber?National Dex id, 1–898. Resolved from the bundled catalogue, loaded lazily.
spriteUrlstring?Any custom image. Wins over pokemonId and skips the catalogue entirely.

NavTheme

FieldTypeDefaultDescription
accentColorstring#64748bSingle source of truth for the active ring, hover ring, inactive ring, trail and focus ring. No color is hardcoded.
ringStyle'solid' | 'pokeball'solidpokeball draws a red/white split ring with a button on the seam.
trailPath'straight' | 'wavy'straightwavy draws the trail as a curve through the node centers instead of a straight line.
dotStyle'dotted' | 'dashed' | 'solid'dottedHow the connecting trail is stroked.
fontstringinheritCSS font-family applied to labels.

Component props beyond NavConfig

PropTypeDescription
activeHrefstring?Current route. Omit and no node is active.
scrollProgressnumber?0–1. Fills the trail and moves the highlight. useScrollProgress() is exported for the page-scroll case.
ariaLabelstring?Landmark name. Defaults to 'Site navigation'.
classNamestring?Merged onto the root <nav>.

Centered horizontal nav

position and orientation are independent, so center works as a top nav. In horizontal, labels always sit below the node so the trail never runs through them.

<Pallet
  position="center"
  orientation="horizontal"
  items={[
    { label: 'Home', href: '/', pokemonId: 25 },
    { label: 'Work', href: '/work', pokemonId: 133 },
    { label: 'Writing', href: '/writing', pokemonId: 143 },
    { label: 'Contact', href: '/contact', pokemonId: 448 },
  ]}
  theme={{ accentColor: '#16a34a', trailPath: 'wavy' }}
  activeHref={pathname}
/>
Live — rendered from the config on the left

Custom sprites — no Pokémon required

Set spriteUrl on an item and the bundled catalogue is never touched. Use it on every item and you get the route-map navigation with entirely your own art, and none of the licensing question below applies to your build.

<Pallet
  position="left"
  orientation="vertical"
  items={[
    { label: 'Home', href: '/', spriteUrl: '/icons/star.svg' },
    { label: 'Work', href: '/work', spriteUrl: '/icons/leaf.svg' },
    { label: 'Contact', href: '/contact', spriteUrl: '/icons/bolt.svg' },
  ]}
  theme={{ accentColor: '#8b5cf6' }}
  activeHref={pathname}
/>
Live — rendered from the config on the left

Pick sprites visually

Writing Dex numbers by hand is no fun. The playground lets you search all 898 sprites, filter by generation, assign them to nav items, and copy out the finished config.

Accessibility

Sprites carry alt text in the form "{Pokémon name}{section name}", and the visible label is hidden from assistive technology when a sprite is present so the section is not announced twice. Nodes are ordinary links, so keyboard navigation works by default, with a deliberate focus ring drawn in your accent color. All motion — hover bounce, ring transitions, trail fill — is suppressed under prefers-reduced-motion, while state that carries meaning, like the active node's scale and the scroll fill position, is kept.

Sprite licensing

The code is MIT. The bundled Pokémon sprites are fan-derived artwork, not covered by that license, and rely on the same fan-tolerance precedent as PokéAPI — a precedent, not a guarantee. Read SPRITES-NOTICE.md before shipping anything commercial, and remember that spriteUrl lets you avoid the question entirely.