# Zendesk Garden デザインシステム

## Zendesk Garden デザインシステム インターフェースプレビュー

返信の表示状態を切り替え、短い下書きを検証し、ローカルスナップショットを保存して、次の下書きを始めましょう。

## Zendesk Garden デザインシステム デザインリファレンス

Garden 9.16.1のネイティブなReactThemeProvider、Buttons、Formsを使用した、独自のローカル下書きワークフロー。

### 角丸の調整

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| borderRadii.sm | 2px | コンポーネントの役割に応じて形状を選びます。デフォルトの中程度の角丸はピル型ではありません。 |
| borderRadii.md | 4px | コンポーネントの役割に応じて形状を選びます。デフォルトの中程度の角丸はピル型ではありません。 |
| borderRadii.lg | 8px | コンポーネントの役割に応じて形状を選びます。デフォルトの中程度の角丸はピル型ではありません。 |
### レスポンシブブレークポイント

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| breakpoints.xs | 0px | テーマのブレークポイントです。各段階でアプリケーションのすべての領域が切り替わることを保証するものではありません。 |
| breakpoints.sm | 576px | テーマのブレークポイントです。各段階でアプリケーションのすべての領域が切り替わることを保証するものではありません。 |
| breakpoints.md | 768px | テーマのブレークポイントです。各段階でアプリケーションのすべての領域が切り替わることを保証するものではありません。 |
| breakpoints.lg | 992px | テーマのブレークポイントです。各段階でアプリケーションのすべての領域が切り替わることを保証するものではありません。 |
| breakpoints.xl | 1200px | テーマのブレークポイントです。各段階でアプリケーションのすべての領域が切り替わることを保証するものではありません。 |
### 文字サイズ

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| fontSizes.xs | 10px | 本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。 |
| fontSizes.sm | 12px | 本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。 |
| fontSizes.md | 14px | 本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。 |
| fontSizes.lg | 18px | 本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。 |
| fontSizes.xl | 22px | 本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。 |
| fontSizes.xxl | 26px | 本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。 |
| fontSizes.xxxl | 36px | 本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。 |
### 行の高さ

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| lineHeights.sm | 16px | テキストロールと併用してください。すべての行の高さをフォントサイズから算出しないでください。 |
| lineHeights.md | 20px | テキストロールと併用してください。すべての行の高さをフォントサイズから算出しないでください。 |
| lineHeights.lg | 24px | テキストロールと併用してください。すべての行の高さをフォントサイズから算出しないでください。 |
| lineHeights.xl | 28px | テキストロールと併用してください。すべての行の高さをフォントサイズから算出しないでください。 |
| lineHeights.xxl | 32px | テキストロールと併用してください。すべての行の高さをフォントサイズから算出しないでください。 |
| lineHeights.xxxl | 44px | テキストロールと併用してください。すべての行の高さをフォントサイズから算出しないでください。 |
### スペーシングの段階

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| space.base | 4 | 一貫したリズムを保つためのテーマのスペーシング値です。 |
| space.xxs | 4px | 一貫したリズムを保つためのテーマのスペーシング値です。 |
| space.xs | 8px | 一貫したリズムを保つためのテーマのスペーシング値です。 |
| space.sm | 12px | 一貫したリズムを保つためのテーマのスペーシング値です。 |
| space.md | 20px | 一貫したリズムを保つためのテーマのスペーシング値です。 |
| space.lg | 32px | 一貫したリズムを保つためのテーマのスペーシング値です。 |
| space.xl | 40px | 一貫したリズムを保つためのテーマのスペーシング値です。 |
| space.xxl | 48px | 一貫したリズムを保つためのテーマのスペーシング値です。 |
### ライトテーマのセマンティックロールマッピング

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| colors.variables.light.background.default | palette.white | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
| colors.variables.light.background.subtle | neutralHue.100 | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
| colors.variables.light.background.danger | dangerHue.100 | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
| colors.variables.light.background.primaryEmphasis | primaryHue.700 | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
| colors.variables.light.foreground.default | neutralHue.900 | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
| colors.variables.light.foreground.subtle | neutralHue.700 | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
| colors.variables.light.foreground.onEmphasis | palette.white | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
| colors.variables.light.foreground.primary | primaryHue.700 | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
| colors.variables.light.foreground.danger | dangerHue.700 | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
| colors.variables.light.border.default | neutralHue.300 | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
| colors.variables.light.border.subtle | neutralHue.200 | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
| colors.variables.light.border.danger | dangerHue.300 | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
| colors.variables.light.border.primaryEmphasis | primaryHue.700 | テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。 |
## Zendesk Garden デザインシステム 完全ガイド

実際のインターフェースで、このデザインシステムを選び、適用し、レビューするための実践ガイドです。

詳しいガイダンス、実装の出発点、ソースへのリンクをまとめています。

## Zendesk Garden デザインシステム サポートワークスペースの構成

### 顧客の問い合わせを表示しておく

> サポート用の返信作成画面では、内容が整っていても質問に沿わない返信にならないよう、十分な文脈を表示する必要があります。この例では、依頼者、組織、トピックとともに、顧客の問い合わせを下書きの上部に配置しています。画面を切り替えずに新しい文章と元の質問を見比べられるよう、適度な情報密度を持たせています。

### 履歴と作成中の下書きを分ける

保存済みのローカル項目は、表示状態を明記して作成欄の上に表示されます。作成中の下書きにはネイティブのTextareaを使用します。保存するとスナップショットが追加され、フィールドがクリアされるため、後からの編集によって以前の保存内容が気付かないうちに書き換わることはありません。

## Zendesk Garden デザインシステムのテーマロールと配色

### カラーをコピーする前にエイリアスを確認する

Garden 9 DEFAULT_THEMEでは、セマンティックロールを色相ファミリーと番号付きパレット値に対応付けています。background.primaryEmphasisのようなロールは、固定の16進カラー値ではありません。カスタムテーマでハードコードされた青色がネイティブコントロールに残らないよう、リファレンステーブルではこれらのエイリアスをそのまま示しています。

### 作成した領域もプロバイダーとの互換性を保つ

ThemeProvider がネイティブコンポーネントのスタイルを提供します。このサンプルでは DEFAULT_THEME と、それに合わせた明るいカスタムワークスペースを使用しています。周囲の背景色しか変わらない見せかけのダークモード切り替えは追加していません。カラースキームに対応する場合は、プロバイダーとあわせてカスタムのメッセージ色とサイドバーの色も切り替えてください。

## Zendesk Garden デザインシステムのタイポグラフィと密度

### 業務で使う14pxの文字を読みやすく保つ

デフォルトテーマには、14pxのミディアムウェイトと行高20pxのロールに加え、補助テキスト用の12pxと見出し用の18pxが用意されています。このサンプルでは、チケットのタイトルに26pxを使い、コンテキストのメタデータはそれより小さくしています。顧客の元のメッセージと保存済みメモには、ラベルのように文字を詰め込まず、通常の本文サイズを使います。

### 長い返信は自然に折り返す

保存したテキストでは改行が維持され、長い単語も折り返されます。そのため、モバイル画面が狭くてもメモ全体を表示でき、横スクロールも発生しません。メッセージ履歴全体を内部スクロール領域にするのではなく、テキストエリアが縦に伸びて入力内容に対応します。

## Zendesk Garden デザインシステムのフィールドとボタンの構成

### ラベル、ヒント、エラーを関連付ける

ネイティブの Field で Label、Hint、Textarea、条件付きの Message をまとめます。記述した最小文字数のルールを満たさない場合、validation プロパティによってテキストエリアの表示が変わります。フィールドの外にある無関係な段落をエラー色にするのではなく、コンポーネントの構成に沿った実装です。

### 公開範囲を個別のコントロールで設定する

ネイティブの Select で「公開返信」または「内部メモ」を選択します。モードに応じてラベルとヒントが切り替わり、保存したスナップショットにも選択したモードが保持されます。どちらの場合もアクションは「ローカルの下書きを保存」のままです。「公開返信」を選んでもメッセージが送信されないことが明確になります。

## Zendesk Garden デザインシステムの下書き状態とローカル履歴

### メッセージを追加する前に入力を検証する

アプリケーションでは、前後の空白を取り除いた文字数が12文字以上であることを求めます。送信に失敗した場合、下書きはそのまま残り、フィールドメッセージが表示されてテキストエリアにフォーカスが移ります。入力を編集すると古いエラーが消え、次回の送信時に最新のテキストが再検証されます。このルールはアプリケーション側の動作であり、Garden の標準仕様として文書化されているものではありません。

### 内部メモを視覚的に区別する

内部メモには、温かみのある入力用背景色と「内部メモの下書き」という明示的なラベルを使用します。公開メッセージには通常の背景面を使います。どちらにも「未送信」と明記します。これにより公開範囲の違いを示しつつ、Zendesk の実際の会話画面を模したり、他の人に何かが届いたと誤解させたりしません。

## Zendesk Garden デザインシステムのレスポンシブな作業領域

### メインの作業の後にコンテキストを配置する

アプリケーションのブレークポイントで、チケットのコンテキストを会話と入力欄の下に移動します。基になるドキュメントの順序は変わりません。スマートフォンでは公開範囲のコントロールが利用可能な幅いっぱいに広がり、ボタンのラベルが圧縮されないようアクション行が折り返されます。

### 適度な角丸と細い区切り線を使う

ネイティブコントロールには、2px、4px、8pxの角丸スケールを適用します。元のメッセージパネルには、控えめな境界線と4pxの角丸を使います。視覚的に強調するのは主要なアクションと入力検証の状態であり、すべてのメッセージに影を付ける必要はありません。

## Zendesk Garden デザインシステムの入力検証とキーボード操作の復帰

### 下書きの一連の操作を確認する

有効な確認では、まず入力に不備がある状態で送信を試し、その後、入力、公開範囲の変更、保存、クリアを行っても、インターフェースが分かりやすいままであることを確認します。ソースでは React ref を使い、エラー発生後またはクリア後にフォーカスを戻します。結果件数はステータス領域で通知されます。

1. 短い下書きを送信し、フィールドのエラーを確認します。

2. 「内部メモ」を選択し、役立つメモを入力して保存します。

3. 後から入力した下書きをクリアし、保存済みのローカルスナップショットが残ることを確認します。

### 読み進めやすい順序を保つ

依頼の後に下書きを配置し、新たに保存したローカルスナップショットは時系列順に並べます。ネイティブボタンにはアクションをテキストで表示します。入力欄にキーボードショートカットや自動送信の動作は隠されておらず、公開範囲の選択にはラベル付きの Select を使います。

## Zendesk Gardenデザインシステム React統合

### 互換性のある世代のパッケージをインストールする

テーマ、ボタン、フォームのパッケージには 9.16.1 を指定し、styled-components と React 18 を使用します。古い世代の Garden パッケージを混在させると、テーマに関する前提が食い違うことがあります。JSX のエントリーポイントにはプロバイダー、フィールドの構成、ローカル状態をすべて含めます。一方、CSS ファイルには独自に定義したレイアウトだけを記述します。

- @zendeskgarden/react-theming 9.16.1

- @zendeskgarden/react-buttons 9.16.1

- @zendeskgarden/react-forms 9.16.1

### 不足しているサービス層だけを拡張する

実際のサポートツールとして機能させるには、認証済みのチケットデータ、権限チェック、送信／下書きの確認済み API処理を追加し、処理中と失敗時の動作も実装してください。それらの応答が用意されるまでは、ローカルスナップショットの仕様を維持してください。フォームの入力検証に通っただけで、ボタンのラベルを「送信」に変更しないでください。

## Zendesk Garden デザインシステムのコンポーネント例

### main.jsx — 動作するサンプル一式

顧客のコンテキストを表示したまま返信を下書きします。以下のソースは、状態管理と入力検証をすべて含む React エントリーポイントです。

```
import React, { useState, useRef } from "react";
import { createRoot } from "react-dom/client";
import { ThemeProvider, DEFAULT_THEME } from "@zendeskgarden/react-theming";
import { Button } from "@zendeskgarden/react-buttons";
import {
  Field,
  Label,
  Textarea,
  Hint,
  Message,
  Select,
} from "@zendeskgarden/react-forms";
import "./garden.css";
function App() {
  const [mode, setMode] = useState("public"),
    [text, setText] = useState(""),
    [error, setError] = useState(false),
    [items, setItems] = useState([]);
  const ref = useRef();
  function submit(e) {
    e.preventDefault();
    if (text.trim().length < 12) {
      setError(true);
      ref.current.focus();
      return;
    }
    setItems([...items, { mode, text: text.trim() }]);
    setText("");
    setError(false);
  }
  return (
    <ThemeProvider theme={DEFAULT_THEME}>
      <main className="garden-workspace">
        <header>
          <span>SUPPORT WORKSPACE / FICTIONAL TICKET</span>
          <h1>Help with an invoice address</h1>
          <p>Ticket #1028 · Nadia Walker · Email channel</p>
        </header>
        <div className="garden-grid">
          <section>
            <div className="message customer">
              <strong>Nadia Walker</strong>
              <small>Customer · example message</small>
              <p>
                Could you update the company address on our next invoice? The
                billing contact has changed.
              </p>
            </div>
            {items.map((i, n) => (
              <article className={"message " + i.mode} key={n}>
                <strong>
                  {i.mode === "public"
                    ? "Public reply draft"
                    : "Internal note draft"}
                </strong>
                <small>Saved locally · not sent</small>
                <p>{i.text}</p>
              </article>
            ))}
            <form onSubmit={submit} noValidate>
              <div className="composer-head">
                <h2>Compose a draft</h2>
                <Field>
                  <Label>Visibility</Label>
                  <Select
                    value={mode}
                    onChange={(e) => setMode(e.target.value)}
                  >
                    <option value="public">Public reply</option>
                    <option value="internal">Internal note</option>
                  </Select>
                </Field>
              </div>
              <Field>
                <Label>
                  {mode === "public" ? "Reply text" : "Internal note"}
                </Label>
                <Hint>
                  {mode === "public"
                    ? "Prepared for the customer; this demo will not send it."
                    : "Internal context for the support team; saved only in this page."}
                </Hint>
                <Textarea
                  ref={ref}
                  value={text}
                  rows={5}
                  validation={error ? "error" : undefined}
                  onChange={(e) => {
                    setText(e.target.value);
                    setError(false);
                  }}
                />
                {error && (
                  <Message validation="error">
                    Write at least 12 characters.
                  </Message>
                )}
              </Field>
              <div className="composer-actions">
                <span>{text.length} characters</span>
                <Button
                  type="button"
                  onClick={() => {
                    setText("");
                    setError(false);
                    ref.current.focus();
                  }}
                >
                  Clear draft
                </Button>
                <Button isPrimary type="submit">
                  Save local draft
                </Button>
              </div>
            </form>
            <p role="status">
              {items.length > 0
                ? `${items.length} draft${items.length === 1 ? "" : "s"} saved locally. No message sent.`
                : ""}
            </p>
          </section>
          <aside>
            <h2>Ticket context</h2>
            <dl>
              <dt>Requester</dt>
              <dd>Nadia Walker</dd>
              <dt>Organization</dt>
              <dd>Northstar Studio</dd>
              <dt>Priority</dt>
              <dd>Normal</dd>
              <dt>Topic</dt>
              <dd>Billing details</dd>
            </dl>
            <div className="context-note">
              <h3>Before replying</h3>
              <ul>
                <li>Confirm the billing contact.</li>
                <li>Keep invoice identifiers out of public examples.</li>
                <li>State whether the change affects future invoices.</li>
              </ul>
            </div>
          </aside>
        </div>
        <footer>
          Native Garden 9.16.1 React components. Original local drafting
          workflow; no Zendesk connection.
        </footer>
      </main>
    </ThemeProvider>
  );
}
createRoot(document.getElementById("root")).render(<App />);
```

コードリファレンス

- Vite React プロジェクトを作成し、<div id="root"></div> を残したまま、これを src/main.jsx として読み込みます。

### garden.css — 元のレスポンシブ構成

ネイティブコンポーネントを基にしたアプリケーションレイアウト。

```
* {
  box-sizing: border-box;
}
body {
  margin: 0;
  font:
    14px/1.5 system-ui,
    sans-serif;
  color: #293239;
  background: #f8f9f9;
}
.garden-workspace header {
  padding: 24px 32px;
  background: white;
  border-bottom: 1px solid #d8dcde;
}
.garden-workspace header span {
  font-size: 10px;
  letter-spacing: 0.08em;
  color: #5c6970;
}
.garden-workspace h1 {
  font-size: 26px;
  line-height: 1.3;
  margin: 8px 0;
}
.garden-workspace header p {
  color: #5c6970;
  margin: 0;
}
.garden-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 280px;
  gap: 24px;
  padding: 24px 32px;
}
.message {
  padding: 20px;
  background: white;
  border: 1px solid #d8dcde;
  border-radius: 4px;
  margin-bottom: 16px;
}
.message p {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  margin: 12px 0 0;
}
.message small {
  display: block;
  color: #5c6970;
  margin-top: 4px;
}
.message.internal {
  background: #fff8ed;
  border-color: #e7ce99;
}
form {
  padding: 24px;
  background: white;
  border: 1px solid #d8dcde;
  border-radius: 4px;
}
.composer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 24px;
}
.composer-head > div {
  max-width: 220px;
}
.garden-workspace h2 {
  font-size: 18px;
  margin: 0 0 12px;
}
.composer-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 12px;
  margin-top: 20px;
}
.composer-actions span {
  font-size: 12px;
  color: #5c6970;
  margin-right: auto;
}
.garden-grid aside {
  background: white;
  border: 1px solid #d8dcde;
  border-radius: 4px;
  padding: 20px;
  align-self: start;
}
dl {
  margin: 0;
}
dt {
  font-size: 12px;
  color: #5c6970;
  margin-top: 16px;
}
dd {
  margin: 4px 0 0;
  font-weight: 600;
}
.context-note {
  margin-top: 24px;
  border-top: 1px solid #e8eaec;
  padding-top: 16px;
}
.context-note h3 {
  font-size: 14px;
}
.context-note ul {
  padding-left: 18px;
  font-size: 12px;
}
.context-note li {
  margin: 8px 0;
}
footer {
  padding: 16px 32px;
  font-size: 12px;
  color: #5c6970;
  border-top: 1px solid #d8dcde;
  background: white;
}
@media (max-width: 850px) {
  .garden-grid {
    grid-template-columns: 1fr;
  }
}
@media (max-width: 550px) {
  .garden-grid {
    padding: 16px;
  }
  .garden-workspace header {
    padding: 20px 16px;
  }
  .composer-head {
    display: block;
  }
  .composer-head > div {
    max-width: none;
  }
  .composer-actions {
    flex-wrap: wrap;
    justify-content: flex-start;
  }
  .composer-actions span {
    width: 100%;
  }
  form {
    padding: 16px;
  }
}
```

コードリファレンス

- main.jsx と同じ場所に保存します。ライブラリのトークンリファレンスとは異なる、カスタムの構成ルールです。

## Zendesk Garden デザインシステムのエージェント設定

### 実装の出発点

バージョンを固定したネイティブのサンプルをバンドルし、ローカルのブラウザーで動作を確認しました。このサンプルでは、アプリケーションのローカルな状態だけを使用します。

```
npm create vite@latest garden-draft -- --template react
cd garden-draft
npm install
npm install react@18.3.1 react-dom@18.3.1 styled-components @zendeskgarden/react-theming@9.16.1 @zendeskgarden/react-buttons@9.16.1 @zendeskgarden/react-forms@9.16.1
# Replace src/main.jsx and add src/garden.css.
npm run dev
```

### あなたのプロジェクト向けプロンプト

```
Garden のネイティブな Field／Label／Hint／Textarea／Message 構成を使って、サポート用の入力画面を作成します。保存する各下書きスナップショットに公開範囲を保持し、メッセージを追加する前に入力を検証してください。顧客のコンテキストを維持し、ローカル保存と送信を明確に区別します。正確なテーマロールとソース全体はこちらです。
```

## Zendesk Garden デザインシステムのソースと対象範囲

OpenDesign のアプリケーションガイド。サンプルの描画には Garden のネイティブコンポーネントを使用します。架空のチケット内容とローカルの下書きは、Zendesk に接続されず、メッセージも送信しません。

- Garden Forms ネイティブの Field、Label、入力検証の構成。

- Garden Buttons アクションのバリエーションと対応サイズ。

- テーマのソース DEFAULT_THEME のエイリアス、パレット、スケール。

## Zendesk Garden デザインシステムの関連リソース

### Adeo Mozaic

Mozaicの16pxマジックユニット、揃えられた48pxコントロール、実際のSCSSインポートとBEMクラスを組み合わせて、実用的な数量コントロールの構成を構築します。棚プランナーによって、上限・下限、型付きエラー、ローカルの資材サマリーを確認できます。

### Adobe Spectrum

選択可能なクリエイティブアセットのテーブルとエクスポートプリセットのインスペクターを通して、React Spectrum v3 を学びます。Provider のテーマと入力スケール、対応しているスタイルプロップ、キー付きコレクション、そして v3 と新しい Spectrum 2 実装との境界を理解します。

### Alaska Airlines Auro

実際のセマンティックカラーとタイプトークン、クラスベースのタイポグラフィ、ネイティブのフライトコンポーネントを通して、Auro の Alaska テーマを探ります。2 件の独自のフライト記録が、航空会社の在庫や予約を表すものではなく、ローカルでの絞り込みと選択を示します。


- [実装リファレンス](https://garden.zendesk.com/components/input/)
- [ソース](https://github.com/zendeskgarden/react-components/tree/main/packages/theming)
- [コードリファレンス](https://garden.zendesk.com/components/input/)
- [Garden Forms ネイティブの Field、Label、入力検証の構成。](https://garden.zendesk.com/components/input/)
- [Garden Buttons アクションのバリエーションと対応サイズ。](https://garden.zendesk.com/components/button/)
- [テーマのソース DEFAULT_THEME のエイリアス、パレット、スケール。](https://github.com/zendeskgarden/react-components/tree/main/packages/theming)
