amsterdam-design-system について
amsterdam-design-systemは、アムステルダム市のデジタル製品を開発する人向けのデザインスキルです。公式コンポーネントやトークン、レイアウト、Tailwind CSS v4との連携方法を扱います。
主な機能
- 01公式Reactコンポーネントとアイコン
- 02Spacious/Compactのデザイントークン
- 03レスポンシブな4/8/12列グリッド
- 04Tailwind CSS v4連携ガイド
- 05Vite Reactスターターアプリ
活用シーン
- 01自治体ウェブサイトのページ作成
- 02内部ツールのコンパクトな画面設計
- 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.gitignorebunfig.tomleslint.config.jsindex.htmlpackage.jsonREADME.mdtailwind.config.jstsconfig.jsonvite.config.tsassets/starter-vite-react/src/App.tsxmain.tsxquery.tsrouter.tsxassets/starter-vite-react/src/components/StatCard.tsxassets/starter-vite-react/src/layouts/AppLayout.tsxassets/starter-vite-react/src/lib/cn.tsassets/starter-vite-react/src/pages/HomePage.tsxNotFoundPage.tsxassets/starter-vite-react/src/styles/index.cssreveal.cssreferences/aesthetic-discipline.mdcomponents.mdicons.mdlayout-patterns.mdtailwind-bridge.mdtokens.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 統合に影響します |
| Tailwind | AMS と併用して Tailwind を使うか、AMS のみか | 併用する場合はブリッジ設定が必要です(references/tailwind-bridge.md を参照) |
| 美的方向性 | Minimal / editorial / dense-data / civic-confident | references/aesthetic-discipline.md における dominant + accent を決定します。オープンエンドな依頼(「洗練された」「モダンな」「見栄えのよい」)の場合にのみ質問してください。 |
一度にすべてを尋ねないでください。 プロンプトが本当にあいまいなままにしている質問を 1〜2 個選んでください。ユーザーが「社内ダッシュボード」と言えば → Compact モードが暗黙に示されているので、質問する必要はありません。
「洗練された」「モダンな」「見栄えのよい」に言及している、あるいはスタイルについてオープンエンドな依頼については、JSX を書く前に
references/aesthetic-discipline.mdを読んでください。 このファイルは、美的意図と ADS 準拠の出力をつなぐブリッジです。
美的規律
ADS は素材を提供します。美的規律とは、その素材を使って結果がワイヤーフレームにならないようにするための使い方です。些細ではない UI タスクでは、JSX を 1 行でも書く前に、references/aesthetic-discipline.md を読み、その 5 つの質問からなるチェックリストにそれぞれ一文で答えてください。
- 支配的な色 — どの
--ams-color-*トークンがキャンバスの 80% 以上を占めますか? - 鋭いアクセント — どの
--ams-color-highlight-*トークンが最大 2〜3 個の要素に現れますか? - リズム — どのセクションが密ですか(
paddingVertical="large")? どれがゆったりしていますか("2x-large")? - ページロードの瞬間 — トップレベルの Grid セルにおける、唯一の段階的な表示シーケンスは何ですか?
- 記憶に残る要素 — ページごとに 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-assets | Amsterdam Sans フォントファイル |
@amsterdam/design-system-css | BEM コンポーネントスタイル(ams-* クラス) |
@amsterdam/design-system-tokens | Spacious + Compact モードの CSS カスタムプロパティ(--ams-*) |
@amsterdam/design-system-react | React コンポーネント(66 個のコンポーネント、すべて forwardRef 付き) |
@amsterdam/design-system-react-icons | AMS アイコンセット用のアイコンコンポーネント |
プロバイダーやコンテキストラッパーは不要です — 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
次に:
references/aesthetic-discipline.md(5 つの質問のチェックリスト)を読みます。src/pages/HomePage.tsxをユーザーの実際のページに置き換え、規律チェックリストに答えた状態を保ちます。- アプリが成長するにつれて、
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) |
| ミディアム | 8 | 576px – 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 固定 |
| H1 | 32-48px 可変 | 24-28px 可変 |
| 行の高さ | 1.6 | 1.5 |
| スペース m | 16-24px 可変 | 12-16px 可変 |
| スペース 2xl | 48-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 のプロパティ
| プロパティ | 型 | デフォルト | 説明 |
|---|---|---|---|
svg | Function | ReactNode | 必須 | アイコンパッケージのアイコンコンポーネントまたはカスタム SVG |
size | 'small' | 'large' | 'heading-1' | 'heading-2' | 'heading-3' | 'heading-4' | 'heading-5' | — | テキストの行の高さに合わせたサイズ |
color | 'inverse' | — | 暗い背景用の白いアイコン |
square | boolean | false | 正方形の境界ボックス |
他のコンポーネントとのアイコンの併用
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 / BellFillIcon | NotificationIcon / NotificationFillIcon |
PersonCircleIcon / PersonCircleFillIcon | UserAccountIcon / UserAccountFillIcon |
TrashBinIcon | DeleteIcon |
CogwheelIcon | SettingsIcon |
CheckMarkCircleIcon | SuccessIcon |
カスタム 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 スターター。上記の「新しいアプリをスキャフォールドする」セクションを参照してください。