Claude Code for Million.js: React Performance Optimization — Claude Skills 360 Blog
Blog / Frontend / Claude Code for Million.js: React Performance Optimization
Frontend

Claude Code for Million.js: React Performance Optimization

Published: April 15, 2027
Read time: 6 min read
By: Claude Skills 360

Million.js replaces React’s virtual DOM diffing with a fine-grained block-based update system — block(Component) wraps a component so Million handles its DOM updates directly, bypassing React reconciliation for static-structure components. <For each={items}> renders lists 70% faster than items.map(item => <Component />). The million/compiler Vite or Babel plugin automatically converts compatible components to blocks at build time without manual wrapping. <Slot> marks dynamic positions inside blocks for React to manage. Million works as a drop-in addition to existing React apps — no rewrite required. Components with conditional rendering or dynamic structure fall back to React’s virtual DOM automatically. Million is most effective on data-heavy UIs: tables, dashboards, and large lists where the DOM structure is stable but data changes frequently. Claude Code identifies block candidates, adds million/compiler to build config, wraps high-frequency components with block(), and replaces array maps with For components.

CLAUDE.md for Million.js

## Million.js Stack
- Version: million >= 3.1
- Block: import { block } from "million/react"; const TableRow = block(TableRowComponent)
- For: import { For } from "million/react"; <For each={items}>{item => <Row item={item} />}</For>
- Compiler: add million/compiler to vite.config.ts — auto-optimizes compatible components
- Slot: import { Slot } from "million/react" — dynamic content inside blocks
- Rules: blocks can't use hooks that cause re-renders at the slot level; static structure required
- Profiles: Chrome DevTools > Performance > record interactions on large lists
- Fallback: non-block components work as-is — gradual adoption

Vite Plugin Setup

// vite.config.ts — Million.js compiler plugin
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import million from "million/compiler"

export default defineConfig({
  plugins: [
    // Million compiler BEFORE React plugin
    million.vite({
      auto: true,  // Automatically optimize compatible components
      mute: false, // Log optimized components
    }),
    react(),
  ],
})
// next.config.ts — Million.js for Next.js
import million from "million/compiler"
import type { NextConfig } from "next"

const nextConfig: NextConfig = {
  reactStrictMode: true,
}

export default million.next(nextConfig, {
  auto: { rsc: false },  // Skip React Server Components (already optimized)
})

Manual Block Components

// components/data/PriceRow.tsx — block for high-frequency price updates
import { block, For } from "million/react"

// Good block candidate: static structure, only data changes
interface PriceData {
  symbol: string
  price: number
  change: number
  changePercent: number
  volume: number
}

// Wrap the component — Million handles DOM updates
const PriceRowBlock = block(function PriceRow({ data }: { data: PriceData }) {
  const isPositive = data.change >= 0

  return (
    <tr className="border-b hover:bg-muted/50 text-sm">
      <td className="px-4 py-2 font-mono font-semibold">{data.symbol}</td>
      <td className="px-4 py-2 tabular-nums">${data.price.toFixed(2)}</td>
      <td className={`px-4 py-2 tabular-nums ${isPositive ? "text-green-600" : "text-red-600"}`}>
        {isPositive ? "+" : ""}{data.change.toFixed(2)}
      </td>
      <td className={`px-4 py-2 tabular-nums ${isPositive ? "text-green-600" : "text-red-600"}`}>
        {isPositive ? "+" : ""}{data.changePercent.toFixed(2)}%
      </td>
      <td className="px-4 py-2 tabular-nums text-muted-foreground">
        {(data.volume / 1_000_000).toFixed(1)}M
      </td>
    </tr>
  )
})

// Table using For for fast list rendering
export function PriceTable({ prices }: { prices: PriceData[] }) {
  return (
    <table className="w-full">
      <thead>
        <tr className="text-left text-xs font-medium text-muted-foreground uppercase">
          <th className="px-4 py-2">Symbol</th>
          <th className="px-4 py-2">Price</th>
          <th className="px-4 py-2">Change</th>
          <th className="px-4 py-2">%</th>
          <th className="px-4 py-2">Volume</th>
        </tr>
      </thead>
      <tbody>
        {/* For is significantly faster than .map() for long lists */}
        <For each={prices}>
          {(price) => <PriceRowBlock data={price} key={price.symbol} />}
        </For>
      </tbody>
    </table>
  )
}

Blocks with Slot for Dynamic Content

// components/data/DataCard.tsx — block with Slot for dynamic children
import { block, Slot } from "million/react"

interface DataCardProps {
  title: string
  value: string
  change: number
  // Dynamic content via Slot — React manages this part
  icon?: React.ReactNode
  actions?: React.ReactNode
}

// Static layout as block — Slot marks React-managed regions
const DataCard = block(function DataCardInner({
  title,
  value,
  change,
  icon,
  actions,
}: DataCardProps) {
  return (
    <div className="rounded-xl border bg-card p-5">
      <div className="flex items-center justify-between mb-3">
        <span className="text-sm font-medium text-muted-foreground">{title}</span>
        {/* Slot wraps dynamic React content */}
        <Slot>{icon}</Slot>
      </div>

      <p className="text-2xl font-bold tabular-nums">{value}</p>

      <div className="flex items-center justify-between mt-2">
        <span className={`text-sm ${change >= 0 ? "text-green-600" : "text-red-600"}`}>
          {change >= 0 ? "↑" : "↓"} {Math.abs(change).toFixed(1)}%
        </span>
        <Slot>{actions}</Slot>
      </div>
    </div>
  )
})

// Dashboard reusing DataCard block
export function MetricsDashboard({ metrics }: { metrics: typeof mockMetrics }) {
  return (
    <div className="grid grid-cols-4 gap-4">
      <For each={metrics}>
        {(metric) => (
          <DataCard
            key={metric.id}
            title={metric.title}
            value={metric.value}
            change={metric.change}
            icon={<MetricIcon type={metric.type} />}
            actions={<TrendChart data={metric.trend} />}
          />
        )}
      </For>
    </div>
  )
}

function MetricIcon({ type }: { type: string }) {
  // Dynamic — handled by React, not affected by block
  const icons: Record<string, string> = {
    revenue: "💰", users: "👥", orders: "📦", conversion: "📈",
  }
  return <span className="text-lg">{icons[type] ?? "📊"}</span>
}

function TrendChart({ data }: { data: number[] }) {
  // Small sparkline — React renders this normally
  const max = Math.max(...data)
  const min = Math.min(...data)
  const range = max - min || 1

  return (
    <svg width="60" height="20" className="text-primary">
      <polyline
        fill="none"
        stroke="currentColor"
        strokeWidth="1.5"
        strokeLinecap="round"
        points={data.map((v, i) => `${(i / (data.length - 1)) * 60},${20 - ((v - min) / range) * 18}`).join(" ")}
      />
    </svg>
  )
}

const mockMetrics = [
  { id: "1", title: "Revenue", value: "$48,295", change: 12.5, type: "revenue", trend: [30, 45, 38, 52, 48, 65, 72] },
  { id: "2", title: "Users", value: "2,847", change: 8.1, type: "users", trend: [20, 28, 35, 30, 42, 45, 51] },
]

Auto Mode with Opt-Out

// With million/compiler auto: true, compatible components are optimized automatically.
// Use the "use no memo" directive to opt out specific components.

// components/ComplexAnimated.tsx — not suitable for Million (has dynamic structure)
"use no memo"  // Opts this component OUT of auto-optimization

import { useState } from "react"

export function AnimatedAccordion({ items }: { items: { title: string; content: string }[] }) {
  const [open, setOpen] = useState<string | null>(null)

  // Dynamic structure (conditional children) — NOT a good block candidate
  return (
    <div className="space-y-2">
      {items.map(item => (
        <div key={item.title} className="border rounded-lg">
          <button
            onClick={() => setOpen(open === item.title ? null : item.title)}
            className="w-full flex justify-between items-center px-4 py-3 text-left"
          >
            {item.title}
            <span className={`transition-transform ${open === item.title ? "rotate-180" : ""}`}>▼</span>
          </button>
          {open === item.title && (
            <div className="px-4 pb-3 text-sm text-muted-foreground">
              {item.content}
            </div>
          )}
        </div>
      ))}
    </div>
  )
}

For the React Compiler (Babel) alternative when automatic memoization via the official React Compiler (babel-plugin-react-compiler) is preferred — React Compiler from the React team automatically adds useMemo and useCallback without any component wrapping, working on a broader range of component patterns than Million’s block approach, see the React Compiler guide. For the virtualization alternative when the performance bottleneck is rendering thousands of rows that are off-screen — @tanstack/react-virtual or react-window render only visible items, eliminating the need for block optimization for very large lists, see the virtual list guide. The Claude Skills 360 bundle includes Million.js skill sets covering block components, For lists, and compiler setup. Start with the free tier to try React performance optimization generation.

Keep Reading

Frontend

Claude Code for Chart.js Advanced: Custom Plugins and Mixed Charts

Advanced Chart.js patterns with Claude Code — chart.register() for tree-shaking, mixed chart types combining bar and line, custom plugin API with beforeDraw and afterDatasetsDraw hooks, ScriptableContext for computed colors, ChartDataLabels plugin for value labels, chartjs-plugin-zoom for pan and zoom, custom gradient fills via ctx.createLinearGradient, ChartJS annotation plugin for threshold lines, streaming data with chartjs-plugin-streaming, and react-chartjs-2 with useRef and chart instance.

6 min read Jun 27, 2027
Frontend

Claude Code for Nivo: Rich SVG and Canvas Charts

Build rich data visualizations with Nivo and Claude Code — ResponsiveLine and ResponsiveBar for adaptive charts, ResponsiveHeatMap for matrix data, ResponsiveTreeMap for hierarchal data, ResponsiveSunburst for nested proportions, ResponsiveChord for relationship diagrams, ResponsiveCalendar for activity heat maps, ResponsiveNetwork for force graphs, NivoTheme for consistent styling, tooltip customization with sliceTooltip, and motion config for spring animations.

6 min read Jun 26, 2027
Frontend

Claude Code for Victory Charts: React Native and Web Charts

Build cross-platform charts with Victory and Claude Code — VictoryChart, VictoryLine, VictoryBar, and VictoryScatter for web and React Native, VictoryPie for donut charts, VictoryArea for stacked areas, VictoryAxis for custom axes, VictoryTooltip and VictoryVoronoiContainer for hover tooltips, VictoryBrushContainer for range selection, VictoryZoomContainer for pan and zoom, VictoryLegend for series labels, custom theme with VictoryTheme, and VictoryStack for grouped bars.

6 min read Jun 25, 2027

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free