エンタープライズ製品デザイン · 新しいリソース

REI Cedar デザインシステム.

検証済みのトークン値を使ったCedarの配送方法選択UIを作成してください。Vueのタイルで構成し、キーボードでの完全な操作と、レスポンシブな商品レイアウトを実現します。

OpenDesign ガイド7 章37 件のリファレンス項目オリジナルアプリケーションガイド
01

REI Cedar デザインシステムのインターフェースプレビュー

ネイティブの Cedar タイルを使って、配送または店舗受け取りを選択します。キーボード操作と選択不可のオプションにも対応します。

受け取り方法を選択完全な例を開く
ネイティブの Cedar 17.1.0 / Vue 3 を使用したオリジナル構成。 · 実装リファレンス
02

REI Cedar デザインシステムのデザインリファレンス

@rei/cdr-tokens 14.0.1 の REI テーマから値を抽出し、ネイティブコンポーネントの動作を @rei/cedar 17.1.0 で確認しています。

REI テーマのカラーの役割

ソース
名前 / ルール値 / 設定用途
cdr-color-background-button-primary-rest#1f513f プライマリボタンの背景色。
cdr-color-background-button-primary-hover#c7dfd1 プライマリのホバー時の塗り。
cdr-color-background-primary#ffffff 標準のコンテンツ面。
cdr-color-background-secondary#F4F2ED セカンダリーサーフェス。
cdr-color-text-button-primary#fafbf9 プライマリボタンのラベル。
cdr-color-text-primary#4b4a48 メインテキストの役割。
cdr-color-text-secondary#736e65 補助テキスト。
cdr-color-text-error#811823 エラーメッセージのテキスト。
cdr-color-border-primary#d5cfc3 プライマリ面の境界線。
cdr-color-border-secondary#958e83 セカンダリの境界線の役割。

ルートサイズ 10px での余白と角丸

ソース
名前 / ルール値 / 設定用途
cdr-space-zero0Cedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-space-sixteenth-x0.1remCedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-space-eighth-x0.2remCedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-space-three-sixteenth-x0.3remCedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-space-quarter-x0.4remCedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-space-three-eighth-x0.6remCedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-space-half-x0.8remCedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-space-three-quarter-x1.2remCedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-space-one-x1.6remCedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-space-one-and-a-half-x2.4remCedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-space-two-x3.2remCedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-space-three-x4.8remCedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-space-four-x6.4remCedar のルートでは 1rem は 10px です。これらの値を 16px のルートにそのまま適用しないでください。
cdr-radius-sharp0固定されたトークンパッケージに基づく角の形状。
cdr-radius-soft0.2rem固定されたトークンパッケージに基づく角の形状。
cdr-radius-softer0.4rem固定されたトークンパッケージに基づく角の形状。
cdr-radius-softest0.6rem固定されたトークンパッケージに基づく角の形状。
cdr-radius-round999.9rem固定されたトークンパッケージに基づく角の形状。

フルフィルメントタイル API

ソース
名前 / ルール値 / 設定用途
checkedboolean選択された方法を反映します。
disabledboolean選択不可のオプションです。状態を変更できないようにします。
roleradio | checkboxフルフィルメント方法を1つ選ぶ場合は radio を使用します。
tabindex0 / -1タブストップ1つと矢印キーによる移動は、アプリケーション側で管理します。
header slotmethod label選択肢を示す、読み上げ可能な名前。
body slotsupporting details配送予定または受け取り場所。
footer slotprominent detailコストまたは提供状況。
icon-right slotselection indicatorサンプルでは、選択中の方法にチェックマークを追加しています。
loadingbooleanヘッダーと寸法を維持しながら、本文とフッターをマスクします。
03

REI Cedar デザインシステム完全ガイド

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

DESIGN-rei-cedar.md

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

ガイドをダウンロード

REI Cedar デザインシステムの Vue ランタイムとスタイルの依存関係

コンポーネントとトークンのバージョンを揃える

動作するサンプルでは、@rei/cedar 17.1.0 と @rei/cdr-tokens 14.0.1、Vue 3 を使用します。コンポーネントパッケージには、モジュール単位のエントリーポイントがあります。この例では、CdrButton と CdrFulfillmentTile、およびそれらが内部で使う面、レイアウト、テキストのコンポーネントに必要なCSSのみをインポートします。JavaScriptの動作だけではスタイル適用まで保証されないため、ソースにはすべてのインポートを記載しています。

この OpenDesign ガイドから

プロプライエタリフォントをサンプルに含めない

Cedar のインストールガイドでは、コンポーネントの使用と REI フォントの利用権が区別されています。このサンプルでは、cdr-fonts.css やフォントフェイスを含む統合スタイルシートをインポートしません。インターフェースのテキストにはシステムの sans-serif を、オリジナルのエディトリアル見出しには Georgia を使用します。これらの代替フォントはアプリケーション側の選択であり、REI のブランド書体ではありません。

REI Cedar デザインシステムのトークン単位と界面表面の色

Cedar のルートスケールを使用する

Cedar のトークンでは、16px の余白を 1.6rem と表します。ルートサイズを 10px とすることが前提です。ルートを 16px にすると、同じ値は 25.6px になります。独立したサンプルでは html を 62.5% に設定し、body のサイズを 1.6rem にしています。ルートサイズが異なるホスト製品では、既存サイトにグローバルリセットを貼り付けるのではなく、明確な連携境界を設ける必要があります。

トークンをコンポーネントの役割に対応付ける

プライマリボタンには、通常時に深い緑の塗り、ホバー時に淡い緑の塗りを使用します。コンテンツ面と境界線には、温かみのあるニュートラルカラーを使います。表には、ドキュメントサイトのテーマではなく、REI テーマのセマンティック値を記載しています。図示したバッグにはオリジナルの装飾色を使っており、公式の Cedar トークンの出力値として示すものではありません。

REI Cedar デザインシステムのフルフィルメントタイル構成

タイルごとに変化する選択肢を1つ提示する

フルフィルメントタイルには、方法名、所要時間、コストまたは提供状況をまとめます。別の操作可能なリンクやボタンを含めないでください。サンプルでは、確認アクションを radio グループの外に配置し、選択不可の速達オプションには、常に読み取れる説明を添えています。header、body、footer のスロットによって、情報の階層が明確になります。

境界線以外でも選択状態を示す

選択中の方法には checked=true が設定され、icon-right スロットにチェックマークが表示されます。これにより、控えめな境界線の違いがわかりにくい場合でも、現在の選択肢を判別できます。選択可能な項目をクリックすると選択状態のみが更新され、選択内容の確定は別の確認ステップで行います。無効な方法によってモデルが更新されることはありません。

REI Cedarデザインシステムのプロダクトコンテキストとレスポンシブレイアウト

商品を選択肢の隣に配置する

広い画面では、オリジナルのCSSデイパックのイラストと商品概要を、受け取り方法の選択肢の隣に配置します。商品は架空のもので、配送に関する表示はサンプルであることを明記しています。この構成では、REIの商品写真を流用したり、実在する在庫情報を装ったりせずに、Cedarの温かみのある背景レイヤーを表現しています。

コントロールを縮小せずにレイアウトを組み替える

REI Cedarデザインシステムの選択、キーボード操作、フィードバック

アプリケーション側でラジオボタンの動作を実装する

タイルはラジオボタンのセマンティクスを提供しますが、グループラベル、選択値、フォーカスの管理はアプリケーション側で行います。選択可能な項目のうち、選択中の項目だけをTabキーの移動対象にします。矢印キーで選択可能な項目を順に移動し、HomeキーとEndキーで先頭または末尾の項目を選択します。利用できない速達配送はスキップされます。アクセシビリティ対応をTODOとして残さず、完全なソースに実装しています。

古い確認フィードバックを無効にする

選択内容を確認すると、注文が行われたかのように見せることなく、ローカルなステータスを表示します。選択中のタイルを変更すると、以前の結果はクリアされます。ステータス領域は方法の説明とは分けてあるため、ラジオボタンのアクセシブルネームを変えずに、支援技術からフィードバックを伝えられます。

REI CedarデザインシステムのVue完全実装

同じ画面をネイティブに再現する

ViteのVueプロジェクトを作成して、バージョンを固定したパッケージをインストールし、以下の完全なmain.jsとcedar.cssの例を使用します。ルート要素の名前はrootのままにするか、Viteのテンプレートに合わせてマウント先のセレクターを変更してください。この例ではVueのレンダー関数を使用しているため、読者に明示されていないSFCの前処理はありません。

  1. バージョンを固定したコンポーネントパッケージとトークンパッケージをインストールします。
  2. main.jsからのCSSインポートをすべて残します。
  3. アプリをroot要素にマウントします。
  4. 矢印キーで受け取り方法を変更し、ローカルな結果を確認します。

レイアウトを調べる前にスタイルを確認する

最初に確認するのは、タイルに背景レイヤー、境界線、パディングが適用され、ボタンがCedarのスタイルになっていることです。画面は動作するのに素のテキストのように見える場合は、コンポーネントのCSSとトークンのCSSがインポートされているか確認してください。間隔が大きすぎる場合は、ルートのfont-sizeを調べてください。それぞれ原因が異なるため、対処方法も異なります。

REI CedarデザインシステムのAIエージェントへの引き継ぎと受け入れ基準

連携範囲を明確にする

バージョンを固定したCedarのコンポーネントとトークンパッケージを使用し、独自フォントを使わないVue 3の受け取り方法セレクターをAIエージェントに依頼します。タイルの状態とキーボード操作を正確に指定してください。実際の商品に適用する場合は、架空の所要時間をバックエンドとの契約に置き換え、注文操作を有効にする前に読み込みとエラーを処理してください。

動作とソースをあわせて確認する

ローカルでの検証では、矢印キーによる選択、視認できる選択状態、ローカルな確認表示、古い結果のクリア、狭い画面でのレイアウトを確認します。ダウンロードできるガイドには、プレビューと同じアプリケーションコードが含まれています。ネイティブランタイムで検証しても、サンプルの配送予定が実際の情報になるわけではなく、REIのブランドを再利用する許可が得られるわけでもありません。

  • 利用できない方法は選択できません。
  • 選択を変更すると、以前の確認結果はクリアされます。
  • フォントファイルやサービス呼び出しは不要です。

REI Cedarデザインシステムのコンポーネント例

main.js — Vueの受け取り方法セレクター完全版

ネイティブコンポーネント、ローカル状態、ロービングラジオフォーカス、必要なスタイルのインポートをすべて含みます。

js
import { createApp, h, ref } from "vue";
import CdrButton from "@rei/cedar/CdrButton";
import CdrFulfillmentTile from "@rei/cedar/CdrFulfillmentTile";
import "@rei/cedar/dist/cdr-reset.css";
import "@rei/cedar/dist/style/cdr-button.css";
import "@rei/cedar/dist/style/cdr-fulfillment-title.css";
import "@rei/cedar/dist/style/cdr-surface-selection.css";
import "@rei/cedar/dist/style/cdr-layout.css";

import "@rei/cdr-tokens/css";
import "@rei/cedar/dist/style/cdr-surface.css";
import "@rei/cedar/dist/style/cdr-body.css";
import "@rei/cedar/dist/style/cdr-subheading-sans.css";
import "./cedar.css";
const choices = [
  {
    id: "ship",
    label: "Ship to home",
    detail: "Sample delivery: 3–5 days",
    price: "No delivery charge",
    available: true,
  },
  {
    id: "pickup",
    label: "Pick up nearby",
    detail: "Sample location: North Trail",
    price: "Ready tomorrow",
    available: true,
  },
  {
    id: "express",
    label: "Express delivery",
    detail: "Unavailable for this sample item",
    price: "Choose another method",
    available: false,
  },
];
createApp({
  setup() {
    const selected = ref("ship"),
      result = ref("");
    function choose(id) {
      selected.value = id;
      result.value = "";
    }
    function keyboard(e, id) {
      if (
        [
          "ArrowRight",
          "ArrowDown",
          "ArrowLeft",
          "ArrowUp",
          "Home",
          "End",
        ].includes(e.key)
      ) {
        e.preventDefault();
        const ids = choices.filter((x) => x.available).map((x) => x.id);
        let next =
          e.key === "Home"
            ? ids[0]
            : e.key === "End"
              ? ids.at(-1)
              : ids[
                  (ids.indexOf(id) +
                    (e.key === "ArrowRight" || e.key === "ArrowDown"
                      ? 1
                      : ids.length - 1)) %
                    ids.length
                ];
        choose(next);
        document.getElementById("choice-" + next).focus();
      }
    }
    return () =>
      h("main", [
        h("header", [
          h("p", { class: "eyebrow" }, "OUTDOOR GEAR / ORIGINAL SPECIMEN"),
          h("h1", "Ready for the next trail"),
          h("p", "Choose a fulfillment method for this fictional daypack."),
        ]),
        h("div", { class: "composition" }, [
          h("section", { class: "product", "aria-label": "Sample product" }, [
            h("div", { class: "art", "aria-hidden": "true" }, [
              h("div", { class: "pack" }, [h("i"), h("span"), h("b")]),
            ]),
            h("div", [
              h("h2", "Ridge daypack · 24 L"),
              h("p", "A lightweight everyday pack for short outings."),
              h(
                "p",
                { class: "note" },
                "Illustrated sample product · no inventory or purchase connection",
              ),
            ]),
          ]),
          h("section", { class: "options" }, [
            h(
              "h2",
              { id: "fulfillment-label" },
              "How would you like to receive it?",
            ),
            h(
              "div",
              {
                class: "tiles",
                role: "radiogroup",
                "aria-labelledby": "fulfillment-label",
              },
              choices.map((c) =>
                h(
                  CdrFulfillmentTile,
                  {
                    id: "choice-" + c.id,
                    role: "radio",
                    tabindex: c.available && selected.value === c.id ? 0 : -1,
                    checked: selected.value === c.id,
                    disabled: !c.available,
                    "aria-label": c.label,
                    onClick: () => c.available && choose(c.id),
                    onKeydown: (e) => keyboard(e, c.id),
                  },
                  {
                    header: () => c.label,
                    "icon-right": () =>
                      selected.value === c.id
                        ? h(
                            "span",
                            {
                              "aria-hidden": "true",
                              style: "font-size:2rem;color:#1f513f",
                            },
                            "✓",
                          )
                        : null,
                    body: () => c.detail,
                    footer: () => c.price,
                  },
                ),
              ),
            ),
            h("div", { class: "review" }, [
              h(
                CdrButton,
                {
                  onClick: () => {
                    result.value = `Local selection: ${choices.find((c) => c.id === selected.value).label}. No order has been placed.`;
                  },
                },
                () => "Review selection",
              ),
              h("p", { role: "status", class: "result" }, result.value),
            ]),
          ]),
        ]),
        h(
          "footer",
          "Native Cedar 17.1.0 fulfillment tiles and button. Original composition with system-font fallback; no REI proprietary fonts or photography.",
        ),
      ]);
  },
}).mount("#root");

コードリファレンス

  • index.htmlで<div id="root"></div>を使用します。

cedar.css — オリジナルの商品レイアウト

レスポンシブレイアウト、CSSイラスト、明示的なフォントフォールバック。

CSS
html {
  font-size: 62.5%;
}
body {
  margin: 0;
  color: #2e2e2b;
  background: #fafbf9;
  font:
    1.6rem/1.5 system-ui,
    sans-serif;
}
* {
  box-sizing: border-box;
}
main {
  padding: 3.2rem;
}
header {
  border-bottom: 1px solid #dcd6cb;
  margin-bottom: 3.2rem;
  padding-bottom: 2.4rem;
}
h1 {
  font:
    700 3.6rem/1.1 Georgia,
    serif;
  margin: 1.2rem 0;
}
h2 {
  font:
    700 2.2rem/1.25 system-ui,
    sans-serif;
  margin: 0 0 1.6rem;
}
p {
  margin: 0.8rem 0;
}
.eyebrow,
footer,
.note {
  font-size: 1.4rem;
  color: #4b4a48;
}
.composition {
  display: grid;
  grid-template-columns: 1fr 1.2fr;
  gap: 4.8rem;
}
.product {
  display: grid;
  gap: 2.4rem;
  align-content: start;
}
.art {
  height: 25rem;
  background: #edeae3;
  border-radius: 0.4rem;
  display: grid;
  place-items: center;
}
.pack {
  position: relative;
  width: 12rem;
  height: 17rem;
  border-radius: 4rem 4rem 2rem 2rem;
  background: #48633c;
  border: 0.6rem solid #34492c;
  box-shadow: 2rem 1rem 0 -1.2rem #b3ad9f;
}
.pack i {
  position: absolute;
  top: -2.2rem;
  left: 3.2rem;
  width: 4.4rem;
  height: 2.4rem;
  border: 0.7rem solid #34492c;
  border-bottom: 0;
  border-radius: 1.4rem 1.4rem 0 0;
}
.pack span {
  position: absolute;
  left: 1.2rem;
  right: 1.2rem;
  bottom: 1.2rem;
  height: 7rem;
  border-radius: 1rem;
  background: #607b52;
  border-top: 0.5rem solid #34492c;
}
.pack b {
  position: absolute;
  left: 4.4rem;
  top: 4rem;
  width: 2rem;
  height: 2rem;
  background: #edeae3;
  border-radius: 50%;
}
.tiles {
  display: grid;
  gap: 1.6rem;
}
.tiles > * {
  font-family: system-ui, sans-serif !important;
}
.review {
  margin-top: 2.4rem;
}
.result {
  color: #355e28;
  font-size: 1.4rem;
  margin-top: 1.6rem;
}
footer {
  margin-top: 3.2rem;
  padding-top: 1.6rem;
  border-top: 1px solid #dcd6cb;
}
:focus-visible {
  outline: 3px solid #406eb5;
  outline-offset: 3px;
}
@media (max-width: 700px) {
  main {
    padding: 2rem;
  }
  .composition {
    grid-template-columns: 1fr;
    gap: 3.2rem;
  }
  .product {
    grid-template-columns: 12rem 1fr;
    gap: 1.6rem;
  }
  .art {
    height: 17rem;
  }
  .pack {
    transform: scale(0.7);
  }
  h1 {
    font-size: 2.8rem;
  }
  .product h2 {
    font-size: 1.8rem;
  }
}

コードリファレンス

  • REI独自のフォントファイルはインポートしていません。
04

REI CedarデザインシステムのAIエージェント設定

実装の出発点

プレビューでは、これらのネイティブモジュールをローカルにバンドルしています。フォントにはシステムフォントのフォールバックを使用します。

シェル
npm create vite@latest cedar-study -- --template vue
cd cedar-study
npm install
npm install @rei/[email protected] @rei/[email protected]
# Replace src/main.js and add src/cedar.css with the complete examples.
# Change the index.html mount element to id="root".
npm run dev

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

AI エージェント用プロンプト
この完全なソースを使用して、Cedar 17.1.0とtokens 14.0.1によるVue 3の受け取り方法セレクターを構築します。10pxのルートスケールを分離し、必要なコンポーネントとトークンのCSSをインポートし、独自フォントを使わず、ロービングラジオフォーカスと無効な選択肢を維持してください。実際の在庫連携の仕様が提供されるまでは、架空の在庫状況を使用してください。
05

REI Cedarデザインシステムの情報源と対象範囲

OpenDesignに関するREI Cedarガイド。サンプルではCedar 17.1.0とtokens 14.0.1を使用します。商品、イラスト、店舗、配送に関する情報は架空のものです。REI独自のフォントや写真は含まれていません。