DEV Community

dhruv
dhruv

Posted on

Structuring a Lightweight React Kanban UI (Vanilla CSS & Vite)

When building internal tools or dashboard prototypes, it can be tempting to immediately install heavy component libraries like Material-UI or Ant Design.

While these libraries are powerful, for many early-stage prototypes a lightweight setup using Vite, React, and Vanilla CSS can be simpler to customize and easier to maintain.

In this tutorial, we'll look at the frontend architecture of a light-themed CRM dashboard featuring a Kanban-style sales pipeline layout.

Technical Scope

Before looking at the code, it's important to define what this example actually includes.

What this is:

  • A static frontend UI prototype
  • A React application built with Vite
  • A responsive Kanban-style layout
  • Static mock CRM data
  • Vanilla CSS styling
  • Basic menu state using React useState

What this is NOT:

  • A production CRM
  • A backend application
  • A database-connected system
  • An API-integrated application
  • An authentication system
  • A drag-and-drop Kanban board

The goal here is simply to demonstrate how a clean CRM-style frontend can be structured using React and standard CSS.

The React Component

A dashboard like this can be split into two main areas:

  1. A sidebar used for navigation
  2. A main content area containing the sales pipeline

For this prototype, we use React's useState hook to visually track the active navigation item.

The pipeline itself uses static mock data.

import { useState } from 'react';
import './index.css';

function App() {
  const [activeMenu, setActiveMenu] = useState('pipeline');

  const leads = {
    new: [
      {
        id: 1,
        name: 'Acme Corp',
        value: '$5,000'
      }
    ],

    contacted: [
      {
        id: 3,
        name: 'Wayne Ent',
        value: '$8,200'
      }
    ],

    qualified: [
      {
        id: 5,
        name: 'Oscorp',
        value: '$25,000'
      }
    ],

    won: [
      {
        id: 6,
        name: 'Globex',
        value: '$14,000'
      }
    ]
  };

  return (
    <div className="crm-app">

      {/* Sidebar Navigation */}
      <aside className="sidebar-light">

        <div className="brand">
          <h1>LeadFlow CRM</h1>
        </div>

        <nav className="nav-menu">

          <button
            className={
              activeMenu === 'dashboard'
                ? 'active'
                : ''
            }
            onClick={() =>
              setActiveMenu('dashboard')
            }
          >
            Dashboard
          </button>

          <button
            className={
              activeMenu === 'pipeline'
                ? 'active'
                : ''
            }
            onClick={() =>
              setActiveMenu('pipeline')
            }
          >
            Sales Pipeline
          </button>

        </nav>

      </aside>

      {/* Main Content */}

      <main className="main-board">

        <header className="board-header">

          <h2>Sales Pipeline</h2>

          <button className="btn-primary">
            + New Deal
          </button>

        </header>

        {/* Kanban Board */}

        <div className="kanban-board">

          <div className="kanban-column">

            <h3>New Leads</h3>

            {leads.new.map((lead) => (

              <div
                className="kanban-card"
                key={lead.id}
              >

                <h4>{lead.name}</h4>

                <span className="value">
                  {lead.value}
                </span>

              </div>

            ))}

          </div>

          {/* Additional columns can be rendered here */}

        </div>

      </main>

    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

The CSS Layout

The main layout can be handled entirely with CSS Flexbox.

The root container is displayed as a flex layout so the sidebar and the main dashboard sit next to each other.

.crm-app {
  display: flex;
  height: 100vh;
  overflow: hidden;
  background-color: #f8fafc;
  color: #0f172a;
}
Enter fullscreen mode Exit fullscreen mode

Sidebar

The sidebar uses a fixed width and does not shrink when the main dashboard grows.

.sidebar-light {
  width: 260px;
  background-color: #ffffff;
  border-right: 1px solid #e2e8f0;

  display: flex;
  flex-direction: column;

  flex-shrink: 0;
}
Enter fullscreen mode Exit fullscreen mode

This keeps the navigation visually stable while the main dashboard content remains flexible.

Main Dashboard Area

The main content area takes up the remaining screen space.

.main-board {
  flex-grow: 1;

  display: flex;
  flex-direction: column;

  overflow-x: auto;
}
Enter fullscreen mode Exit fullscreen mode

Horizontal Kanban Layout

The Kanban board is also a flex container.

Each column has a fixed minimum width so the board can scroll horizontally if more columns are added.

.kanban-board {
  display: flex;

  padding: 32px;

  gap: 24px;

  overflow-x: auto;

  flex-grow: 1;

  align-items: flex-start;
}
Enter fullscreen mode Exit fullscreen mode

Individual Kanban Columns

Each pipeline stage is represented by a simple column.

.kanban-column {
  min-width: 280px;
  width: 280px;

  background-color: #f1f5f9;

  border-radius: 12px;

  padding: 16px;

  display: flex;
  flex-direction: column;

  gap: 16px;
}
Enter fullscreen mode Exit fullscreen mode

Cards inside each column can then display information such as:

  • Company name
  • Deal value
  • Status
  • Contact information
  • Sales stage

For this prototype, the data is intentionally static.

Responsive Behavior

A simple media query can adapt the layout for smaller screens.

For example:

@media (max-width: 768px) {

  .crm-app {
    flex-direction: column;
  }

  .sidebar-light {
    width: 100%;
  }

  .kanban-board {
    padding: 16px;
    overflow-x: auto;
  }
}
Enter fullscreen mode Exit fullscreen mode

This can move the sidebar above the dashboard and keep the Kanban board horizontally scrollable on smaller screens.

Why This Approach Can Be Useful

1. Simple Setup

No additional UI component library is required for this prototype, which keeps the setup simple and gives you direct control over the styling.

2. Fast Development Workflow

Vite provides a fast development experience with quick startup and hot module replacement for typical frontend projects.

3. Full Styling Control

Using Vanilla CSS means you control:

  • spacing
  • typography
  • colors
  • borders
  • shadows
  • responsive behavior

without overriding a component library's existing design system.

4. Clear Component Structure

React makes it easy to break a dashboard into reusable pieces such as:

  • Sidebar
  • Header
  • Kanban Column
  • Deal Card
  • Metric Card
  • Table
  • Form

As the prototype grows, these can be separated into individual components.

Important Limitations

This example is intentionally limited to frontend UI structure.

It does not include:

  • API requests
  • Authentication
  • Database storage
  • Drag-and-drop behavior
  • Real CRM data
  • Backend business logic

Those features would require additional development beyond the scope of this lightweight frontend prototype.

Final Result

Using only:

  • React
  • Vite
  • Vanilla CSS
  • Static mock data

you can build a clean and responsive CRM-style dashboard prototype without immediately introducing large UI libraries or backend infrastructure.

This type of setup can be useful when validating an interface, building an internal-tool prototype, or turning an existing wireframe into a functional frontend.


If you need help building a small responsive React dashboard or frontend prototype, you can view my Upwork service here:

Top comments (0)