カスタマーサービスソフトウェア · 新しいリソース

Zendesk Garden デザインシステム.

実際のテーマエイリアス、タイポグラフィと角丸のスケール、完全な返信作成画面、表示状態に応じたローカル下書き、入力欄の復元機能を備えた、サポート業務向けの Garden ガイド。

OpenDesign ガイド8章42 件の参考エントリーオリジナルアプリケーションガイド
01

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

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

顧客の状況を確認しながら返信を作成完全な例を開く
Garden 9.16.1のネイティブなReactThemeProvider、Buttons、Formsを使用した、独自のローカル下書きワークフロー。· 実装リファレンス
02

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

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

角丸の調整

ソース
名前 / ルール値 / 設定用途
borderRadii.sm2pxコンポーネントの役割に応じて形状を選びます。デフォルトの中程度の角丸はピル型ではありません。
borderRadii.md4pxコンポーネントの役割に応じて形状を選びます。デフォルトの中程度の角丸はピル型ではありません。
borderRadii.lg8pxコンポーネントの役割に応じて形状を選びます。デフォルトの中程度の角丸はピル型ではありません。

レスポンシブブレークポイント

ソース
名前 / ルール値 / 設定用途
breakpoints.xs0pxテーマのブレークポイントです。各段階でアプリケーションのすべての領域が切り替わることを保証するものではありません。
breakpoints.sm576pxテーマのブレークポイントです。各段階でアプリケーションのすべての領域が切り替わることを保証するものではありません。
breakpoints.md768pxテーマのブレークポイントです。各段階でアプリケーションのすべての領域が切り替わることを保証するものではありません。
breakpoints.lg992pxテーマのブレークポイントです。各段階でアプリケーションのすべての領域が切り替わることを保証するものではありません。
breakpoints.xl1200pxテーマのブレークポイントです。各段階でアプリケーションのすべての領域が切り替わることを保証するものではありません。

文字サイズ

ソース
名前 / ルール値 / 設定用途
fontSizes.xs10px本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。
fontSizes.sm12px本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。
fontSizes.md14px本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。
fontSizes.lg18px本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。
fontSizes.xl22px本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。
fontSizes.xxl26px本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。
fontSizes.xxxl36px本文、ラベル、メタデータ、見出しのロールをそれぞれ維持します。

行の高さ

ソース
名前 / ルール値 / 設定用途
lineHeights.sm16pxテキストロールと併用してください。すべての行の高さをフォントサイズから算出しないでください。
lineHeights.md20pxテキストロールと併用してください。すべての行の高さをフォントサイズから算出しないでください。
lineHeights.lg24pxテキストロールと併用してください。すべての行の高さをフォントサイズから算出しないでください。
lineHeights.xl28pxテキストロールと併用してください。すべての行の高さをフォントサイズから算出しないでください。
lineHeights.xxl32pxテキストロールと併用してください。すべての行の高さをフォントサイズから算出しないでください。
lineHeights.xxxl44pxテキストロールと併用してください。すべての行の高さをフォントサイズから算出しないでください。

スペーシングの段階

ソース
名前 / ルール値 / 設定用途
space.base4一貫したリズムを保つためのテーマのスペーシング値です。
space.xxs4px一貫したリズムを保つためのテーマのスペーシング値です。
space.xs8px一貫したリズムを保つためのテーマのスペーシング値です。
space.sm12px一貫したリズムを保つためのテーマのスペーシング値です。
space.md20px一貫したリズムを保つためのテーマのスペーシング値です。
space.lg32px一貫したリズムを保つためのテーマのスペーシング値です。
space.xl40px一貫したリズムを保つためのテーマのスペーシング値です。
space.xxl48px一貫したリズムを保つためのテーマのスペーシング値です。

ライトテーマのセマンティックロールマッピング

ソース
名前 / ルール値 / 設定用途
colors.variables.light.background.defaultpalette.whiteテーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
colors.variables.light.background.subtleneutralHue.100テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
colors.variables.light.background.dangerdangerHue.100テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
colors.variables.light.background.primaryEmphasisprimaryHue.700テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
colors.variables.light.foreground.defaultneutralHue.900テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
colors.variables.light.foreground.subtleneutralHue.700テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
colors.variables.light.foreground.onEmphasispalette.whiteテーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
colors.variables.light.foreground.primaryprimaryHue.700テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
colors.variables.light.foreground.dangerdangerHue.700テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
colors.variables.light.border.defaultneutralHue.300テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
colors.variables.light.border.subtleneutralHue.200テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
colors.variables.light.border.dangerdangerHue.300テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
colors.variables.light.border.primaryEmphasisprimaryHue.700テーマロールのエイリアスです。CSSカラーとして扱うのではなく、選択した色相とパレットに基づいて解決してください。
03

Zendesk Garden デザインシステム 完全ガイド

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

DESIGN-zendesk-garden.md

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

ガイドをダウンロード

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

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

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

この OpenDesign ガイドから

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

保存済みのローカル項目は、表示状態を明記して作成欄の上に表示されます。作成中の下書きにはネイティブの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 プロパティによってテキストエリアの表示が変わります。フィールドの外にある無関係な段落をエラー色にするのではなく、コンポーネントの構成に沿った実装です。

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

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

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

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

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

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

jsx
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 — 元のレスポンシブ構成

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

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 と同じ場所に保存します。ライブラリのトークンリファレンスとは異なる、カスタムの構成ルールです。
04

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

実装の出発点

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

シェル
npm create vite@latest garden-draft -- --template react
cd garden-draft
npm install
npm install [email protected] [email protected] styled-components @zendeskgarden/[email protected] @zendeskgarden/[email protected] @zendeskgarden/[email protected]
# Replace src/main.jsx and add src/garden.css.
npm run dev

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

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

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

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