Advanced (Diperbarui: 22/7/2026)

Membangun Design System dengan Claude Code: Design Tokens, Storybook, dan CI

Panduan praktis memakai Claude Code untuk design tokens, komponen React, Storybook, aksesibilitas, visual test, dan CI.

Membangun Design System dengan Claude Code: Design Tokens, Storybook, dan CI

Ketika satu Button tampil berbeda di setiap layar

Masalah design system biasanya terasa saat perubahan yang tampak kecil berubah menjadi pekerjaan besar. Desainer mengganti warna tombol utama, tetapi dashboard, halaman tagihan, dan web mobile memakai tiga nilai hex yang berbeda. Focus ring hilang di satu layar, loading state masih dapat diklik dua kali di layar lain, sedangkan story di Storybook sudah tertinggal dari kode produksi.

Design system dibuat untuk mencegah kondisi itu. Ia bukan sekadar galeri komponen yang rapi, melainkan cara kerja bersama untuk mengubah warna, jarak, tipografi, state komponen, proses review, dan pengujian tanpa merusak layar produk. Claude Code dapat membaca repository, mengubah sejumlah file yang dibatasi, menjalankan Storybook serta test, lalu menjelaskan diff. Namun keputusan brand, public API, pengalaman pengguna, dan review aksesibilitas terakhir tetap menjadi tanggung jawab manusia.

Panduan ini menyusun alur dari tokens.json, komponen React/TypeScript, Storybook, pemeriksaan aksesibilitas dan visual di CI, sampai batas aman integrasi Figma. Bacaan terkait tersedia di pengelolaan design token dengan Claude Code, pengembangan Storybook, dan pekerjaan aksesibilitas dengan Claude Code.

Poin utama sebelum mulai

  • Jadikan tokens.json kontrak yang dapat dibaca reviewer dan divalidasi oleh CI.
  • Beri Claude Code satu komponen, batas file, dan kriteria penerimaan yang jelas; jangan meminta seluruh library ditulis ulang sekaligus.
  • Untuk Storybook berbasis Vite pada 2026, gunakan @storybook/addon-vitest dan vitest --project=storybook sebagai jalur utama.
  • Automated a11y dan visual test membantu menemukan regresi, tetapi tidak menggantikan review keyboard dan screen reader oleh manusia.
  • Mulai integrasi Figma dari laporan perbedaan, bukan sinkronisasi dua arah yang langsung menimpa token produksi.

Langkah awal yang aman adalah memilih satu komponen penting, misalnya Button. Selesaikan token, props, state Storybook, pemeriksaan aksesibilitas, dan visual test untuk komponen itu sebelum pindah ke komponen berikutnya. Diff tetap kecil dan penyebab kegagalan lebih mudah ditemukan.

Arsitektur target

Dalam alur ini, sumber kebenaran di sisi kode adalah tokens.json. Figma tetap penting untuk eksplorasi dan review desain, tetapi perubahan yang masuk ke produk harus berupa kontrak yang dapat diperiksa di pull request dan diuji di CI.

flowchart LR
  Figma["Figma Variables"]
  Tokens["tokens.json"]
  Build["token build script"]
  CSS["CSS variables"]
  TS["TypeScript token map"]
  Components["React components"]
  Storybook["Storybook stories"]
  CI["Visual and a11y CI"]

  Figma -->|review input| Tokens
  Tokens --> Build
  Build --> CSS
  Build --> TS
  CSS --> Components
  TS --> Components
  Components --> Storybook
  Storybook --> CI

Design token adalah keputusan desain yang diberi nama dan disimpan sebagai data, misalnya warna, spacing, radius, tipografi, serta state komponen. Komponen sebaiknya tidak bergantung langsung pada nilai mentah seperti #2563eb. Token semantik seperti action.background.primary menjelaskan tujuan nilai tersebut, sehingga raw value dapat berubah tanpa mengubah makna di setiap komponen.

Gunakan sumber resmi yang masih berlaku: format Design Tokens Community Group, dokumentasi Claude Code, panduan keamanan Claude Code, Storybook Vitest addon, pengujian aksesibilitas Storybook, visual testing Storybook, dan Figma REST API.

Batas kerja Claude Code dan keputusan manusia

Prompt seperti “buatkan design system” terlalu luas. Hasilnya dapat mengubah banyak file, merusak public API, dan menghasilkan diff yang sulit direview. Instruksi “migrasikan hanya Button, pertahankan public API, tambahkan semua state di Storybook, lalu jalankan a11y test” jauh lebih aman karena ruang kerja dan bukti selesai terlihat jelas.

Area kerjaTugas yang tepat untuk Claude CodeKeputusan manusia
TokensMenginventarisasi warna dan spacing berulang dari CSSMakna brand dan penamaan token
ComponentsMengimplementasikan primitive Button, Input, dan Alert yang typedPublic API dan semantik produk
StorybookMenambahkan variant, state, dan interaction storyState yang penting dalam alur pengguna nyata
AccessibilityMenemukan label yang hilang, masalah focus, dan pelanggaran axePenilaian akhir keyboard, screen reader, dan UX
CIMenambahkan visual dan a11y checks pada pull requestKebijakan failure dan proses pengecualian

Berikan aturan proyek singkat sebelum Claude Code mengedit:

Aturan tugas design system:
- Edit hanya src/components, src/styles, .storybook, tests, scripts, dan tokens.json.
- Jangan ubah warna brand tanpa mencantumkan nama token lama dan baru.
- Setiap komponen baru harus memiliki TypeScript props, perilaku keyboard, Storybook stories, dan catatan a11y.
- Sebelum menyatakan selesai, jalankan npm run tokens:build, npm run test:storybook -- --run, npm run build-storybook, dan npm run test:visual.
- Jika perilaku focus berubah, sertakan langkah review manual.

Claude Code menangani inventarisasi berulang, implementasi terbatas, eksekusi command, dan ringkasan diff. Reviewer manusia memeriksa penamaan token, kompatibilitas API, visual diff, keyboard flow, serta arti brand. Jangan masukkan token Figma, token npm, secret CI, atau screenshot pelanggan pribadi ke prompt. Baca command sebelum memberikan izin dan jangan menerima pembaruan snapshot besar tanpa review visual.

Setup minimal Storybook pada 2026

Contoh ini mengasumsikan aplikasi React dan TypeScript. Sesuaikan sintaks dengan package manager proyek, tetapi pertahankan fungsi setiap dependency dan script.

npm install class-variance-authority clsx tailwind-merge
npx storybook@latest init
npx storybook add @storybook/addon-a11y
npx storybook add @storybook/addon-vitest
npm install -D @playwright/test concurrently http-server wait-on
npx playwright install chromium

Untuk framework Storybook berbasis Vite atau integrasi Next.js Vite yang didukung, jalur yang direkomendasikan saat ini adalah @storybook/addon-vitest. Jika proyek tidak dapat memakai integrasi tersebut, @storybook/test-runner lama boleh digunakan hanya sebagai fallback atau jembatan migrasi sesuai dokumentasi resmi. Jangan menjadikannya setup utama untuk proyek baru.

Tambahkan scripts yang sama untuk lingkungan lokal dan CI:

{
  "scripts": {
    "tokens:build": "node scripts/build-tokens.mjs",
    "storybook": "storybook dev -p 6006",
    "build-storybook": "storybook build",
    "test:storybook": "vitest --project=storybook",
    "test:visual": "playwright test tests/button.visual.spec.ts"
  }
}

Command npm run test:storybook -- --run menjalankan test sekali di CI lalu berhenti. Vitest addon mengubah stories menjadi browser tests, sehingga component dan a11y test tidak memerlukan Storybook server terpisah. Built Storybook server di bagian CI nanti dipertahankan hanya untuk screenshot Playwright khusus.

Jadikan Design Tokens sebagai kontrak

Pisahkan token menjadi layer primitive, semantic, dan component. Primitive menyimpan raw value, semantic menjelaskan fungsi, sedangkan component mengikat fungsi itu pada state UI tertentu. Struktur ini mencegah perubahan brand berubah menjadi pencarian dan penggantian nilai di seluruh codebase.

{
  "$schema": "https://www.designtokens.org/schemas/2025.10/format.json",
  "primitive": {
    "color": {
      "blue": {
        "50": {
          "$type": "color",
          "$value": { "colorSpace": "srgb", "components": [0.9373, 0.9647, 1], "hex": "#eff6ff" }
        },
        "600": {
          "$type": "color",
          "$value": { "colorSpace": "srgb", "components": [0.1451, 0.3882, 0.9216], "hex": "#2563eb" }
        },
        "700": {
          "$type": "color",
          "$value": { "colorSpace": "srgb", "components": [0.1137, 0.3059, 0.8471], "hex": "#1d4ed8" }
        }
      },
      "gray": {
        "50": {
          "$type": "color",
          "$value": { "colorSpace": "srgb", "components": [0.9765, 0.9804, 0.9843], "hex": "#f9fafb" }
        },
        "200": {
          "$type": "color",
          "$value": { "colorSpace": "srgb", "components": [0.898, 0.9059, 0.9216], "hex": "#e5e7eb" }
        },
        "900": {
          "$type": "color",
          "$value": { "colorSpace": "srgb", "components": [0.0667, 0.0941, 0.1529], "hex": "#111827" }
        }
      },
      "red": {
        "600": {
          "$type": "color",
          "$value": { "colorSpace": "srgb", "components": [0.8627, 0.149, 0.149], "hex": "#dc2626" }
        },
        "700": {
          "$type": "color",
          "$value": { "colorSpace": "srgb", "components": [0.7255, 0.1098, 0.1098], "hex": "#b91c1c" }
        }
      },
      "white": {
        "$type": "color",
        "$value": { "colorSpace": "srgb", "components": [1, 1, 1], "hex": "#ffffff" }
      }
    },
    "space": {
      "2": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } },
      "3": { "$type": "dimension", "$value": { "value": 0.75, "unit": "rem" } },
      "4": { "$type": "dimension", "$value": { "value": 1, "unit": "rem" } },
      "6": { "$type": "dimension", "$value": { "value": 1.5, "unit": "rem" } }
    },
    "radius": {
      "md": { "$type": "dimension", "$value": { "value": 0.375, "unit": "rem" } },
      "lg": { "$type": "dimension", "$value": { "value": 0.5, "unit": "rem" } }
    }
  },
  "semantic": {
    "color": {
      "surface": { "$type": "color", "$value": "{primitive.color.white}" },
      "text": { "$type": "color", "$value": "{primitive.color.gray.900}" },
      "border": { "$type": "color", "$value": "{primitive.color.gray.200}" },
      "focus": { "$type": "color", "$value": "{primitive.color.blue.600}" }
    }
  },
  "component": {
    "button": {
      "primary": {
        "background": { "$type": "color", "$value": "{primitive.color.blue.600}" },
        "backgroundHover": { "$type": "color", "$value": "{primitive.color.blue.700}" },
        "text": { "$type": "color", "$value": "{primitive.color.white}" }
      },
      "danger": {
        "background": { "$type": "color", "$value": "{primitive.color.red.600}" },
        "backgroundHover": { "$type": "color", "$value": "{primitive.color.red.700}" },
        "text": { "$type": "color", "$value": "{primitive.color.white}" }
      }
    }
  }
}

Bangkitkan CSS custom properties dan TypeScript token map dari file itu:

import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname } from "node:path";

const source = JSON.parse(readFileSync("tokens.json", "utf8"));

function getToken(path) {
  const node = path.split(".").reduce((current, key) => current?.[key], source);
  if (!node || typeof node.$value === "undefined") {
    throw new Error(`Unknown token reference: ${path}`);
  }
  return node.$value;
}

function resolveValue(value, stack = []) {
  if (typeof value === "string" && value.startsWith("{") && value.endsWith("}")) {
    const path = value.slice(1, -1);
    if (stack.includes(path)) {
      throw new Error(`Circular token reference: ${[...stack, path].join(" -> ")}`);
    }
    return resolveValue(getToken(path), [...stack, path]);
  }
  return value;
}

function toCssValue(value) {
  if (value && typeof value === "object") {
    if (typeof value.hex === "string") return value.hex;
    if (typeof value.value === "number" && typeof value.unit === "string") {
      return `${value.value}${value.unit}`;
    }
    throw new Error(`Unsupported token value: ${JSON.stringify(value)}`);
  }
  return String(value);
}

function walk(node, pathParts = [], result = {}) {
  if (!node || typeof node !== "object") return result;

  if (node && typeof node === "object" && typeof node.$value !== "undefined") {
    result[pathParts.join("-")] = toCssValue(resolveValue(node.$value));
    return result;
  }

  for (const [key, value] of Object.entries(node)) {
    if (key.startsWith("$")) continue;
    walk(value, [...pathParts, key], result);
  }

  return result;
}

const flat = walk(source);
const css = [
  ":root {",
  ...Object.entries(flat).map(([name, value]) => `  --${name}: ${value};`),
  "}",
  ""
].join("\n");

mkdirSync(dirname("src/styles/tokens.css"), { recursive: true });
mkdirSync(dirname("src/tokens.ts"), { recursive: true });
writeFileSync("src/styles/tokens.css", css);
writeFileSync("src/tokens.ts", `export const tokens = ${JSON.stringify(flat, null, 2)} as const;\n`);

console.log(`Generated ${Object.keys(flat).length} tokens.`);

Jangan langsung meminta Claude Code mengganti seluruh UI. Minta dahulu daftar raw color dan spacing yang berulang, usulan pemetaan token, serta file yang terdampak. Setelah manusia menyetujui arti token, migrasikan satu komponen. Cara ini mencegah nama semantik yang keliru menyebar ke banyak file.

Membangun komponen React yang typed

Layer komponen sebaiknya membosankan dalam arti positif: perilakunya mudah ditebak dan API-nya stabil. Button berikut mempunyai variant, size, loading state, disabled behavior, dan focus ring yang terlihat. Review tidak berhenti pada tampilan; periksa juga ref, native button semantics, dan pencegahan submit ganda saat loading.

import { forwardRef, type ButtonHTMLAttributes } from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

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

const buttonVariants = cva(
  [
    "inline-flex items-center justify-center gap-2 rounded-md font-medium",
    "transition-colors focus-visible:outline-none focus-visible:ring-2",
    "focus-visible:ring-[var(--semantic-color-focus)] focus-visible:ring-offset-2",
    "disabled:pointer-events-none disabled:opacity-50"
  ],
  {
    variants: {
      variant: {
        primary: [
          "bg-[var(--component-button-primary-background)]",
          "text-[var(--component-button-primary-text)]",
          "hover:bg-[var(--component-button-primary-backgroundHover)]"
        ],
        secondary: "border border-[var(--semantic-color-border)] bg-[var(--semantic-color-surface)] text-[var(--semantic-color-text)] hover:bg-gray-50",
        danger: [
          "bg-[var(--component-button-danger-background)]",
          "text-[var(--component-button-danger-text)]",
          "hover:bg-[var(--component-button-danger-backgroundHover)]"
        ]
      },
      size: {
        sm: "h-8 px-3 text-sm",
        md: "h-10 px-4 text-sm",
        lg: "h-12 px-6 text-base"
      }
    },
    defaultVariants: {
      variant: "primary",
      size: "md"
    }
  }
);

export interface ButtonProps
  extends ButtonHTMLAttributes<HTMLButtonElement>,
    VariantProps<typeof buttonVariants> {
  loading?: boolean;
}

export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button(
  { className, variant, size, loading = false, disabled, children, ...props },
  ref
) {
  return (
    <button
      ref={ref}
      className={cn(buttonVariants({ variant, size }), className)}
      disabled={disabled || loading}
      aria-busy={loading || undefined}
      {...props}
    >
      {loading ? (
        <span
          aria-hidden="true"
          className="h-4 w-4 animate-spin rounded-full border-2 border-current border-r-transparent"
        />
      ) : null}
      <span>{children}</span>
    </button>
  );
});

Pertanyaan review yang tepat bukan hanya “apakah tombol ini terlihat bagus?”, melainkan “apakah API ini cukup stabil untuk digunakan banyak tim produk?”. Periksa existing callers, default variant, loading behavior, keyboard focus, dan kondisi disabled sebelum menyetujui migrasi.

Menjadikan Storybook sebagai spesifikasi

Setiap state penting perlu memiliki story. Tanpa story, desainer sulit mereview state, developer tidak mempunyai story ID yang stabil untuk test, dan visual diff kehilangan konteks. Pertahankan stories yang sudah ada, tambahkan state yang hilang, dan jelaskan setiap perubahan story ID.

import type { Meta, StoryObj } from "@storybook/react-vite";
import { Button } from "./Button";

const meta = {
  title: "Design System/Button",
  component: Button,
  parameters: {
    layout: "centered",
    a11y: {
      test: "error"
    }
  },
  argTypes: {
    variant: {
      control: "select",
      options: ["primary", "secondary", "danger"]
    },
    size: {
      control: "select",
      options: ["sm", "md", "lg"]
    },
    loading: { control: "boolean" },
    disabled: { control: "boolean" }
  }
} satisfies Meta<typeof Button>;

export default meta;
type Story = StoryObj<typeof meta>;

export const Primary: Story = {
  args: {
    children: "Save changes",
    variant: "primary"
  }
};

export const Danger: Story = {
  args: {
    children: "Delete",
    variant: "danger"
  }
};

export const Loading: Story = {
  args: {
    children: "Saving",
    loading: true
  }
};

export const AllStates: Story = {
  render: () => (
    <div className="flex flex-wrap items-center gap-3">
      <Button variant="primary" size="sm">Small</Button>
      <Button variant="primary" size="md">Medium</Button>
      <Button variant="primary" size="lg">Large</Button>
      <Button variant="secondary">Secondary</Button>
      <Button variant="danger">Danger</Button>
      <Button disabled>Disabled</Button>
      <Button loading>Loading</Button>
    </div>
  )
};

Pengaturan parameters.a11y.test = "error" membuat pelanggaran dari accessibility addon menggagalkan component test. Itu memberi umpan balik dini di pull request, tetapi manusia tetap perlu menilai arti copy, urutan focus, keyboard flow, dan pemahaman screen reader.

Menjalankan component, a11y, dan visual checks di CI

Pada Storybook berbasis Vite, @storybook/addon-vitest mengubah stories menjadi browser tests. Jalankan npm run test:storybook -- --run di CI. Berbeda dari alur test-runner lama, component dan a11y test tidak memerlukan Storybook server terpisah. Server hasil build di bawah hanya dipakai untuk screenshot Playwright khusus.

Mulai visual test dari stories bernilai tinggi. Jika semua animasi, tanggal, external font, dan random ID langsung dijadikan snapshot, noise akan menutupi regresi yang penting. Bekukan data dinamis dan pilih state yang memang perlu disetujui manusia.

Sebelum mengaktifkan CI, jalankan npx playwright test tests/button.visual.spec.ts --update-snapshots satu kali di aplikasi target, tinjau baseline image secara manual, lalu commit ke repository. Tanpa baseline, run pertama gagal karena Playwright tidak memiliki pembanding.

import { expect, test } from "@playwright/test";

test("button all states visual snapshot", async ({ page }) => {
  await page.goto("http://127.0.0.1:6006/iframe.html?id=design-system-button--all-states");
  await expect(page).toHaveScreenshot("button-all-states.png", {
    fullPage: true,
    animations: "disabled"
  });
});

Hubungkan token generation, Vitest story tests, Storybook build, dan Playwright visual test sebagai tahap yang dapat dibaca jelas di GitHub Actions:

name: design-system-quality

on:
  pull_request:
    paths:
      - "tokens.json"
      - "scripts/build-tokens.mjs"
      - "src/components/**"
      - "src/styles/**"
      - ".storybook/**"
      - "tests/**"
      - "package.json"
      - "package-lock.json"

jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run tokens:build
      - run: npx playwright install --with-deps chromium
      - run: npm run test:storybook -- --run
      - run: npm run build-storybook
      - run: >
          npx concurrently -k -s first -n server,tests
          "npx http-server storybook-static -p 6006"
          "npx wait-on http://127.0.0.1:6006 && npm run test:visual"

Saat CI gagal, berikan kepada Claude Code failing story ID, pelanggaran axe, daftar file yang berubah, dan visual diff. Jangan menempel seluruh log yang mungkin memuat secret. Minta agent mereproduksi failure, membuat fix terkecil, dan menjelaskan bukti test; jangan memperbarui snapshot hanya agar check menjadi hijau.

Batas aman integrasi Figma

Figma Variables merupakan input yang baik untuk token, tetapi automatic two-way sync terlalu berisiko pada tahap awal. Eksperimen yang belum disetujui, nama komponen lama, atau catatan desain privat dapat masuk ke production token. Mulailah dari laporan perbedaan dan biarkan manusia memutuskan sumber kebenaran.

AreaOtomasi yang amanHindari
Figma VariablesExport lalu bandingkan dengan tokens.jsonMenimpa production tokens tanpa review
Figma ComponentsMengumpulkan kandidat state dan propsMenentukan React API secara otomatis
Figma commentsMerangkum pertanyaan yang belum selesaiMenebak keputusan desain final
Storybook linksMenambahkan story URL pada design reviewMenganggap Storybook sebagai persetujuan desain

Gunakan prompt lokal berikut untuk membuat review report terlebih dahulu:

Baca figma-tokens-export.json dan tokens.json.
Buat laporan Markdown yang memuat:
1. token yang ada di Figma tetapi tidak ada di code
2. token yang ada di code tetapi tidak ada di Figma
3. perbedaan nilai pada semantic token yang cocok
Jangan mengedit tokens.json dan jangan mengganti nama token. Tandai perbedaan berisiko pada focus, danger, dan text color.

Tujuannya bukan sinkronisasi demi sinkronisasi, melainkan diff yang aman dan dapat direview bersama. Simpan report sebagai artifact pull request agar keputusan token dapat dilacak saat muncul perbedaan baru.

Empat kasus penggunaan yang nyata

Kasus penggunaan 1: Menyatukan Button pada admin SaaS

Input: class, props, stories, dan screenshot Button dari beberapa layar. Output Claude Code: inventory penggunaan, compatibility props, pemetaan token, dan diff migrasi untuk satu layar. Review manusia: semantik tindakan billing atau destructive, keyboard operation, dan visual diff. Migrasi satu layar membatasi penyebab jika existing caller rusak.

Kasus penggunaan 2: Mengganti brand pada produk white-label

Input: primitive brand colors setiap pelanggan dan schema semantic token bersama. Output Claude Code: CSS variables per brand, typed token map, dan theme switch di Storybook. Review manusia: contrast, aturan brand legal, serta warna focus dan danger. Semantic layer tetap stabil walaupun raw value berbeda untuk setiap pelanggan.

Kasus penggunaan 3: Mengambil kandidat token dari legacy CSS

Input: hex color, spacing, dan selector yang berulang. Output Claude Code: frequency report, usulan pemetaan primitive/semantic, dan tabel migrasi. Review manusia: apakah nilai yang tampak sama benar-benar mempunyai makna yang sama. Jangan mengganti seluruh CSS dalam satu commit; mulai dari komponen bernilai tinggi dan periksa snapshot.

Kasus penggunaan 4: Menstabilkan funnel pemasaran dan inquiry

Input: CTA button, pricing card, form states, dan halaman konversi. Output Claude Code: shared tokens, component variants, error/loading stories, dan kandidat visual test. Review manusia: copy, CTA utama, hierarchy mobile, serta makna bisnis eksperimen. State yang konsisten membantu pengunjung memahami tindakan dan membuat perubahan konversi lebih mudah diukur.

Jebakan, penyebab, dan cara memperbaikinya

Jebakan: primitive token dipakai langsung di komponen. Penyebabnya adalah blue-600 terasa cepat ditulis. Saat brand berubah, setiap komponen harus dicari. Perbaikan: batasi raw value di primitive layer dan gunakan semantic atau component token pada UI.

Jebakan: Storybook hanya berjalan lokal. Penyebabnya adalah katalog dianggap dokumentasi, bukan kontrak. Story dan addon dapat rusak tanpa diketahui. Perbaikan: wajibkan vitest --project=storybook, Storybook build, dan visual tests terpilih pada pull request.

Jebakan: semua story dijadikan snapshot. Penyebabnya adalah mengejar jumlah coverage. Animation, date, font, dan random ID menghasilkan diff bising. Perbaikan: bekukan data dinamis dan mulai dari state checkout, billing, atau destructive action yang bernilai tinggi.

Jebakan: hasil axe dianggap aksesibilitas lengkap. Penyebabnya adalah hasil otomatis disamakan dengan penilaian pengguna. Axe tidak memahami kualitas copy dan alur screen reader. Perbaikan: tambahkan review keyboard-only, focus order, dan screen reader untuk workflow utama.

Jebakan: seluruh migrasi diberikan kepada Claude Code sekaligus. Penyebabnya adalah prompt tidak membatasi file dan acceptance criteria. Perbaikan: kerjakan satu komponen, minta tests serta changed-file list, dan biarkan manusia menyetujui setiap perubahan API.

Jebakan: Figma dan code disinkronkan dua arah tanpa review. Penyebabnya adalah “single source of truth” disalahartikan sebagai automatic overwrite. Perbaikan: buat difference report, setujui perubahan token, lalu generate output code.

Checklist sebelum merge

  • Nama token menyatakan fungsi, bukan hanya penampilan.
  • Props komponen minimal, typed, dan stabil bagi existing callers.
  • State disabled, loading, error, focus, serta hover ada di Storybook.
  • Keyboard-only operation dan focus order sudah direview manusia.
  • ARIA ditambahkan saat perlu dan tidak menduplikasi native HTML.
  • Perubahan visual snapshot sudah dilihat dan disetujui.
  • Perbedaan Figma tersimpan sebagai review artifact.
  • Claude Code hanya mengubah area file yang diminta.
  • Prompt, log, story, dan screenshot tidak memuat secret atau data pelanggan pribadi.

Masukkan checklist ini ke project instructions. Pada sesi berikutnya Claude Code dapat memakai acceptance criteria yang sama, sementara reviewer tidak perlu menulis ulang batas kerja dari awal.

Pilih satu langkah berikutnya

Pastikan dahulu bahwa tokens.json menghasilkan CSS variables dan TypeScript constants, stories Button menampilkan semua state, serta CI dapat mengulang Storybook component, accessibility, dan visual checks. Pertahankan integrasi Figma dalam mode report-only sampai tim menyepakati sumber kebenaran. Untuk bantuan terstruktur mengenai implementasi design system, adopsi Storybook, atau workflow accessibility, gunakan training dan konsultasi Claude Code.

Hasil yang benar-benar diuji

Pada 22 Juli 2026, kode build-tokens.mjs dalam artikel ini diekstrak dan dijalankan terhadap contoh tokens.json lengkap. Proses selesai dengan exit code 0, menghasilkan 25 CSS custom properties dan TypeScript token map, serta menyelesaikan reference {primitive.color.blue.600} menjadi #2563eb. Negative fixture dengan unknown reference keluar non-zero dan menampilkan Unknown token reference. JSON snippets berhasil diparse, code fences dan internal links diperiksa, sedangkan command Storybook dicocokkan dengan dokumentasi resmi Vitest addon serta migrasi terkini. Storybook tidak dipasang di repository situs ini, jadi component dan visual tests harus dijalankan di aplikasi target sebelum workflow diadopsi.

#Claude Code #design system #Design Tokens #Storybook #aksesibilitas
Gratis

PDF gratis: cheatsheet Claude Code

Masukkan email dan unduh satu halaman berisi command, kebiasaan review, dan workflow aman.

Kami menjaga datamu dan tidak mengirim spam.

Masa

Tentang penulis

Masa

Engineer yang berfokus pada workflow Claude Code praktis dan adopsi tim.