Linking and Navigating

Bini.js provides built-in navigation components and hooks for fast, client-side transitions between routes without full page reloads. This page covers how to use Link, NavLink, and the navigation hooks.

useNavigate hook

The useNavigate hook returns a function that lets you navigate programmatically. It is auto-imported in all pages.

app
login
page.tsx
dashboard
page.tsx
/login
/dashboard
app/login/page.tsx
export default function LoginPage() {
  const navigate = useNavigate()

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault()
    const success = await loginUser()
    if (success) navigate('/dashboard')
  }

  return (
    <form onSubmit={handleSubmit}>
      <button type="submit">Login</button>
    </form>
  )
}

Navigate options

OptionTypeDescription
replacebooleanReplace the current entry in history
stateanyState to persist to the location
// Navigate with options
navigate('/profile', { replace: true, state: { from: 'login' } })

// Go back
navigate(-1)

// Go forward
navigate(1)

useParams hook

The useParams hook returns an object of key/value pairs of the dynamic route parameters from the current URL. Wrap a folder name in square brackets, like [slug], to create a dynamic segment.

app
blog
[slug]
page.tsx
/blog/:slug
app/blog/[slug]/page.tsx
export default function BlogPost() {
  const { slug } = useParams<{ slug: string }>()

  return (
    <div>
      <h1>Blog Post: {slug}</h1>
    </div>
  )
}

useLocation hook

The useLocation hook returns the current location object, including pathname, search, hash, and any state passed during navigation. This is useful for things like breadcrumbs.

app/components/Breadcrumbs.tsx
export default function Breadcrumbs() {
  const location = useLocation()
  const segments = location.pathname.split('/').filter(Boolean)

  return (
    <nav>
      <Link to="/">Home</Link>
      {segments.map((name, index) => {
        const routeTo = `/${segments.slice(0, index + 1).join('/')}`
        return (
          <Link key={routeTo} to={routeTo}>
            {name}
          </Link>
        )
      })}
    </nav>
  )
}

Location properties

PropertyTypeDescription
pathnamestringThe path of the current URL
searchstringThe query string, including the leading ?
hashstringThe URL hash, including the leading #
stateanyState passed via Link or navigate
keystringA unique key for this location entry

useSearchParams hook

The useSearchParams hook reads and updates the query string. It works like useState: you get the current params and a function to change them.

app/shop/page.tsx
export default function ShopPage() {
  const [searchParams, setSearchParams] = useSearchParams()
  const category = searchParams.get('category') || 'all'

  return (
    <div>
      <p>Category: {category}</p>
      <button onClick={() => setSearchParams({ category: 'shoes' })}>
        Show shoes
      </button>
    </div>
  )
}

Programmatic navigation

While <Link> is ideal for declarative navigation in your JSX, sometimes you need logic before navigating. useNavigate returns a function you can call inside event handlers, effects, or after async operations. It performs the same client-side navigation as <Link>, preserving layout state and skipping a full page reload.

This is a good fit for post-form redirects, authentication flows, and conditional navigation. Pass replace: true when the user shouldn't be able to go back to the previous page, such as after logging in.

app/login/page.tsx
export default function LoginPage() {
  const navigate = useNavigate()
  const { state } = useLocation()

  const handleLogin = async () => {
    const result = await login()
    if (!result.success) return

    // Send the user back to where they came from
    navigate(state?.from ?? '/dashboard', { replace: true })
  }

  return <button onClick={handleLogin}>Login</button>
}

Best practices

  • Use <Link> for standard navigation links.
  • Use <NavLink> for navigation menus that need active-state styling.
  • Use useNavigate for programmatic navigation, such as redirects after a form or login.
  • Use useParams to access dynamic route parameters.
  • Use useSearchParams for managing query strings and filters.
Was this helpful?