Skip to content

UI Kit and Components

overthelex edited this page May 17, 2026 · 2 revisions

UI Kit & Components

The UI Kit & Components system within the SecondLayer frontend (lexwebapp/) is a structured, reusable design system built on TailwindCSS with a variants-and-sizes pattern. It provides accessible, type-safe components that ensure visual consistency across the legal tech platform, supporting features such as legal document analysis, court case searching, and real-time AI chat interactions.

The architecture uses centralized design tokens defined in the Tailwind configuration, a component-level styles/types separation pattern, and Framer Motion for animations. All components are TypeScript-first with exported prop interfaces.

Design Tokens (Tailwind Configuration)

Design tokens are defined in lexwebapp/tailwind.config.js rather than a separate tokens file. The Tailwind config extends the default theme with project-specific values.

Color Palette

The project uses a custom claude namespace for its core color system, based on the Zinc scale:

Token Value Usage
claude.bg #FAFAFA Page background
claude.sidebar #F4F4F5 Sidebar background (Zinc-100)
claude.accent #18181B Primary CTA, focus rings (Zinc-900)
claude.text #18181B Body text (Zinc-900)
claude.subtext #71717A Secondary text (Zinc-500)
claude.border #E4E4E7 Borders, dividers (Zinc-200)
claude.user #F1F1F4 User message bubble background

Typography

Token Value
fontFamily.serif "Crimson Pro", serif
fontFamily.sans Inter, sans-serif

Prose (long-form text) styling uses the @tailwindcss/typography plugin with custom CSS variable overrides matching the Zinc color system.

Elevation (Box Shadows)

Token Description
elevation-0 None
elevation-1 Subtle (cards, inputs)
elevation-2 Medium (dropdowns, popovers)
elevation-3 Prominent (modals, overlays)
input-focus Input focus ring (rgba(24,24,27,0.08))

Animation

Token Effect
fade-in 0.3s ease-out translateY(10px) to 0

Component Architecture

The UI library is located at lexwebapp/src/components/ui/. Each component follows a consistent file structure:

ComponentName/
  index.ts           # Re-exports
  ComponentName.tsx  # Implementation
  ComponentName.types.ts  # TypeScript interfaces
  ComponentName.styles.ts # Style utility functions

All components are exported from lexwebapp/src/components/ui/index.ts organized by category:

graph TD
    TW[Tailwind Config] --> UI[UI Component Library]
    UI --> Basic[Basic Components]
    UI --> Layout[Layout Components]
    UI --> Form[Form Components]
    UI --> Nav[Navigation Components]
    UI --> Feed[Feedback Components]
    Basic --> Button
    Basic --> Input
    Basic --> Card
    Layout --> Modal
    Layout --> Badge
    Layout --> ConfirmModal
    Form --> Checkbox
    Form --> Switch
    Nav --> Tabs
    Feed --> Spinner
Loading

Base UI Components

Button

Supports variant-and-size composition with loading states and icon slots.

Prop Type Default
variant 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' 'primary'
size 'sm' | 'md' | 'lg' 'md'
isLoading boolean false
fullWidth boolean false
leftIcon ReactNode --
rightIcon ReactNode --

Style composition: base classes (flex, rounded-lg, transition, focus ring) + variant classes + size classes, combined via the getButtonClasses() utility.

Input

Three-variant input with label, error, helper text, and icon support.

Prop Type Default
variant 'default' | 'filled' | 'flushed' 'default'
size 'sm' | 'md' | 'lg' 'md'
label string --
error string --
helperText string --
leftIcon / rightIcon ReactNode --
fullWidth boolean false

Card

Composition-based card using Card, CardHeader, CardBody, CardFooter sub-components.

Prop Type Default
variant 'default' | 'outlined' | 'elevated' 'default'
hoverable boolean false

Modal

Animated modal with Framer Motion, Escape key close, backdrop click, and scroll lock.

Prop Type Default
size 'sm' | 'md' | 'lg' | 'xl' | 'full' 'md'
isOpen boolean --
onClose () => void --
title string --
showCloseButton boolean true
closeOnBackdrop boolean true

ConfirmModal

A specialized confirmation dialog built on Framer Motion with optional text input. Supports 'default' and 'danger' variants. Used for destructive action confirmations throughout the app.

Badge

Semantic status indicators with dot support.

Prop Type Default
variant 'default' | 'success' | 'error' | 'warning' | 'info' 'default'
size 'sm' | 'md' | 'lg' 'md'
dot boolean false

Checkbox

Accessible checkbox with custom styling using peer selectors. Supports label and error props. Uses claude-accent for the checked state.

Switch

Toggle switch with three sizes (sm, md, lg). Uses peer-based CSS transitions for the sliding thumb animation. Supports label prop.

Tabs

Compound component pattern using React Context: Tabs, TabList, Tab, TabPanel. Features:

  • Controlled and uncontrolled modes (value/onChange or defaultTab)
  • Animated active indicator via Framer Motion layoutId
  • Icon and badge support on individual tabs
  • Animated panel transitions

Spinner

Loading indicator using the Lucide Loader icon with CSS spin animation.

Prop Type Default
size 'sm' | 'md' | 'lg' | 'xl' 'md'
color 'primary' | 'white' | 'gray' 'primary'

Specialized Legal Components

Beyond the base UI kit, the project implements domain-specific components for AI-driven legal analysis. These live at lexwebapp/src/components/ (top level, not inside ui/).

Message System

The message system is split into a message/ module:

  • Message (index.tsx) -- top-level component rendering user/assistant messages with rich metadata (decisions, analytics, citations, documents, thinking steps, execution plans, cost summaries)
  • UserMessage -- user query bubble with edit capability
  • AssistantMessage -- assistant response with Markdown rendering and embedded structured data
  • MarkdownContent -- Markdown formatter with legal code highlighting

MessageThread

Manages the scrolling message list with auto-scroll behavior (pauses when user scrolls up) and integrates the SelectionToolbar for text selection actions.

ThinkingSteps

An expandable component that displays the AI's reasoning chain progressively. Shows step titles with completion indicators and expandable content sections. Animates with Framer Motion.

DecisionCard

Displays court decisions with:

  • Case number, court name, date
  • Summary text and relevance percentage
  • Status badge (active, overturned, modified)
  • Document type indicator and external link

AnalyticsBlock

Renders statistical case outcome data:

  • Total cases with satisfied/rejected/partial breakdown (percentages)
  • Trend indicator (up/down/stable)
  • AI interpretation text

CostSummary

Displays API cost tracking information for the current request.

PlanDisplay / PlanReviewDisplay

Renders execution plans showing which tools the AI intends to use, for user review before execution.

Component Domain Modules

The frontend organizes feature-specific components into sub-directories:

Module Location Purpose
chat/ Chat-specific UI (tool selector, file attachments, prompt manager, tabs for decisions/documents/regulations)
message/ Message rendering pipeline
right-panel/ Evidence and results panel (search results, documents render here)
sidebar/ Navigation sidebar
billing/ Subscription and payment UI
consultation/ Legal consultation interface
legislation/ Legislation viewer components
contracts/ Contract management UI
admin/ Admin panel components
onboarding/ User onboarding flow
charts/ Data visualization components
video-call/ Video consultation UI

Accessibility

All base UI components implement accessibility features:

  • Keyboard Navigation: Tab navigation, Enter/Space activation, Escape for modals
  • Focus Management: Visible focus rings (focus:ring-2 focus:ring-offset-2), scroll lock on modal open
  • Screen Reader Support: aria-label on close buttons, semantic HTML (label/input pairing via htmlFor)
  • Peer Selectors: Checkbox and Switch use peer sr-only pattern for custom styling while maintaining native input accessibility

Usage Example

import { Card, CardBody, Input, Button, Badge, Tabs, TabList, Tab, TabPanel } from '../components/ui';

function SearchForm() {
  return (
    <Card variant="elevated">
      <CardBody className="space-y-4">
        <Input
          label="Search court decisions"
          variant="default"
          leftIcon={<SearchIcon />}
          fullWidth
        />
        <div className="flex gap-2">
          <Badge variant="info">Civil</Badge>
          <Badge variant="warning">Criminal</Badge>
        </div>
        <Button variant="primary" fullWidth>
          Search
        </Button>
      </CardBody>
    </Card>
  );
}

Clone this wiki locally