Frontend Components

by TheKeithStewart

artcodedata

This skill should be used when creating or modifying frontend dashboard components in the ClaudeCode Sentiment Monitor project. Specifically trigger this skill for tasks involving React 19 components, Next.js 15 App Router pages, shadcn/ui components, Recharts visualizations, SWR data fetching, or Tailwind CSS styling.

Skill Details

Repository Files

3 files in this skill directory


name: frontend-components description: This skill should be used when creating or modifying frontend dashboard components in the ClaudeCode Sentiment Monitor project. Specifically trigger this skill for tasks involving React 19 components, Next.js 15 App Router pages, shadcn/ui components, Recharts visualizations, SWR data fetching, or Tailwind CSS styling.

Frontend Components Development

Overview

Guide for developing dashboard components in the ClaudeCode Sentiment Monitor project using React 19, Next.js 15, shadcn/ui, Recharts, and Tailwind CSS.

When to Use This Skill

Use this skill when:

  • Creating new dashboard components
  • Modifying existing components
  • Adding charts or visualizations
  • Implementing data fetching with SWR
  • Styling components with Tailwind CSS
  • Working with shadcn/ui components
  • Adding modals or dialogs
  • Debugging frontend issues

Tech Stack

  • Framework: Next.js 15 (App Router), React 19, TypeScript 5
  • UI Library: shadcn/ui with Tailwind CSS 4
  • Charts: Recharts 3
  • Data Fetching: SWR 2.3.6 (30-second refresh intervals)
  • Working Directory: All component development in app/ directory

Quick Start

Component Template

Use the bundled template asset: assets/component-template.tsx

This provides the standard structure:

  1. "use client" directive
  2. State hooks
  3. SWR data fetching
  4. Loading state
  5. Error state
  6. Empty state
  7. Main render with Card layout

Copy and customize for new components.

Component Structure

"use client";

import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import useSWR from "swr";

const fetcher = (url: string) => fetch(url).then((res) => res.json());

interface ComponentNameProps {
  timeRange: "7d" | "30d" | "90d";
  subreddit: string;
}

export function ComponentName({ timeRange, subreddit }: ComponentNameProps) {
  // 1. Hooks first
  const { data, error, isLoading } = useSWR(
    `/api/endpoint?range=${timeRange}&subreddit=${subreddit}`,
    fetcher,
    { refreshInterval: 30000 }
  );

  // 2. Early returns for states
  if (isLoading) return <LoadingState />;
  if (error) return <ErrorState />;
  if (!data) return null;

  // 3. Render
  return (
    <Card>
      <CardHeader>
        <CardTitle>Title</CardTitle>
      </CardHeader>
      <CardContent>{/* Content */}</CardContent>
    </Card>
  );
}

Data Fetching with SWR

Standard pattern:

const { data, error, isLoading } = useSWR("/api/endpoint", fetcher, {
  refreshInterval: 30000, // 30-second refresh
  revalidateOnFocus: true,
});

Conditional fetching (dialogs/modals):

const { data, error, isLoading } = useSWR(
  isOpen ? `/api/endpoint?param=${value}` : null,
  fetcher
);

Type-safe fetching:

interface DataType {
  field: string;
}

const { data } = useSWR<DataType>("/api/endpoint", fetcher);

See references/component-patterns.md for more SWR patterns.

Charts with Recharts

Line Chart (Sentiment)

import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer, ReferenceLine } from "recharts";
import { format } from "date-fns";

<ResponsiveContainer width="100%" height={300}>
  <LineChart data={data} onClick={(e) => e && onDateClick(e.activeLabel)}>
    <CartesianGrid strokeDasharray="3 3" />
    <XAxis
      dataKey="date"
      tickFormatter={(date) => format(new Date(date), "MMM d")}
    />
    <YAxis domain={[-1, 1]} />
    <Tooltip content={<CustomTooltip />} />
    <ReferenceLine y={0} stroke="#888" strokeDasharray="3 3" />
    <Line
      type="monotone"
      dataKey="sentiment"
      stroke="hsl(var(--primary))"
      strokeWidth={2}
      dot={{ r: 4 }}
    />
  </LineChart>
</ResponsiveContainer>

Bar Chart (Volume)

import { BarChart, Bar, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer } from "recharts";

<ResponsiveContainer width="100%" height={300}>
  <BarChart data={data}>
    <CartesianGrid strokeDasharray="3 3" />
    <XAxis dataKey="date" tickFormatter={(date) => format(new Date(date), "MMM d")} />
    <YAxis />
    <Tooltip content={<CustomTooltip />} />
    <Bar dataKey="totalCount" fill="hsl(var(--primary))" radius={[4, 4, 0, 0]} />
  </BarChart>
</ResponsiveContainer>

Chart best practices:

  • Always wrap in <ResponsiveContainer>
  • Use Tailwind CSS variables for colors: hsl(var(--primary))
  • Format dates with date-fns
  • Create custom tooltip components
  • Use onClick for drill-down functionality

See references/component-patterns.md for more chart patterns.

Sentiment Colors

Standard color scheme (used across all components):

  • Positive (> 0.2): text-emerald-600 bg-emerald-50
  • Negative (< -0.2): text-rose-600 bg-rose-50
  • Neutral (-0.2 to 0.2): text-slate-600 bg-slate-50

Sentiment Badge Component:

function getSentimentColor(sentiment: number): string {
  if (sentiment > 0.2) return "text-emerald-600 bg-emerald-50";
  if (sentiment < -0.2) return "text-rose-600 bg-rose-50";
  return "text-slate-600 bg-slate-50";
}

function SentimentBadge({ sentiment }: { sentiment: number }) {
  const colorClass = getSentimentColor(sentiment);
  return (
    <span className={`px-2 py-1 rounded-full text-xs font-medium ${colorClass}`}>
      {sentiment > 0 ? "+" : ""}{sentiment.toFixed(2)}
    </span>
  );
}

Dialogs and Modals

Use shadcn/ui Dialog with conditional SWR fetching:

import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";

<Dialog open={open} onOpenChange={onOpenChange}>
  <DialogContent className="max-w-4xl max-h-[80vh] overflow-y-auto">
    <DialogHeader>
      <DialogTitle>Title</DialogTitle>
    </DialogHeader>
    {isLoading && <p>Loading...</p>}
    {error && <p className="text-destructive">Error</p>}
    {data && <div className="space-y-4">{/* Content */}</div>}
  </DialogContent>
</Dialog>

Best practices:

  • Use conditional fetching (only fetch when open)
  • Add max-h-[80vh] overflow-y-auto for scrollable content
  • Handle loading/error states within dialog

State Management

DashboardShell pattern (centralized state):

export function DashboardShell() {
  const [timeRange, setTimeRange] = useState<"7d" | "30d" | "90d">("7d");
  const [subreddit, setSubreddit] = useState<string>("all");
  const [drillDownDate, setDrillDownDate] = useState<string | null>(null);

  return (
    <div>
      <SentimentChart
        timeRange={timeRange}
        subreddit={subreddit}
        onDateClick={setDrillDownDate}
      />
      <DrillDownDialog
        open={!!drillDownDate}
        onOpenChange={(open) => !open && setDrillDownDate(null)}
        date={drillDownDate}
        subreddit={subreddit}
      />
    </div>
  );
}

Rules:

  • Keep state in nearest common ancestor (DashboardShell)
  • Pass state down as props (no context for small apps)
  • Use callback props for child-to-parent communication
  • Avoid prop drilling beyond 2-3 levels

Styling with Tailwind CSS

Common patterns:

// Spacing
className="space-y-4"               // Vertical spacing
className="flex gap-4"               // Horizontal spacing
className="grid grid-cols-2 gap-4"  // Grid layout

// Containers
className="max-w-4xl mx-auto"          // Centered
className="max-h-[80vh] overflow-y-auto"  // Scrollable

// Typography
className="text-sm text-muted-foreground"  // Secondary text
className="text-lg font-semibold"          // Heading

Best practices:

  • Use shadcn/ui CSS variables: hsl(var(--primary)), text-muted-foreground
  • Prefer space-y-* and gap-* over margins
  • Use responsive classes: md:grid-cols-2 lg:grid-cols-3

TypeScript Best Practices

Always use explicit types:

// Component props
interface ChartProps {
  timeRange: "7d" | "30d" | "90d";
  subreddit: "all" | "ClaudeAI" | "ClaudeCode" | "Anthropic";
  onDateClick: (date: string) => void;
}

// API responses
interface DashboardData {
  dates: string[];
  sentiment: number[];
}

// Type SWR responses
const { data } = useSWR<DashboardData>("/api/endpoint", fetcher);

Common UI Patterns

CSV Export Button:

import { Button } from "@/components/ui/button";
import { Download } from "lucide-react";

<Button onClick={() => window.open(`/api/export/csv?range=${timeRange}`, "_blank")} variant="outline" size="sm">
  <Download className="mr-2 h-4 w-4" />
  Export CSV
</Button>

Loading Skeleton:

import { Skeleton } from "@/components/ui/skeleton";

if (isLoading) {
  return (
    <Card>
      <CardHeader>
        <Skeleton className="h-6 w-32" />
      </CardHeader>
      <CardContent>
        <Skeleton className="h-[300px] w-full" />
      </CardContent>
    </Card>
  );
}

Error Alert:

import { AlertCircle } from "lucide-react";
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";

if (error) {
  return (
    <Alert variant="destructive">
      <AlertCircle className="h-4 w-4" />
      <AlertTitle>Error</AlertTitle>
      <AlertDescription>Failed to load data. Please try again.</AlertDescription>
    </Alert>
  );
}

Testing Components

cd app
npm run dev  # Start dev server on http://localhost:3000

# In browser DevTools:
# - Check Network tab for API calls
# - Verify SWR caching behavior
# - Test responsive design
# - Check for console errors

Component Checklist

When creating/modifying a component:

  • Explicit TypeScript interface for props
  • SWR used for data fetching (not useEffect + fetch)
  • Loading, error, and empty states handled
  • Sentiment colors follow standard scheme
  • Charts use ResponsiveContainer and custom tooltips
  • Dates formatted with date-fns
  • Tailwind classes use shadcn/ui CSS variables
  • Exported as named export (not default)
  • "use client" directive if using hooks

Common Pitfalls

Avoid these mistakes:

  1. useEffect for data fetching - Use SWR instead
  2. Hardcoded colors - Use Tailwind CSS variables
  3. Missing loading states - Users need feedback
  4. Mutating props - Components should be pure
  5. Skipping TypeScript types - Explicit types prevent errors
  6. Deep nesting - Extract to separate files if > 100 lines
  7. Inline styles - Use Tailwind classes exclusively

Resources

Examples

See existing implementations in app/components/dashboard/:

  • DashboardShell.tsx - State management and layout
  • SentimentChart.tsx - Line chart with drill-down
  • VolumeChart.tsx - Bar chart with custom tooltips
  • DrillDownDialog.tsx - Modal with conditional fetching

Related Skills

Xlsx

Comprehensive spreadsheet creation, editing, and analysis with support for formulas, formatting, data analysis, and visualization. When Claude needs to work with spreadsheets (.xlsx, .xlsm, .csv, .tsv, etc) for: (1) Creating new spreadsheets with formulas and formatting, (2) Reading or analyzing data, (3) Modify existing spreadsheets while preserving formulas, (4) Data analysis and visualization in spreadsheets, or (5) Recalculating formulas

data

Clickhouse Io

ClickHouse database patterns, query optimization, analytics, and data engineering best practices for high-performance analytical workloads.

datacli

Clickhouse Io

ClickHouse database patterns, query optimization, analytics, and data engineering best practices for high-performance analytical workloads.

datacli

Analyzing Financial Statements

This skill calculates key financial ratios and metrics from financial statement data for investment analysis

data

Data Storytelling

Transform data into compelling narratives using visualization, context, and persuasive structure. Use when presenting analytics to stakeholders, creating data reports, or building executive presentations.

data

Team Composition Analysis

This skill should be used when the user asks to "plan team structure", "determine hiring needs", "design org chart", "calculate compensation", "plan equity allocation", or requests organizational design and headcount planning for a startup.

artdesign

Startup Financial Modeling

This skill should be used when the user asks to "create financial projections", "build a financial model", "forecast revenue", "calculate burn rate", "estimate runway", "model cash flow", or requests 3-5 year financial planning for a startup.

art

Kpi Dashboard Design

Design effective KPI dashboards with metrics selection, visualization best practices, and real-time monitoring patterns. Use when building business dashboards, selecting metrics, or designing data visualization layouts.

designdata

Dbt Transformation Patterns

Master dbt (data build tool) for analytics engineering with model organization, testing, documentation, and incremental strategies. Use when building data transformations, creating data models, or implementing analytics engineering best practices.

testingdocumenttool

Startup Metrics Framework

This skill should be used when the user asks about "key startup metrics", "SaaS metrics", "CAC and LTV", "unit economics", "burn multiple", "rule of 40", "marketplace metrics", or requests guidance on tracking and optimizing business performance metrics.

art

Skill Information

Category:Creative
Last Updated:11/2/2025