Remix: Create a navigation

On websites it’s common to have a navigation header (or sidebar) with links that have an “active” state, which means they get a visual indication that you’re on that specific page.

Let’s see how to do that with Remix.

You know how to use the Link component to link to another page:

<Link to="/about">
  About
</Link>

There’s another Remix component called NavLink that does the same, but also comes with additional functionality attached.

import { NavLink } from "@remix-run/react"

If Remix knows the link is active, it adds the active HTML class to it, so you can style it with CSS. When the active link is pending (undefined), it will have a pending class.

You can provide a callback function to the className prop to customize the class when the link is active, for example to add a Tailwind class:

<NavLink
  to="/about"
  className={({ isActive }) =>
    isActive ? "font-bold" : ""
  }
>
  About
</NavLink>

Let’s do an example, suppose you have 3 routes: /, /about and /contact, powered by 3 files:

  • app/routes/_index.jsx
  • app/routes/about.jsx
  • app/routes/contact.jsx

We’ll have a component imported by those 3 route components, let’s call it Nav.

Create a folder app/components and a new file Nav.jsx

In there we create links to those 3 routes using NavLink:

import { NavLink } from '@remix-run/react'

export default function Nav() {
  return (
    <nav className='flex gap-4'>
      <NavLink
        to='/'
        className={({ isActive }) => (isActive ? 'font-bold' : '')}>
        Home
      </NavLink>
      <NavLink
        to='/about'
        className={({ isActive }) => (isActive ? 'font-bold' : '')}>
        About
      </NavLink>
      <NavLink
        to='/contact'
        className={({ isActive }) => (isActive ? 'font-bold' : '')}>
        Contact
      </NavLink>
    </nav>
  )
}

Now you can import this component on top of every route component, like this:

//app/routes/contact.jsx
import Nav from '../components/Nav'

export const meta = () => {
  return [{ title: 'Contact' }]
}

export default function Contact() {
  return (
    <div style={{ fontFamily: 'system-ui, sans-serif', lineHeight: '1.4' }}>
      <Nav />
      <h1>Contact us</h1>

      <p>Contact form: ...</p>
    </div>
  )
}
//app/routes/about.jsx
import Nav from '../components/Nav'

export const meta = () => {
  return [{ title: 'About page' }]
}

export default function About() {
  return (
    <div style={{ fontFamily: 'system-ui, sans-serif', lineHeight: '1.4' }}>
      <Nav />
      <h1>About this site</h1>
      <p>It's a very cool site!</p>
    </div>
  )
}

And if you open the site in the browser you’ll see the navigation apply the font-bold Tailwind CSS class if the route corresponds to the NavLink:

Lessons in this unit:

0: Introduction
1: Create your first Remix app
2: The root route
3: File based routing
4: Linking your pages
5: Styling with CSS and Tailwind
6: ▶︎ Create a navigation
7: Dynamic routes and nested routes
8: Connecting a database
9: Data mutations using forms and actions
Are you intimidated by Git? Can’t figure out merge vs rebase? Are you afraid of screwing up something any time you have to do something in Git? Do you rely on ChatGPT or random people’s answer on StackOverflow to fix your problems? Your coworkers are tired of explaining Git to you all the time? Git is something we all need to use, but few of us really master it. I created this course to improve your Git (and GitHub) knowledge at a radical level. Launching May 21, 2024. Join the waiting list!