DEV Community

Voke
Voke

Posted on

Building in Public: CV Analyzer - Act 3 · Scene 1 : Before The AuthPage

This post walks through setting up reusable UI components and active navigation in a React app using React Router’s NavLink, preparing the codebase for authentication and future feature pages.

Click here for Act 2 · Scene 2

Table of Contents

Act 3 · Scene 1: Before The AuthPage

In this scene, I introduced reusable UI building blocks and active navigation using React Router’s NavLink, laying groundwork for authentication and analysis flows before building the actual pages.

Overview

With routing, layout, and the home page now stable, the application finally has a backbone. At this point, it made sense to pause feature work and ask myself a quiet question:

What UI decision am I going to regret not making early?

Two answers came back immediately:

  • Reusable layout wrappers
  • Navigation that knows where you are

So that’s what this scene is about.

Here in this scene, I am introducing two structural UI elements that will support everything that comes next:

  • A reusable Card component to standardize layout
  • Active navigation state using NavLink

Creating a Reusable Card Component

A Card is a reusable UI wrapper component that standardizes layout and styling. It centralizes layout and styling ensuring a consistent visual structure across the application.

Instead of repeating padding, borders, and spacing rules, I created a reusable wrapper.

Folder structure:

components/
ui/
card/
Card.tsx
Card.module.scss

The Card.tsx file:

import type React from "react";
import classes from "./Card.module.scss";

const Card: React.FC<{ children: React.ReactNode; className: string }> = (
  props
) => {
  return (
    <div className={`${classes.card} ${props.className}`}>
      {props.children}
    </div>
  );
};

export default Card;
Enter fullscreen mode Exit fullscreen mode

Just a wrapper that does its job and stays out of the way. This is the kind of component you don’t think about later.

Adding Active Navigation with NavLink

Next problem:

The navigation had no awareness. It didn’t know where the user was. It didn’t react.

That felt kind of off.

I needed it to react when a user visits a specific page or route.

Instead of using the ever popular Link, I used NavLink in its place. And added a small helper to conditionally apply styles based on route activity:

const navDataHandler = (navData: any) => {
  return navData.isActive ? classes.active : "";
};
Enter fullscreen mode Exit fullscreen mode

The MainNav looked like this:

<h1>
  <NavLink to="/" className={navDataHandler}>
    <span>AI Talent Profile</span> Analyzer
  </NavLink>
</h1>

<nav>
  <ul>
    <li>
      <NavLink to="/auth" className={navDataHandler}>
        Auth
      </NavLink>
    </li>
    <li>
      <NavLink to="/analysis-form" className={navDataHandler}>
        Analyze Candidate
      </NavLink>
    </li>
  </ul>
</nav>
Enter fullscreen mode Exit fullscreen mode

This was added to the scss file:

.active {
  border-bottom: 1px solid red;
}

a {
  text-decoration: none;
}
Enter fullscreen mode Exit fullscreen mode

At this point, active routes were visually clear.

What Happens When Routes Don’t Exist (Yet)

Alright, here comes an interesting part.

I saved the file. Hot reload kicked in. And for a moment, everything looked… fine.
The active state kicked in exactly where it should; there was a red underline under AI Talent Profile Analyzer, which told me the NavLink logic was doing its job.

But then I clicked Auth. And Boooooooom!!!

I saw this:

Got the Same thing for Analyze Candidate.

Meanwhile I saw this in the console for both auth and analyze candidate:

For auth:

For AnalyzeCandidate:

No routes matched location is what is being displayed in the browser console for both auth and analyze candidate.

But in all honesty, this was expected.

Do you know why?

This happened because these routes don’t exist yet in the router configuration.

Current router tree in App.tsx:

function App() {
  const router = createBrowserRouter([
    {
      path: "/",
      element: <RootLayout />,
      errorElement: <ErrorPage />,
      children: [{ path: "/", element: <HomePage /> }],
    },
  ]);

  return <RouterProvider router={router} />;
}
Enter fullscreen mode Exit fullscreen mode

As you can see from the code above, there are no entries for: /auth or /analysis-form.

So React Router correctly falls back to the error boundary.

This is not a bug. I repeat, this is not a bug.
That’s the system working as designed.

So, how do I go about fixing it? Well, stay tuned. We will break it down in the next scene.

Mental Model

At this stage:

  • Navigation reflects application state
  • UI building blocks are reusable and consistent
  • Routes are intentionally incomplete
  • The app is telling me what to build next

Why This Scene Matters

This scene shows that I:

  • Build foundations before features
  • Expect systems to be incomplete mid-build
  • Think in reusable UI layers
  • Let architecture guide the next step

Thanks for reading.
Let’s move on to the Next Scene.

We in the Building…
Building in Progress…

Top comments (0)