hono-preact
Overview
Quick Start
The Route Table
Layouts & Nesting
Adding Pages
Active Links
Server Loaders
Loading States
Reloading Data
Prefetching
Streaming
Live Loaders
Realtime Channels
Server Actions
Validation
Optimistic UI
View Transitions
Middleware
CSRF Protection
CLI
Vite Config
Project Structure
Composing Hono Middleware
WebSockets
Rooms & Presence
renderPage
Link Prefetch
Build & Deploy
Overview
Dialog
Popover
Tooltip
Menu
Context Menu
Select
Combobox
Toast
renderElement
useControllableState
mergeRefs
useListNavigation
useTypeahead
useListboxSelection
usePosition
usePositioner
useDismiss
useFocusReturn
useSafeArea
usePresence

Active Links#

Highlighting the current page in navigation needs one question answered: does the current URL match a given route? useRouteActive, useRouteMatch, and <NavLink> answer it against the same route grammar your route table uses, so /posts/:id matches any post and hands you the id.

useRouteActive#

Returns true when the current path matches the route.

import { useRouteActive } from 'hono-preact';

function Tab() {
  const active = useRouteActive('/docs');
  return (
    <a href="/docs" aria-current={active ? 'page' : undefined}>
      Docs
    </a>
  );
}

By default the match is exact. Pass { exact: false } to also match descendant paths, e.g. highlight a section for every page beneath it:

// active on /docs/components AND /docs/components/dialog
const inSection = useRouteActive('/docs/components', { exact: false });

One caveat: because every path is a descendant of /, a non-exact match on the root (useRouteActive('/', { exact: false })) is active everywhere. Keep a "Home" link exact (the default).

useRouteMatch#

Same matching, but returns the captured params (or null). Use it when you want to both test and read the dynamic segments.

import { useRouteMatch } from 'hono-preact';

function Crumb() {
  const params = useRouteMatch('/posts/:id');
  // on /posts/42 -> { id: '42' }, elsewhere -> null
  return params ? <span>Post {params.id}</span> : null;
}

The route accepts the full pattern grammar: :param, *, +, :param?.

buildPath#

Build a typed URL from a route pattern and its params. TypeScript enforces that the pattern is registered and that the params object matches the pattern's dynamic segments. Param values must be strings; convert numbers or other types before passing them.

import { buildPath } from 'hono-preact';

// /posts/42
const href = buildPath('/posts/:id', { id: '42' });

// /dashboard  (no params needed; second argument is omitted)
const dashHref = buildPath('/dashboard');

buildPath is the safe alternative to template literals: a wrong key or a missing param is a compile error, not a silent bug.

A <a> that applies an active or inactive class for you (and sets aria-current="page" when active).

import { NavLink } from 'hono-preact';

<NavLink
  href="/docs"
  activeClass="text-accent font-semibold"
  inactiveClass="text-muted"
>
  Docs
</NavLink>;

Any class you pass is always applied; activeClass / inactiveClass are merged on top per state. Other anchor props (target, rel, data-*) pass straight through.

Use exact={false} for section links, and match when the link target differs from the pattern you want to highlight on:

// links to /posts, but stays active on /posts/123
<NavLink href="/posts" match="/posts/:id" activeClass="text-accent">
  Posts
</NavLink>

useNavigate() returns a navigate(path, options?) function for navigating from an event handler (a logout button, a post-action redirect). A soft navigate runs the same client middleware, loaders, and view transitions as a <NavLink> click.

import { useNavigate } from 'hono-preact';

function LogoutButton() {
  const navigate = useNavigate();
  return (
    <button onClick={() => navigate('/login', { replace: true })}>
      Log out
    </button>
  );
}
OptionTypeDefaultDescription
replacebooleanfalseReplace the current history entry instead of pushing a new one.
reloadbooleanfalseDo a full-page navigation (clean slate) instead of a client navigation.

API reference#

<NavLink> forwards any other <a> attribute (e.g. target, rel, data-*) to the underlying anchor and sets aria-current="page" while the link is active.

PropTypeDefaultDescription
hrefstringrequiredDestination path.
matchstringhrefPattern tested for the active state.
exactbooleantrueMatch the full path; set false for prefix (section) matching.
classstringnoneAlways applied.
activeClassstringnoneMerged in when the link is active.
inactiveClassstringnoneMerged in when the link is not active.

See also#