Skip to Content

Styles Documentation

Overview

The styles directory (src/styles/) contains global CSS styles and theming configuration. The application primarily uses Tailwind CSS for styling, with additional global styles for specific requirements.

Directory Structure

src/styles/ └── globals.css # Global CSS styles and Tailwind directives

Additional styling configuration:

├── tailwind.config.ts # Tailwind configuration (project root) ├── components.json # shadcn/ui configuration (project root) └── postcss.config.cjs # PostCSS configuration (project root)

Global Styles (globals.css)

The main CSS file that defines Tailwind directives, CSS variables, and global styles.

Structure

@tailwind base; @tailwind components; @tailwind utilities; /* CSS Variables */ @layer base { :root { --background: 0 0% 100%; --foreground: 240 10% 3.9%; --card: 0 0% 100%; --card-foreground: 240 10% 3.9%; --popover: 0 0% 100%; --popover-foreground: 240 10% 3.9%; --primary: 240 5.9% 10%; --primary-foreground: 0 0% 98%; --secondary: 240 4.8% 95.9%; --secondary-foreground: 240 5.9% 10%; --muted: 240 4.8% 95.9%; --muted-foreground: 240 3.8% 46.1%; --accent: 240 4.8% 95.9%; --accent-foreground: 240 5.9% 10%; --destructive: 0 84.2% 60.2%; --destructive-foreground: 0 0% 98%; --border: 240 5.9% 90%; --input: 240 5.9% 90%; --ring: 240 5.9% 10%; --radius: 0.5rem; } } /* Global element styles */ @layer base { * { @apply border-border; } body { @apply bg-background text-foreground; font-feature-settings: "rlig" 1, "calt" 1; } } /* Custom utilities */ @layer utilities { .step { counter-increment: step; } .step:before { @apply absolute w-9 h-9 bg-muted rounded-full font-mono font-medium text-center text-base inline-flex items-center justify-center -indent-px border-4 border-background -ml-[50px] mt-[-4px]; content: counter(step); } }

Tailwind Configuration (tailwind.config.ts)

Extended Tailwind configuration with custom theme values.

Key Extensions

import type { Config } from 'tailwindcss'; const config: Config = { darkMode: ['class'], content: [ './pages/**/*.{ts,tsx}', './components/**/*.{ts,tsx}', './app/**/*.{ts,tsx}', './src/**/*.{ts,tsx}', ], theme: { container: { center: true, padding: '2rem', screens: { '2xl': '1400px', }, }, extend: { // Color system using CSS variables colors: { border: 'hsl(var(--border))', input: 'hsl(var(--input))', ring: 'hsl(var(--ring))', background: 'hsl(var(--background))', foreground: 'hsl(var(--foreground))', primary: { DEFAULT: 'hsl(var(--primary))', foreground: 'hsl(var(--primary-foreground))', }, secondary: { DEFAULT: 'hsl(var(--secondary))', foreground: 'hsl(var(--secondary-foreground))', }, destructive: { DEFAULT: 'hsl(var(--destructive))', foreground: 'hsl(var(--destructive-foreground))', }, muted: { DEFAULT: 'hsl(var(--muted))', foreground: 'hsl(var(--muted-foreground))', }, accent: { DEFAULT: 'hsl(var(--accent))', foreground: 'hsl(var(--accent-foreground))', }, popover: { DEFAULT: 'hsl(var(--popover))', foreground: 'hsl(var(--popover-foreground))', }, card: { DEFAULT: 'hsl(var(--card))', foreground: 'hsl(var(--card-foreground))', }, }, borderRadius: { lg: 'var(--radius)', md: 'calc(var(--radius) - 2px)', sm: 'calc(var(--radius) - 4px)', }, fontFamily: { sans: ['var(--font-howden)', 'system-ui', 'sans-serif'], }, keyframes: { 'accordion-down': { from: { height: '0' }, to: { height: 'var(--radix-accordion-content-height)' }, }, 'accordion-up': { from: { height: 'var(--radix-accordion-content-height)' }, to: { height: '0' }, }, }, animation: { 'accordion-down': 'accordion-down 0.2s ease-out', 'accordion-up': 'accordion-up 0.2s ease-out', }, }, }, plugins: [ require('tailwindcss-animate'), ], }; export default config;

shadcn/ui Configuration (components.json)

Configuration for shadcn/ui component library:

{ "$schema": "https://ui.shadcn.com/schema.json", "style": "default", "rsc": false, "tsx": true, "tailwind": { "config": "tailwind.config.ts", "css": "src/styles/globals.css", "baseColor": "zinc", "cssVariables": true }, "aliases": { "components": "@/components", "utils": "@/utils/cn" } }

Styling Architecture

1. Tailwind First

Use Tailwind utilities for all styling needs:

// Preferred <div className="flex items-center justify-between p-4 bg-white rounded-lg shadow-sm"> // Avoid <div style={{ display: 'flex', alignItems: 'center', padding: '1rem' }}>

2. Component Variants

Use class-variance-authority for component variants:

import { cva, type VariantProps } from 'class-variance-authority'; const buttonVariants = cva( 'inline-flex items-center justify-center rounded-md text-sm font-medium', { variants: { variant: { default: 'bg-primary text-primary-foreground hover:bg-primary/90', destructive: 'bg-destructive text-destructive-foreground', outline: 'border border-input bg-background', secondary: 'bg-secondary text-secondary-foreground', ghost: 'hover:bg-accent hover:text-accent-foreground', link: 'text-primary underline-offset-4 hover:underline', }, size: { default: 'h-10 px-4 py-2', sm: 'h-9 rounded-md px-3', lg: 'h-11 rounded-md px-8', icon: 'h-10 w-10', }, }, defaultVariants: { variant: 'default', size: 'default', }, } );

3. CSS Variables for Theming

HSL values in CSS variables enable easy theming:

:root { --primary: 240 5.9% 10%; /* HSL values */ } /* Usage in Tailwind */ .text-primary { color: hsl(var(--primary)); }

Benefits:

  • Easy dark mode switching
  • Runtime theme customization
  • Opacity support with / syntax: bg-primary/50

Color System

Semantic Colors

TokenLight ModeUsage
--backgroundWhitePage background
--foregroundNear blackPrimary text
--primaryDark grayPrimary buttons, links
--secondaryLight graySecondary buttons
--mutedVery light graySubtle backgrounds
--accentLight grayHighlights, hover states
--destructiveRedErrors, deletions
--borderLight grayBorders, dividers

Color Usage Patterns

// Primary actions <Button className="bg-primary text-primary-foreground hover:bg-primary/90"> Save </Button> // Secondary actions <Button variant="secondary">Cancel</Button> // Destructive actions <Button variant="destructive">Delete</Button> // Muted text <p className="text-muted-foreground">Helper text</p> // Card backgrounds <Card className="bg-card text-card-foreground">

Responsive Design

Breakpoints

BreakpointWidthUsage
sm640pxSmall tablets
md768pxTablets
lg1024pxSmall laptops
xl1280pxDesktops
2xl1400pxLarge screens

Responsive Patterns

// Mobile-first approach <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4"> // Responsive padding <div className="p-4 md:p-6 lg:p-8"> // Responsive typography <h1 className="text-xl md:text-2xl lg:text-3xl"> // Hide/show elements <MobileNav className="block lg:hidden" /> <DesktopNav className="hidden lg:block" />

Custom Utilities

Container Queries

@layer utilities { .container-query { container-type: inline-size; } @container (min-width: 400px) { .container-responsive { flex-direction: row; } } }

Animation Utilities

@layer utilities { .animate-fade-in { animation: fadeIn 0.3s ease-in-out; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } }

Dark Mode

The application supports dark mode through CSS variables:

:root { /* Light mode (default) */ --background: 0 0% 100%; --foreground: 240 10% 3.9%; } .dark { /* Dark mode overrides */ --background: 240 10% 3.9%; --foreground: 0 0% 98%; }

Implementation:

// Using next-themes import { ThemeProvider } from 'next-themes'; <ThemeProvider attribute="class" defaultTheme="light"> <App /> </ThemeProvider> // Toggle theme import { useTheme } from 'next-themes'; const { theme, setTheme } = useTheme(); <button onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}> Toggle </button>

Best Practices

1. Use cn() Utility

Combine Tailwind classes with proper merging:

import { cn } from '@/utils/cn'; <div className={cn( 'base-classes', conditional && 'conditional-classes', className // Allow override )}>

2. Avoid Arbitrary Values

// Avoid <div className="w-[123px] h-[45px]"> // Prefer (add to tailwind.config.ts if needed) <div className="w-32 h-12">
// Logical grouping <div className=" /* Layout */ flex items-center justify-between gap-4 /* Spacing */ p-4 m-2 /* Visual */ bg-white rounded-lg shadow-sm border /* Typography */ text-sm font-medium text-gray-900 ">

4. Use Component Primitives

// Instead of repeating classes const Card = ({ children, className }) => ( <div className={cn('rounded-lg border bg-card p-4', className)}> {children} </div> ); // Use consistently <Card className="hover:shadow-md">

5. Responsive Container

// Use container queries for component-level responsiveness <div className="@container"> <div className="flex flex-col @md:flex-row">

Styling Checklist

When adding new components:

  • Use Tailwind utilities (not inline styles)
  • Apply cn() for class merging
  • Support dark mode (use semantic colors)
  • Add responsive breakpoints
  • Test keyboard focus states
  • Verify reduced motion support
  • Check color contrast ratios

Last updated on