Introduction to Our Frontend Tech Stack

React + Vite + TypeScript + Shadcn UI

Agenda

  1. HTML, CSS, JavaScript: The Fundamentals
  2. React: Component-Based UI
  3. Vite: Modern Build Tool
  4. TypeScript: Type Safety
  5. TailwindCSS: Utility-First Styling
  6. Public Folder Structure
  7. App Architecture
  8. Routing Strategy
  9. Future Plans for DRI-UI

Why a Shared Frontend?

Mono-repo approach:

  • Easy visibility
  • Code sharing, shared knowledge
  • Discoverability
  • Improved collaboration across teams
  • Projects should stop feeling quite so alien to each team
  • Consistent look and feel across projects
  • Standardisation across the group, we can all become experts in the same tech together
  • Benefit from updates across all projects

Downsides of a shared frontend monorepo

Downsides:

  • Common code updates can impact many projects
  • Deployment process can become more challenge
  • Maintenance and management of the shared codebase can lose clear ownership

HTML, CSS, JavaScript: The Fundamentals

  • HTML: Structure of the page
  • CSS: Styling and layout
  • JavaScript: Interactivity and behavior
<div>
  <h2>Counter</h2>
  <div id="value">0</div>
  <button id="increment">+</button>
</div>

<script>
  let count = 0;
  const value = document.getElementById('value');
  
  document.getElementById('increment').addEventListener('click', function() {
    count++;
    value.textContent = count;
  });
</script>

The Problem with Traditional Approaches

  • Difficult to reuse UI components
  • Hard to keep UI in sync with data
  • Becomes unmaintainable as app grows

Enter React

React is a library for building user interfaces:

  • Component-based: Break UI into reusable pieces
  • Virtual DOM: Efficiently updates the real DOM
  • One-way data flow: Predictable state management

React Components

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <h2>Counter</h2>
      <div>{count}</div>
      <button onClick={() => setCount(count + 1)}>+</button>
    </div>
  );
}

✅ Reusable
✅ Self-contained
✅ Testable
✅ Maintainable

Vite: Modern Build Tool

  • Lightning fast development server
  • Hot Module Replacement (HMR)
  • Optimized production builds
  • No/little configuration required

TypeScript: Adding Type Safety

JavaScript:

function printUser(user) {
  // What properties does user have?
  console.log(user.name); // Might be undefined!
}

TypeScript:

interface User {
  id: number;
  name: string;
  email: string;
  role: 'admin' | 'user';
}

function printUser(user: User) {
  console.log(user.name); // Safe!
}

TypeScript Benefits

  • Catch errors at compile time, not runtime
  • Better developer experience (autocomplete)
  • Self-documenting code
  • Safer refactoring
// Component with typed props
interface ButtonProps {
  text: string;
  onClick: () => void;
  variant?: 'primary' | 'secondary';
  disabled?: boolean;
}

function Button({ text, onClick, variant = 'primary', disabled = false }: ButtonProps) {
  // Implementation
}

TailwindCSS: Utility-First CSS

Traditional CSS:

.btn {
  padding: 0.5rem 1rem;
  background-color: #3b82f6;
  color: white;
  border-radius: 0.25rem;
}
.btn:hover {
  background-color: #2563eb;
}

Tailwind CSS:

<button className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
  Click Me
</button>

Why Tailwind?

  • Write CSS directly in your HTML/JSX via class names
  • No more naming CSS classes
  • Consistent design system
  • Responsive design made easy with media query shortcuts like w-[100px] md:w-[200px]
  • Highly customizable

Shadcn UI: Accessible Components

A component library that gets included in a simple way

  • downloads it directly into the code base
  • means we have the flexibility to modify it to our needs if required
  • out the box styled and accessible components
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Card, CardHeader, CardContent } from "@/components/ui/card";

function LoginForm() {
  return (
    <Card>
      <CardHeader>Login</CardHeader>
      <CardContent>
        <Input placeholder="Email" type="email" />
        <Input placeholder="Password" type="password" className="mt-2" />
        <Button className="mt-4 w-full">Sign In</Button>
      </CardContent>
    </Card>
  );
}

Public Folder Structure

public/
  └── v1/
      ├── cosmos/
  • Static files served directly
  • acts as a fake api
  • means development doesn't rely on a deployed api
  • development can update both in the same repo

App Structure

/src/app/
        main.tsx
        cosmos/main.tsx
        |     |
        |     /pages, components, etc
        |
        fdri/main.tsx
        |   |
        |   /pages, componets, etc
        |
        lcm/main.tsx
        ...

Routing Strategy

import { Routes, Route } from 'react-router-dom';

function App() {
  return (
     <BrowserRouter>
      <Routes>
        <Route index element={<Overview />} />
        <Route path="/cosmos/*" element={<Cosmos />} />
        <Route path="/fdri/*" element={<Fdri />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
    </BrowserRouter>
  );
}
  • Client-side routing
  • No page refreshes
  • Nested routes
  • URL parameters

Future Plans for DRI-UI

Potential new things:

  • split out the compiling
  • npm workspaces
  • Storybook integration
  • Accessibility audits with lighthouse
  • End-to-end testing
  • State management solution

Questions?

Thank you!