We use tracking cookies to understand how you use the product and help us improve it. For more information on how we store cookies, read our  privacy policy.

Overview

Learn about Plainform's UI system built with Tailwind CSS 4 and shadcn/ui components

Plainform uses a modern UI system combining Tailwind CSS 4 with shadcn/ui-inspired components built on Radix UI primitives. This approach provides a flexible, accessible, and customizable design system.

What's Included

Tailwind CSS 4

Tailwind CSS 4 is the latest version featuring:

  • Native CSS imports with @import 'tailwindcss'
  • CSS-first configuration using @theme directive
  • Improved performance and smaller bundle sizes
  • Enhanced dark mode support with custom variants

UI Components

Plainform includes 25+ pre-built components in components/ui/:

  • Form Elements: Button, Input, Label, InputOTP
  • Layout: Card, Separator, Sheet, ScrollArea
  • Overlays: Dialog, Popover, DropdownMenu
  • Navigation: Tabs, TableOfContents, BackButton
  • Feedback: Skeleton, ProgressBar, Avatar
  • Advanced: Accordion, BentoGrid, Marquee, AnimatedShinyText

All components are built with:

  • Radix UI primitives for accessibility
  • TypeScript for type safety
  • forwardRef for ref forwarding
  • Tailwind CSS for styling

Design System

The design system uses CSS variables for theming:

components/styles/globals.css
:root {
  --color-surface: #fafafa;
  --color-foreground: #171717;
  --color-brand: #4153ff;
  --color-neutral: #e7e6e6;
}

.dark {
  --color-surface: #171717;
  --color-foreground: #fafafa;
  --color-brand: #4153ff;
  --color-neutral: #262626;
}

Component Architecture

Base Pattern

UI components follow standard React patterns with TypeScript:

components/ui/Card.tsx
import * as React from 'react';
import { cn } from '@/lib/utils';

function Card({ className, ...props }: React.ComponentProps<'div'>) {
  return (
    <div
      className={cn(
        'bg-neutral/40 text-foreground flex flex-col gap-6 rounded-md border border-neutral py-6 shadow-sm',
        className
      )}
      {...props}
    />
  );
}

function CardHeader({ className, ...props }: React.ComponentProps<'div'>) {
  return (
    <div
      className={cn('grid auto-rows-min items-start gap-1.5 px-6', className)}
      {...props}
    />
  );
}

export { Card, CardHeader };

Key Features

  • Composition: Components can be composed together
  • Customization: Override styles via className prop
  • Accessibility: Built-in ARIA attributes and keyboard navigation
  • Type Safety: Full TypeScript support with proper types

Styling Utilities

cn() Helper

The cn() utility merges Tailwind classes intelligently:

lib/utils.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

Usage:

components/Example.tsx
<div className={cn(
  'base-classes',
  variant === 'primary' && 'bg-brand',
  className
)} />

Typography System

Global typography styles are defined in globals.css:

components/styles/globals.css
@layer base {
  h1 {
    @apply text-5xl font-bold leading-normal max-md:text-[36px] font-poppins;
  }
  h2 {
    @apply text-[2.5rem] font-semibold leading-normal max-md:text-[32px] font-poppins;
  }
  p {
    @apply text-base font-normal leading-normal max-md:text-[15px];
  }
}

Responsive Design

All components are mobile-first and responsive:

components/Example.tsx
<div className="w-full md:w-1/2 lg:w-1/3">
  <p className="text-sm md:text-base lg:text-lg">
    Responsive text
  </p>
</div>

Custom breakpoints:

components/Example.tsx
<div className="max-[1000px]:hidden">
  Desktop only content
</div>

Dark Mode

Dark mode is handled automatically using CSS variables:

components/Card.tsx
<div className="bg-card text-card-foreground border-border">
  <h2 className="text-foreground">Title</h2>
  <p className="text-muted-foreground">Description</p>
</div>

The theme provider handles mode switching:

components/providers/ThemeProvider.tsx
import { ThemeProvider } from 'next-themes';

<ThemeProvider attribute="class" defaultTheme="system">
  {children}
</ThemeProvider>

Next Steps

How is this guide ?

Last updated on