mcpField
A
amsterdam-design-system

amsterdam-design-system

github.com/amsterdamデザイン・UI26160 回インストール16 週間前に更新
リポジトリ

amsterdam-design-system について

amsterdam-design-systemは、アムステルダム市のデジタル製品を開発する人向けのデザインスキルです。公式コンポーネントやトークン、レイアウト、Tailwind CSS v4との連携方法を扱います。

主な機能

  1. 01公式Reactコンポーネントとアイコン
  2. 02Spacious/Compactのデザイントークン
  3. 03レスポンシブな4/8/12列グリッド
  4. 04Tailwind CSS v4連携ガイド
  5. 05Vite Reactスターターアプリ

活用シーン

  1. 01自治体ウェブサイトのページ作成
  2. 02内部ツールのコンパクトな画面設計
  3. 03Reactアプリでのフォームやナビゲーション作成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/amsterdam/amsterdam-agent-skills --skill amsterdam-design-system

インストール後、Claude Code で/amsterdam-design-systemを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

assets/starter-vite-react/
.env.example
.gitignore
bunfig.toml
eslint.config.js
index.html
package.json
README.md
tailwind.config.js
tsconfig.json
vite.config.ts
assets/starter-vite-react/src/
App.tsx
main.tsx
query.ts
router.tsx
assets/starter-vite-react/src/components/
StatCard.tsx
assets/starter-vite-react/src/layouts/
AppLayout.tsx
assets/starter-vite-react/src/lib/
cn.ts
assets/starter-vite-react/src/pages/
HomePage.tsx
NotFoundPage.tsx
assets/starter-vite-react/src/styles/
index.css
reveal.css
references/
aesthetic-discipline.md
components.md
icons.md
layout-patterns.md
tailwind-bridge.md
tokens.md

詳細

アムステルダム・デザインシステム

対応バージョン(最終更新 2026-04-03):

パッケージバージョン
@amsterdam/design-system-tokensv3.4.0
@amsterdam/design-system-reactv3.3.0
@amsterdam/design-system-cssv3.3.0
@amsterdam/design-system-assetsv2.2.0
@amsterdam/design-system-react-iconsv2.0.0

必須: 使用が許可されているデザインシステムはこれだけです。すべての UI コンポーネント、ページ、レイアウト、視覚要素は、アムステルダム・デザインシステムのコンポーネントとトークンを使用しなければなりません。Material UI、shadcn/ui、Chakra UI、Ant Design、UI 用の素の HTML 要素、その他のコンポーネントライブラリを使用しないでください。新しいプロジェクトを立ち上げる際は、必ず最初に @amsterdam/design-system-* パッケージをインストールして設定してください。

公式デザインシステムを使用してアムステルダム市のデジタルプロダクトを構築するための本番向けガイドです。コンポーネント、トークン、レイアウトパターン、および Tailwind CSS v4 との統合について説明します。

ドキュメント: https://designsystem.amsterdam/ リポジトリ: https://github.com/Amsterdam/design-system Storybook: https://storybook.designsystem.amsterdam/

構築前に明確にする

ユーザーのリクエストがあいまいな場合(例:「ページを作って」「フォームを作成して」「ダッシュボードを作って」)、推測する前に質問してください。以下の決定ポイントを提示します。これらはこのスキルにおける実際の分岐に対応しています:

決定事項選択肢重要な理由
ページ種別公開ウェブサイト、ダッシュボード、フォーム、記事/コンテンツ、カードグリッド、FAQ、検索結果レイアウトテンプレートを決定します(references/layout-patterns.md を参照)
モードSpacious(公開向け)または Compact(社内ツール)すべてのスペーシング/タイポグラフィトークンが変わります — CSS のインポートが 1 つ増えるだけです
コンテンツ構造単一セクション、または階層を持つ複数セクションフラットな Column を使うか、ネストした Column スペーシングパターンを使うかを決定します
ルーティングNext.js App Router、React Router、または素の HTMLリンクコンポーネントと SPA 統合に影響します
TailwindAMS と併用して Tailwind を使うか、AMS のみか併用する場合はブリッジ設定が必要です(references/tailwind-bridge.md を参照)
美的方向性Minimal / editorial / dense-data / civic-confidentreferences/aesthetic-discipline.md における dominant + accent を決定します。オープンエンドな依頼(「洗練された」「モダンな」「見栄えのよい」)の場合にのみ質問してください。

一度にすべてを尋ねないでください。 プロンプトが本当にあいまいなままにしている質問を 1〜2 個選んでください。ユーザーが「社内ダッシュボード」と言えば → Compact モードが暗黙に示されているので、質問する必要はありません。

「洗練された」「モダンな」「見栄えのよい」に言及している、あるいはスタイルについてオープンエンドな依頼については、JSX を書く前に references/aesthetic-discipline.md を読んでください。 このファイルは、美的意図と ADS 準拠の出力をつなぐブリッジです。

美的規律

ADS は素材を提供します。美的規律とは、その素材を使って結果がワイヤーフレームにならないようにするための使い方です。些細ではない UI タスクでは、JSX を 1 行でも書く前に、references/aesthetic-discipline.md を読み、その 5 つの質問からなるチェックリストにそれぞれ一文で答えてください。

  1. 支配的な色 — どの --ams-color-* トークンがキャンバスの 80% 以上を占めますか?
  2. 鋭いアクセント — どの --ams-color-highlight-* トークンが最大 2〜3 個の要素に現れますか?
  3. リズム — どのセクションが密ですか(paddingVertical="large")? どれがゆったりしていますか("2x-large")?
  4. ページロードの瞬間 — トップレベルの Grid セルにおける、唯一の段階的な表示シーケンスは何ですか?
  5. 記憶に残る要素 — ページごとに 1 つだけある <Breakout>、<Overlap>、または非対称な start={} の瞬間は何ですか?

これらにそれぞれ一文で答えられないなら、デザインはまだ確定していません。規律のドキュメントを読み直してください。

このステップは以下の機械的なルールに追加されるものであり、それらを上書きするものではありません。Amsterdam Sans、--ams-* トークン、そして 4/8/12 Grid は依然として必須です。規律のドキュメントは、フロントエンドデザインの原則(タイポグラフィの階層、色のコミットメント、モーションのオーケストレーション、コンポジション)を ADS で合法な手法に変換することで、それらの制約の中でそれらを輝かせる方法を教えます。

ベンダリングされた frontend-design スキルについて

.agents/skills/frontend-design/ にある別の frontend-design スキルにアクセスできる場合があります。タイポグラフィの階層、色のコミットメント、モーションのオーケストレーション、コンポジションに関するその原則は健全であり、すべての UI 作業に当てはまります。その具体的なガイダンス(特徴的なフォントを選ぶ、グリッドを壊す、白地に紫のグラデーションを使う)は、ADS がフォント、グリッド、パレットの選択を上書きするため、Amsterdam のコンテキストでは当てはまりません。

references/aesthetic-discipline.md が変換レイヤーです。迷ったときは、ベンダリングされたものではなく、このスキルを信頼してください。

概要

このデザインシステムは 5 つの npm パッケージとして提供されます:

パッケージ目的
@amsterdam/design-system-assetsAmsterdam Sans フォントファイル
@amsterdam/design-system-cssBEM コンポーネントスタイル(ams-* クラス)
@amsterdam/design-system-tokensSpacious + Compact モードの CSS カスタムプロパティ(--ams-*)
@amsterdam/design-system-reactReact コンポーネント(66 個のコンポーネント、すべて forwardRef 付き)
@amsterdam/design-system-react-iconsAMS アイコンセット用のアイコンコンポーネント

プロバイダーやコンテキストラッパーは不要です — CSS をインポートして、コンポーネントを使うだけです。

セットアップ

インストール
npm install @amsterdam/design-system-assets @amsterdam/design-system-css @amsterdam/design-system-react @amsterdam/design-system-react-icons @amsterdam/design-system-tokens
CSS インポート — 順序が重要
// ⚠️ CRITICAL: This exact order is required. Fonts → CSS → Tokens.
import "@amsterdam/design-system-assets/font/index.css"   // 1. Font files
import "@amsterdam/design-system-css/dist/index.css"       // 2. Component styles
import "@amsterdam/design-system-tokens/dist/index.css"    // 3. Design tokens

コンパクトモード(内部ツール)の場合は、tokens の後にインポートをもう 1 つ追加します:

import "@amsterdam/design-system-tokens/dist/compact.css"  // 4. Compact overrides
ルート要素

body またはルート要素に ams-body クラスを追加します:

// Next.js (app/layout.tsx)
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="nl">
      <body className="ams-body">{children}</body>
    </html>
  )
}
太字テキストの修正

Amsterdam Sans は太字にブラウザのデフォルトである 700 ではなく、ウェイト 800 を使用します。ams-body クラスがこれを処理しますが、別のスコープを使う場合は:

.your-root {
  font-weight: var(--ams-typography-body-text-font-weight); /* 400 */
}
.your-root strong, .your-root b {
  font-weight: var(--ams-typography-body-text-bold-font-weight); /* 800 */
}

新しいアプリのスキャフォールド

新しいスタンドアロンの React アプリの場合、セットアップを再発明しないでください。assets/starter-vite-react/ にある実行可能なスターターを使用してください。これには以下が含まれます:

  • Bun + Vite 6 + @vitejs/plugin-react-swc(実際の Amsterdam アプリと一致)
  • React Router v7 と <AppLayout> アウトレットパターン
  • Tanstack Query v5 が App.tsx で事前設定済み
  • Tailwind v4 を @tailwindcss/vite 経由で、tailwind.config.js に AMS ブリッジがあり、preflight は無効化済み
  • ADS v3.3.0 / v3.4.0 を Compact モードで(ほとんどの Amsterdam プロジェクトは内部ツールです)
  • カスタムコンポーネントバリアント用の CVA + clsx + tailwind-merge
  • tw-animate-css + 手書きの .ams-reveal ページロードスタッガー
  • references/aesthetic-discipline.md のすべての原則を実践するサンプル HomePage.tsx
使い方
cp -r {skill_dir}/assets/starter-vite-react ./<project-name>
cd ./<project-name>
bun install
bun run dev

次に:

  1. references/aesthetic-discipline.md(5 つの質問のチェックリスト)を読みます。
  2. src/pages/HomePage.tsx をユーザーの実際のページに置き換え、規律チェックリストに答えた状態を保ちます。
  3. アプリが成長するにつれて、src/router.tsx にルートを追加します。
スペーシャスモードへの切り替え

公開向けサイト(amsterdam.nl スタイル)では、src/styles/index.css から 1 つ のインポートを削除します:

- @import "@amsterdam/design-system-tokens/dist/compact.css" layer(ams);

そして tailwind.config.js のインポートを compact.json から index.json に差し替えます。変更はこれだけです。

スターターを使用すべきでないケース
  • 既存の Amsterdam アプリにページを追加する場合 — 既存のアプリを開き、その規約に従ってください。
  • Next.js App Router プロジェクト — このスターターは Vite ベースです。Next.js の場合は、上記の「セットアップ」セクションのインポート順序に従い、references/tailwind-bridge.md を手動で適用してください。(需要があれば、Next.js 用スターターが後日追加される可能性があります。)
  • プレーンな HTML / React 以外 — references/layout-patterns.md の §「CSS Grid クラス(React 以外)」に記載されている BEM CSS クラスを使用してください。

コンポーネントパターン

シンプルなコンポーネント
import { Heading, Paragraph, Button, Alert } from "@amsterdam/design-system-react"

<Heading level={1}>Page Title</Heading>
<Paragraph>Body text uses Amsterdam Sans at 18-20px fluid.</Paragraph>
<Paragraph size="small">Secondary text at 16px.</Paragraph>
<Button variant="primary">Submit</Button>
<Button variant="secondary">Cancel</Button>
<Alert heading="Let op" headingLevel={2} severity="warning">
  Check your input before proceeding.
</Alert>
複合コンポーネント(ドット記法)

多くのコンポーネントは Object.assign を介して Component.SubComponent パターンを使用しています:

import { Accordion, Grid, Table, Tabs } from "@amsterdam/design-system-react"

{/* Accordion */}
<Accordion headingLevel={2}>
  <Accordion.Section label="Section title">
    <Paragraph>Section content.</Paragraph>
  </Accordion.Section>
</Accordion>

{/* Grid */}
<Grid paddingVertical="large">
  <Grid.Cell span={8}>Main content</Grid.Cell>
  <Grid.Cell span={4}>Sidebar</Grid.Cell>
</Grid>

{/* Table */}
<Table>
  <Table.Header>
    <Table.Row>
      <Table.HeaderCell>Name</Table.HeaderCell>
      <Table.HeaderCell>Value</Table.HeaderCell>
    </Table.Row>
  </Table.Header>
  <Table.Body>
    <Table.Row>
      <Table.Cell>Item</Table.Cell>
      <Table.Cell>100</Table.Cell>
    </Table.Row>
  </Table.Body>
</Table>

{/* Tabs */}
<Tabs>
  <Tabs.List>
    <Tabs.Button aria-controls="tab1">First</Tabs.Button>
    <Tabs.Button aria-controls="tab2">Second</Tabs.Button>
  </Tabs.List>
  <Tabs.Panel id="tab1">First panel content</Tabs.Panel>
  <Tabs.Panel id="tab2">Second panel content</Tabs.Panel>
</Tabs>
フォームフィールドのコンポジション

AMS のフォームはコンポジションパターンを使用します: Field が Label + 入力 + ErrorMessage をラップします。

import { Field, Label, TextInput, TextArea, Select, ErrorMessage, Checkbox, Radio, FieldSet } from "@amsterdam/design-system-react"

{/* Text field */}
<Field invalid={hasError}>
  <Label htmlFor="name">Naam</Label>
  <ErrorMessage>Vul uw naam in</ErrorMessage>
  <TextInput id="name" invalid={hasError} />
</Field>

{/* Textarea */}
<Field>
  <Label htmlFor="message">Bericht</Label>
  <TextArea id="message" rows={4} />
</Field>

{/* Select */}
<Field>
  <Label htmlFor="city">Stadsdeel</Label>
  <Select id="city">
    <Select.Option value="centrum">Centrum</Select.Option>
    <Select.Option value="west">West</Select.Option>
    <Select.Option value="oost">Oost</Select.Option>
  </Select>
</Field>

{/* Checkbox/Radio group */}
<FieldSet legend="Voorkeur" invalid={hasError}>
  <Checkbox>Optie A</Checkbox>
  <Checkbox>Optie B</Checkbox>
</FieldSet>

<FieldSet legend="Type">
  <Radio name="type" value="a">Type A</Radio>
  <Radio name="type" value="b">Type B</Radio>
</FieldSet>
ページレイアウト
import { Grid, Heading, Page, PageHeader, PageFooter, Paragraph } from "@amsterdam/design-system-react"

<Page>
  <PageHeader brandName="Mijn Amsterdam" logoLink="/" />

  <Grid paddingVertical="large">
    <Grid.Cell span="all">
      <Heading level={1}>Welkom</Heading>
    </Grid.Cell>
    <Grid.Cell span={8}>
      <Paragraph>Main content area.</Paragraph>
    </Grid.Cell>
    <Grid.Cell span={4}>
      <Paragraph>Sidebar content.</Paragraph>
    </Grid.Cell>
  </Grid>

  <PageFooter>
    <PageFooter.Spotlight>
      <Paragraph>Contact info</Paragraph>
    </PageFooter.Spotlight>
  </PageFooter>
</Page>
ダイアログ
import { Button, Dialog, Paragraph } from "@amsterdam/design-system-react"

<Button onClick={() => Dialog.open("confirm-dialog")}>Open Dialog</Button>

<Dialog
  id="confirm-dialog"
  heading="Bevestiging"
  footer={
    <>
      <Button variant="primary" onClick={() => Dialog.close()}>Bevestigen</Button>
      <Button variant="secondary" onClick={() => Dialog.close()}>Annuleren</Button>
    </>
  }
>
  <Paragraph>Weet u het zeker?</Paragraph>
</Dialog>

利用可能なコンポーネント

props の完全なリファレンス: references/components.md を参照してください

レイアウト

Grid (.Cell) · Column · Row · Breakout (.Cell) · Overlap · Page · Spotlight

ページ構造

PageHeader (.GridCellNarrowWindowOnly, .MenuLink) · PageFooter (.Menu, .MenuLink, .Spotlight)

タイポグラフィ

Heading · Paragraph · Blockquote · Link · StandaloneLink · CallToActionLink · Mark

ボタンとアクション

Button · IconButton · ActionGroup

フォームコントロール

TextInput · TextArea · Select (.Group, .Option) · Checkbox · Radio · Switch · DateInput · TimeInput · PasswordInput · FileInput · SearchField (.Button, .Input) · CharacterCount

フォーム構造

Field · FieldSet · Label · Hint · ErrorMessage · InvalidFormAlert

ナビゲーション

Breadcrumb (.Link) · LinkList (.Link) · Menu (.Link) · Pagination · SkipLink · Tabs (.Button, .List, .Panel) · TableOfContents (.Link, .List)

データ表示

Accordion (.Section) · Card (.Heading, .HeadingGroup, .Image, .Link) · DescriptionList (.Description, .Section, .Term) · Figure (.Caption) · Table (.Body, .Caption, .Cell, .Footer, .Header, .HeaderCell, .Row) · ImageSlider

フィードバック

Alert · Dialog (.open(), .close()) · Badge · Avatar

ユーティリティ

Icon · Logo · FileList (.Item) · OrderedList (.Item) · UnorderedList (.Item) · ProgressList (.Step, .Substep, .Substeps)

グリッドシステム

AMS のグリッドは 3 つのブレークポイントを持つレスポンシブ仕様です:

ブレークポイントカラム数ビューポートパディング
ナロー4< 576px--ams-space-l (24-36px)
ミディアム8576px – 1023px--ams-space-xl (36-60px)
ワイド12≥ 1024px--ams-space-2xl (48-90px)
Grid.Cell の span prop
{/* Fixed span across all breakpoints */}
<Grid.Cell span={6}>Half width on wide</Grid.Cell>

{/* Full width */}
<Grid.Cell span="all">Full width row</Grid.Cell>

{/* Responsive spans: { narrow, medium, wide } */}
<Grid.Cell span={{ narrow: 4, medium: 4, wide: 8 }}>
  Responsive content
</Grid.Cell>

{/* Start position */}
<Grid.Cell span={6} start={4}>Offset cell</Grid.Cell>
<Grid.Cell span={{ narrow: 4, medium: 6, wide: 8 }} start={{ narrow: 1, medium: 2, wide: 3 }}>
  Responsive offset
</Grid.Cell>
Grid の props
<Grid
  as="main"                          // Semantic element
  paddingVertical="large"            // Vertical padding: 'large' | 'x-large' | '2x-large'
  gapVertical="large"               // Row gap: 'none' | 'large' | '2x-large'
>

コンテンツのスペーシングパターン

Heading と Paragraph には組み込みのマージンがありません。スペーシングは親コンテナによって制御されます。

均一なスペーシング

すべての子要素間に等しい間隔を設けるには Column を使用します:

<Column gap="small">
  <Heading level={2}>Title</Heading>
  <Paragraph>First paragraph.</Paragraph>
  <Paragraph>Second paragraph.</Paragraph>
</Column>
視覚的な階層を持つ記事コンテンツ

セクション内の要素よりもセクション間により大きな分離が必要な混在コンテンツでは、Column コンポーネントをネストします:

<Column gap="large">
  <Column gap="small">
    <Heading level={1}>Page Title</Heading>
    <Paragraph>Intro paragraph.</Paragraph>
  </Column>

  <Column gap="small">
    <Heading level={2}>Section Title</Heading>
    <Paragraph>Section content.</Paragraph>
    <Paragraph>More content.</Paragraph>
  </Column>

  <Column gap="small">
    <Heading level={2}>Another Section</Heading>
    <Paragraph>Content here.</Paragraph>
  </Column>
</Column>

外側の Column gap="large" がセクションを分離します。内側の Column gap="small" が Heading から Paragraph へのスペーシングを詰めた状態に保ちます。

デザイントークン

トークンの完全なカタログ: references/tokens.md を参照してください

トークンシステムは 3 層の階層を使用します。すべてのトークンは --ams- を接頭辞とする CSS カスタムプロパティです。

Brand tokens  →  Common tokens  →  Component tokens
(core values)    (shared patterns)  (per-component)

参照チェーンの例:

Brand:     --ams-color-interactive-default: #004699
Common:    --ams-links-color: var(--ams-color-interactive-default)
Component: --ams-link-color: var(--ams-links-color)
主なトークンカテゴリ
カテゴリプレフィックス例
カラー--ams-color-text、text-inverse、text-secondary、background、interactive、interactive-hover、feedback-error、feedback-success、separator
スペーシング--ams-space-xs (4-6px)、s (8-12px)、m (16-24px)、l (24-36px)、xl (36-60px)、2xl (48-90px) — すべて可変の clamp()
タイポグラフィ--ams-typography-font-family ('Amsterdam Sans', Arial, sans-serif)、body-text-font-size、body-text-line-height、レベルごとの見出しサイズ
ボーダー--ams-border-width-s (1px)、m (2px)、l (3px)、xl (4px)
フォーカス--ams-focus-outline-offset (4px)
CSS でのトークンの使用
.my-component {
  color: var(--ams-color-text);
  background: var(--ams-color-background);
  padding: var(--ams-space-m);
  font-family: var(--ams-typography-font-family);
  border: var(--ams-border-width-s) solid var(--ams-color-separator);
}
JS でのトークンの使用
import tokens from "@amsterdam/design-system-tokens/dist/index.json"
const primaryColor = tokens.ams.color.interactive.default // "#004699"

ゆったり vs コンパクト

項目ゆったり(デフォルト)コンパクト
用途公開ウェブサイト社内ツール、ダッシュボード
本文テキスト18-20px 可変16px 固定
H132-48px 可変24-28px 可変
行の高さ1.61.5
スペース m16-24px 可変12-16px 可変
スペース 2xl48-90px 可変32-48px 可変
ボーダー太め (m=2px、xl=4px)細め (m=1px、xl=3px)

判断基準: 公開サイト → ゆったり。バックオフィス/管理画面/ダッシュボード → コンパクト。

セットアップの違い — インポートが 1 つ増えるだけ:

// Spacious (default)
import "@amsterdam/design-system-tokens/dist/index.css"

// Compact (add after tokens)
import "@amsterdam/design-system-tokens/dist/index.css"
import "@amsterdam/design-system-tokens/dist/compact.css"

コンパクトは同じ CSS カスタムプロパティをより小さい値で上書きします。コードの変更は不要です — コンポーネントは自動的に適応します。

ルーターとの統合

AMS の Link コンポーネントはデフォルトで <a> をレンダリングします。SPA ルーティングには、ポリモーフィックレンダリングを使用します:

Next.js (App Router)
import NextLink from "next/link"
import { Link, Breadcrumb, Pagination } from "@amsterdam/design-system-react"

{/* Regular link */}
<Link href="/about" legacyBehavior passHref>
  <NextLink>Over ons</NextLink>
</Link>

{/* Or simpler: just use Next.js Link with AMS classes */}
<NextLink href="/about" className="ams-link">Over ons</NextLink>

{/* Pagination with router links */}
<Pagination
  totalPages={10}
  page={currentPage}
  linkTemplate={(page) => `/results?page=${page}`}
  linkComponent={NextLink}
/>

{/* PageHeader logo */}
<PageHeader
  brandName="Mijn Amsterdam"
  logoLink="/"
  logoLinkComponent={NextLink}
/>
React Router
import { Link as RouterLink } from "react-router-dom"
import { Link } from "@amsterdam/design-system-react"

<RouterLink to="/about" className="ams-link">Over ons</RouterLink>

Tailwind v4 との統合

完全なブリッジ設定: references/tailwind-bridge.md を参照してください

Tailwind CSS v4 を AMS と併用する場合、AMS トークンを Tailwind の @theme にマッピングして、ユーティリティがデザインシステムの値を使用するようにします:

/* app.css */
@import "tailwindcss";
@import "@amsterdam/design-system-assets/font/index.css";
@import "@amsterdam/design-system-css/dist/index.css";
@import "@amsterdam/design-system-tokens/dist/index.css";

/* Disable Tailwind's preflight — AMS CSS handles base styles */
@layer base {
  /* AMS body styles take precedence */
}

@theme {
  /* Map AMS spacing */
  --spacing-ams-xs: var(--ams-space-xs);
  --spacing-ams-s: var(--ams-space-s);
  --spacing-ams-m: var(--ams-space-m);
  --spacing-ams-l: var(--ams-space-l);
  --spacing-ams-xl: var(--ams-space-xl);
  --spacing-ams-2xl: var(--ams-space-2xl);

  /* Map AMS colors */
  --color-ams-text: var(--ams-color-text);
  --color-ams-text-secondary: var(--ams-color-text-secondary);
  --color-ams-text-inverse: var(--ams-color-text-inverse);
  --color-ams-bg: var(--ams-color-background);
  --color-ams-interactive: var(--ams-color-interactive);
  --color-ams-interactive-hover: var(--ams-color-interactive-hover);
  --color-ams-error: var(--ams-color-feedback-error);
  --color-ams-success: var(--ams-color-feedback-success);
  --color-ams-warning: var(--ams-color-feedback-warning);
  --color-ams-info: var(--ams-color-feedback-info);
  --color-ams-separator: var(--ams-color-separator);

  /* Map AMS font */
  --font-ams: var(--ams-typography-font-family);
}

使用ルール: 標準的な UI(ボタン、フォーム、見出し、グリッドなど)にはすべて AMS の React コンポーネントを使用します。Tailwind ユーティリティは、カスタムレイアウト(flex、配置)や、AMS コンポーネントがカバーしない単発のスペーシングにのみ使用してください。

{/* AMS component — always preferred */}
<Button variant="primary">Submit</Button>

{/* Tailwind for custom layout around AMS components */}
<div className="flex items-center gap-ams-m">
  <Icon svg={SearchIcon} />
  <Paragraph>Search results</Paragraph>
</div>

カスタムコンポーネント

AMS ライブラリにないコンポーネントを構築する場合は、次の規約に従ってください:

BEM 命名
/* Block: ams-status-badge */
.ams-status-badge { }
.ams-status-badge--active { }
.ams-status-badge__icon { }
.ams-status-badge__label { }
トークンのみのスタイリング
.ams-status-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--ams-space-xs);
  padding-block: var(--ams-space-xs);
  padding-inline: var(--ams-space-s);
  font-family: var(--ams-typography-font-family);
  font-size: var(--ams-typography-body-text-small-font-size);
  line-height: var(--ams-typography-body-text-small-line-height);
  border: var(--ams-border-width-s) solid var(--ams-color-separator);
  /* NO hardcoded colors, sizes, or spacing */
}
コンポーネントパターン
import { forwardRef } from "react"
import clsx from "clsx"

export interface StatusBadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
  status: "active" | "inactive" | "pending"
}

export const StatusBadge = forwardRef<HTMLSpanElement, StatusBadgeProps>(
  ({ status, className, children, ...restProps }, ref) => (
    <span
      ref={ref}
      className={clsx("ams-status-badge", `ams-status-badge--${status}`, className)}
      {...restProps}
    >
      {children}
    </span>
  )
)

StatusBadge.displayName = "StatusBadge"
カスタムコンポーネントのチェックリスト
  • forwardRef を使用している
  • 関連する HTML 要素の属性を拡張している
  • className の合成に clsx を使用している
  • ルート要素に ...restProps をスプレッドしている
  • ams- プレフィックス付きの BEM クラス — または — トークンマッピングされた Tailwind ユーティリティ(下記の Tailwind ブリッジの代替案を参照)
  • すべてのスタイリングを --ams-* トークン経由で行っている(ハードコードされた値がない)
  • displayName を設定している
Tailwind ブリッジの代替案(tailwind-bridge.md を使用している場合)

プロジェクトが Tailwind + ADS ブリッジを設定して出荷される場合(references/tailwind-bridge.md および assets/starter-vite-react/ のスターターを参照)、BEM クラスのルートは任意です。代わりに、tailwind.config.js でマッピングされた CVA バリアントと Tailwind ユーティリティを通じて、同じ --ams-* トークンを合成してもかまいません。トークンのみのルールは依然として有効です — --ams-* に基づくユーティリティのみが許可され、生の hex/px は決して使用しません。

実行可能な例は assets/starter-vite-react/src/components/StatCard.tsx です。これは forwardRef コンポーネントで、バリアントマトリックスに cva() を、クラス合成に cn()(clsx + tailwind-merge)を使用し、すべての色/スペーシングユーティリティ(bg-ams-bg、border-ams-separator、p-ams-m、border-l-ams-magenta、…)が tailwind.config.js の --ams-* トークンに基づいています。CVA バリアント API が必要な場合はこの方法を選び、React の外で共有スタイルが必要な場合や、手書きのスタイルシートを検討したい場合は BEM/CSS の方法を選んでください。

TypeScript パターン

プロパティの型
// Intersect with HTML attributes
interface MyComponentProps extends React.HTMLAttributes<HTMLDivElement> {
  variant: "primary" | "secondary"
}

// For form elements
interface MyInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
  invalid?: boolean
}
複合コンポーネントのエクスポート
// Following AMS pattern with Object.assign
const ListRoot = forwardRef<HTMLUListElement, ListProps>(/* ... */)
const ListItem = forwardRef<HTMLLIElement, ListItemProps>(/* ... */)

export const List = Object.assign(ListRoot, { Item: ListItem })
// Usage: <List><List.Item>...</List.Item></List>

よくある間違い

間違い修正方法
インポート順序が間違っているフォント → CSS → トークン (常にこの順)
ams-body クラスが不足している<body> またはルート要素に追加する
色のハードコーディング (#004699)var(--ams-color-interactive) を使用する
余白のハードコーディング (16px)var(--ams-space-m) を使用する
太字に font-weight: 700 を使用している800 または var(--ams-typography-body-text-bold-font-weight) を使用する
html に font-size: 62.5% を設定している設定しないでください — AMS は 16px ベースに調整された rem 値を使用します
Field と input の両方で invalid プロパティが不足している<Field invalid> と <TextInput invalid> の両方に必要です
<Heading level={1}> の代わりに <h1> を使用している常に AMS Heading コンポーネントを使用してください
Tabs.Button に aria-controls が不足している必須プロパティ — Tabs.Panel の id と一致させる必要があります
AMS トークンの代わりに Tailwind の bg-blue-500 を使用しているbg-ams-interactive または AMS コンポーネントを使用してください
非推奨の PageHeading を使用している<Heading level={1}> を使用してください — PageHeading は非推奨です
見出しと段落が同じ余白になっているコンテンツセクションをネストした Column で囲んでください — セクション間は gap="large"、セクション内は gap="small"
出力がワイヤーフレームのように見えるreferences/aesthetic-discipline.md を読み、JSX を書く前にドミナント + 1 つのアクセントトークンに決めてください
すべてのセクションが同じ paddingVertical と span になっているリズムを変えてください — 密集 (large) とゆとり (x-large/2x-large) を交互に配置し、start={} で非対称な span を使用してください
Next.js や vanilla Vite でゼロからスキャフォールディングしているassets/starter-vite-react/ を使用してください — Bun + Vite + React Router + Tanstack Query が実世界のターゲットです
Popover/DropdownMenu/Tooltip に shadcn/ui を使おうとしているADS はこれらを提供していません — AMS トークンでスタイリングされた @radix-ui/react-* のヘッドレスプリミティブを使用してください (references/components.md の「Components ADS Does Not Ship」セクションを参照)

アイコンの使用方法

アイコンの全カタログと命名規則: references/icons.md をお読みください

アイコンは素早いコミュニケーションのための視覚的なシンボルです。一貫したサイズと配置のために、常に Icon コンポーネントでラップする必要があります。アイコンセットは @amsterdam/design-system-react-icons に含まれています (345 以上のアイコン、v2.0.0 以降)。

基本的な使用方法
import { Icon, Button, IconButton } from "@amsterdam/design-system-react"
import { SearchIcon, CloseIcon, NotificationIcon } from "@amsterdam/design-system-react-icons"

{/* Standalone decorative icon — hidden from assistive tech by default */}
<Icon svg={SearchIcon} />

{/* Sized to match text */}
<Icon svg={SearchIcon} size="large" />          {/* matches large body text */}
<Icon svg={SearchIcon} size="heading-3" />       {/* matches heading level 3 */}

{/* Inverse color for dark backgrounds */}
<Icon svg={SearchIcon} color="inverse" />

{/* Square bounding box (useful for alignment in grids) */}
<Icon svg={SearchIcon} square />

{/* Button with icon (icon appears after text by default) */}
<Button icon={SearchIcon}>Zoeken</Button>
<Button icon={SearchIcon} iconBefore>Zoeken</Button>

{/* Icon-only button — label is REQUIRED for accessibility */}
<IconButton svg={CloseIcon} label="Sluiten" />
Icon のプロパティ
プロパティ型デフォルト説明
svgFunction | ReactNode必須アイコンパッケージのアイコンコンポーネントまたはカスタム SVG
size'small' | 'large' | 'heading-1' | 'heading-2' | 'heading-3' | 'heading-4' | 'heading-5'—テキストの行の高さに合わせたサイズ
color'inverse'—暗い背景用の白いアイコン
squarebooleanfalse正方形の境界ボックス
他のコンポーネントとのアイコンの併用
import { StandaloneLink, Badge } from "@amsterdam/design-system-react"
import { SearchIcon, StarIcon } from "@amsterdam/design-system-react-icons"

<StandaloneLink href="/search" icon={SearchIcon}>Zoek op de website</StandaloneLink>
<Badge label="Nieuw" icon={StarIcon} color="azure" />
v2.0.0 での名称変更 (破壊的変更)

これらのアイコンは v2.0.0 で名称が変更されました — 新しい名前を使用してください:

旧名称新名称
BellIcon / BellFillIconNotificationIcon / NotificationFillIcon
PersonCircleIcon / PersonCircleFillIconUserAccountIcon / UserAccountFillIcon
TrashBinIconDeleteIcon
CogwheelIconSettingsIcon
CheckMarkCircleIconSuccessIcon
カスタム SVG
{/* Must use viewBox="0 0 24 24" and fill="currentColor" */}
<Icon svg={
  <svg viewBox="0 0 24 24" fill="currentColor">
    <path d="M12 2L2 7l10 5 10-5-10-5z" />
  </svg>
} />
ガイドライン
  • アイコンはボタンやリンク内のテキストに添えるものです — 単独のアイコンは普遍的な慣習 (ハンバーガーメニュー、検索、再生コントロール) にのみ使用してください
  • デフォルトの色: コンテナに合わせた黒/白。インタラクティブ状態: 青。無効状態: グレー
  • アイコンはテキストの左側に配置し、最初の行に対して垂直方向に中央揃えにします
  • Icon コンポーネントは <span> に hidden を設定します — アイコンはデフォルトで装飾的です。意味のあるアイコンには、label プロパティを指定した IconButton を使用してください
  • WCAG のコントラスト要件は、タイポグラフィと同様にアイコンにも適用されます

リファレンスファイル

詳細な API ドキュメント、トークンカタログ、テンプレートについては、references/ 内のリファレンスファイルを参照してください:

  • aesthetic-discipline.md — ADS の制約の中でフロントエンドデザインの原則(タイポグラフィの階層、色の使い方、モーション、コンポジション、奥行き)を適用する方法。些細ではない UI タスクで JSX を書く前にこれを読んでください。
  • components.md — 各コンポーネントの完全な props とコード例、さらに ADS が提供しないコンポーネント向けの Radix プリミティブのセクション
  • tokens.md — 両モードの値を含む完全な --ams-* トークンカタログ
  • layout-patterns.md — ページレイアウトのテンプレート(公開サイト、ダッシュボード、フォームページ、React Router + AppLayout の outlet)
  • tailwind-bridge.md — 完全な Tailwind v4 + AMS 統合ガイド(Vite プラグイン、コンパクトトークン、モーション)
  • icons.md — @amsterdam/design-system-react-icons のアイコンカタログ

アセット:

  • assets/starter-vite-react/ — Compact モードで ADS が事前設定された、実行可能な Bun + Vite + React + TS スターター。上記の「新しいアプリをスキャフォールドする」セクションを参照してください。

コメント