# Kiwi Orbit デザインシステム

## Kiwi Orbit デザインシステムのインターフェースプレビュー

旅行者数と追加オプションを変更して内訳を確認し、選択肢を編集して古い確認内容をクリアします。

## Kiwi Orbitデザインシステムのデザインリファレンス

Native Orbit React コンポーネント 27.7.0（defaultTheme およびコンパイル済み Tailwind CSS）; トークンリファレンス 11.0.0。

### 製品アクションの色

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| buttonPrimaryBackground | #008F7B | 主要アクションの状態リファレンス。ホバー、アクティブ、フォーカスの役割を明確に分けます。 |
| buttonPrimaryBackgroundHover | #007565 | 主要アクションの状態リファレンス。ホバー、アクティブ、フォーカスの役割を明確に分けます。 |
| buttonPrimaryBackgroundActive | #006153 | 主要アクションの状態リファレンス。ホバー、アクティブ、フォーカスの役割を明確に分けます。 |
| buttonPrimaryForeground | #FFFFFF | 主要アクションの状態リファレンス。ホバー、アクティブ、フォーカスの役割を明確に分けます。 |
| buttonPrimaryForegroundHover | #FFFFFF | 主要アクションの状態リファレンス。ホバー、アクティブ、フォーカスの役割を明確に分けます。 |
| buttonPrimaryForegroundActive | #FFFFFF | 主要アクションの状態リファレンス。ホバー、アクティブ、フォーカスの役割を明確に分けます。 |
| buttonPrimaryBorderColorFocus | rgba(0, 143, 123, 0.5) | 主要アクションの状態リファレンス。ホバー、アクティブ、フォーカスの役割を明確に分けます。 |
### コンポーネントの間隔

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| space50 | 2px | 公開済みトークンパッケージで定義された、実際のピクセル単位の間隔値です。 |
| space100 | 4px | 公開済みトークンパッケージで定義された、実際のピクセル単位の間隔値です。 |
| space150 | 6px | 公開済みトークンパッケージで定義された、実際のピクセル単位の間隔値です。 |
| space200 | 8px | 公開済みトークンパッケージで定義された、実際のピクセル単位の間隔値です。 |
| space300 | 12px | 公開済みトークンパッケージで定義された、実際のピクセル単位の間隔値です。 |
| space400 | 16px | 公開済みトークンパッケージで定義された、実際のピクセル単位の間隔値です。 |
| space500 | 20px | 公開済みトークンパッケージで定義された、実際のピクセル単位の間隔値です。 |
| space600 | 24px | 公開済みトークンパッケージで定義された、実際のピクセル単位の間隔値です。 |
| space800 | 32px | 公開済みトークンパッケージで定義された、実際のピクセル単位の間隔値です。 |
| space1000 | 40px | 公開済みトークンパッケージで定義された、実際のピクセル単位の間隔値です。 |
| space1200 | 48px | 公開済みトークンパッケージで定義された、実際のピクセル単位の間隔値です。 |
### 角丸

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| borderRadius50 | 2px | 用途に応じた角丸で、コントロールと大きな旅行情報の背景面を使い分けます。 |
| borderRadius100 | 4px | 用途に応じた角丸で、コントロールと大きな旅行情報の背景面を使い分けます。 |
| borderRadius150 | 6px | 用途に応じた角丸で、コントロールと大きな旅行情報の背景面を使い分けます。 |
| borderRadius200 | 8px | 用途に応じた角丸で、コントロールと大きな旅行情報の背景面を使い分けます。 |
| borderRadius300 | 12px | 用途に応じた角丸で、コントロールと大きな旅行情報の背景面を使い分けます。 |
| borderRadius400 | 16px | 用途に応じた角丸で、コントロールと大きな旅行情報の背景面を使い分けます。 |
| borderRadiusNone | 0 | 用途に応じた角丸で、コントロールと大きな旅行情報の背景面を使い分けます。 |
| borderRadiusFull | 9999px | 用途に応じた角丸で、コントロールと大きな旅行情報の背景面を使い分けます。 |
### 本文の文字スタイル

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| fontSizeTextSmall | 13px | 公開済みの本文スタイルです。ページ独自の見出しはアプリケーション側で構成します。 |
| fontSizeTextNormal | 15px | 公開済みの本文スタイルです。ページ独自の見出しはアプリケーション側で構成します。 |
| fontSizeTextLarge | 16px | 公開済みの本文スタイルです。ページ独自の見出しはアプリケーション側で構成します。 |
| fontSizeTextExtraLarge | 18px | 公開済みの本文スタイルです。ページ独自の見出しはアプリケーション側で構成します。 |
### 製品カラーとニュートラルな背景面

| 名前 / ルール | 値 / 設定 | 用途 |
| --- | --- | --- |
| paletteCloudLight | #F5F7F9 | 落ち着いた背景面と読みやすいテキストで、製品アクションカラーを引き立てます。 |
| paletteCloudNormal | #E8EDF1 | 落ち着いた背景面と読みやすいテキストで、製品アクションカラーを引き立てます。 |
| paletteInkDark | #252A31 | 落ち着いた背景面と読みやすいテキストで、製品アクションカラーを引き立てます。 |
| paletteInkLight | #657890 | 落ち着いた背景面と読みやすいテキストで、製品アクションカラーを引き立てます。 |
| paletteInkNormal | #4F5E71 | 落ち着いた背景面と読みやすいテキストで、製品アクションカラーを引き立てます。 |
| paletteProductLight | #E1F4F3 | 落ち着いた背景面と読みやすいテキストで、製品アクションカラーを引き立てます。 |
| paletteProductNormal | #008F7B | 落ち着いた背景面と読みやすいテキストで、製品アクションカラーを引き立てます。 |
| paletteProductDark | #007061 | 落ち着いた背景面と読みやすいテキストで、製品アクションカラーを引き立てます。 |
## Kiwi Orbitデザインシステム完全ガイド

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

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

## Kiwi Orbitデザインシステムの旅行選択レイアウト

### 追加オプションの前にルートを示す

> ルート概要には、追加手荷物の選択肢の前に、2つの空港コード、都市名、架空の所要時間を表示します。これにより、利用者は追加オプションを比較しながら購入内容を確認できます。点線のコネクターは独自のCSSイラストであり、航空会社のルート図でも、実在するサービスを示すものでもありません。

### 選択肢と合計金額を分けて表示する

片側に搭乗者と手荷物の選択肢を、隣に料金の内訳を配置します。同じ状態から、選択中のコントロールと金額の両方を表示します。スマートフォンでは、概要を選択肢の後に文書順で配置するため、どの入力が合計金額に反映されるのかが明確です。

## Kiwi Orbitデザインシステムの製品カラーとフィードバック

### 主要アクションには製品カラーを使う

トークンパッケージには、ホバー時とアクティブ時で異なる色合いを持つ、緑色の製品アクションカラーが用意されています。推測したブランドカラーに頼らず、リファレンスにはボタンの役割に対応する正確な値を記載します。ニュートラルなクラウドカラーの背景面で選択可能な追加オプションを囲み、確認アクションが埋もれないようにします。

### 結果に即したフィードバックを表示する

ネイティブの成功アラートには「選択内容をローカルで確認しました」と表示し、搭乗者数と合計金額を示します。選択肢が変更されるとアラートは消去されます。そのため、追加オプションを編集した後も、以前の緑色の確認表示が新しい選択内容を検証したかのように残ることはありません。

## Kiwi Orbitデザインシステムのタイポグラフィと価格の階層

### 説明文にはネイティブのテキストスタイルを使う

Orbit では、13px の小サイズと 15px の通常サイズを含む、複数の本文スタイルが用意されています。このサンプルではネイティブの Text コンポーネントと Heading コンポーネントを使い、ルートコードと合計金額は独自に強調しています。ここでは文書化されたフォールバックフォントスタックをブラウザーで使用し、Kiwi.com のブランドフォントを暗黙に読み込むことはありません。

### 金額のそばに単位を表示する

各手荷物料金には「搭乗者1人あたり」と明記します。内訳では、選択した追加オプションごとの料金に搭乗者数を掛け、合計金額を各項目より目立たせます。金額だけでは対象範囲を誤解しやすいため、モバイルでも単位を省略しないでください。

## Kiwi Orbitデザインシステムの角丸と間隔のスケール

### コントロールと大きな背景面を使い分ける

現在の角丸スケールには、2、4、6、8、12、16px の段階と、なし・最大の値があります。作成したルートパネルと概要パネルには12pxの角丸を使い、ネイティブのコントロールにはそれぞれのテーマ規則を適用します。入れ子になったすべての要素に最大の角丸を適用すると、フォームの階層がわかりにくくなります。

### 折り返し時も選択肢の行を保つ

手荷物の行には、ネイティブのチェックボックス、補足の許容量テキスト、料金をまとめて配置します。説明テキストには伸縮可能な幅を与え、料金は読みやすい状態に保ちます。どちらかの主要領域が比較に十分な幅を保てなくなる前に、ページを1列レイアウトに切り替えます。

## Kiwi Orbitデザインシステムのチェックボックスとセレクト

### コンポーネントのラベルと情報フィールドを使う

Checkbox には、公開プロパティを使って表示ラベルと補足情報を渡します。Select にはラベルと、搭乗者1人から4人までの明示的な選択肢を設定します。こうしたネイティブの構成なら、手荷物コントロールを装ったクリック可能な div を使わずに、操作性とラベル付けの動作を保てます。

### 追加オプションを個別に扱う

機内持ち込み手荷物と預け入れ手荷物は、それぞれ独立した真偽値で管理します。一方を選択したときに、もう一方が自動的に解除されることはありません。これは意図的に簡略化したサンプル上の仕様です。実際の航空会社では、相互排他的なバンドルや搭乗者ごとの許容量に応じて、別のデータモデルが必要になる場合があります。

## Kiwi Orbitデザインシステムの選択内容の計算と確認

### 1つの計算式から合計金額を算出する

このサンプルでは、搭乗者数に基本運賃と、選択した1人あたりの追加料金の合計を掛けて計算します。表示中の選択肢とずれる可能性がある、個別に編集可能な合計金額は保存しません。すべての料金と許容量は架空のものであり、現在の Kiwi.com の販売内容ではありません。

### 確認用のスナップショットを記録する

確認時には、搭乗者数、手荷物の選択内容、合計金額をまとめて記録します。いずれかのコントロールを変更すると、そのスナップショットは消去されます。これにより、ローカルでのクリックが予約、決済、リアルタイムの空席確認、確定見積もりを意味するかのように見せることなく、状態の一貫性を示せます。

## Kiwi Orbitデザインシステムのアクセシブルな選択フィードバック

### ラベルと再計算をあわせて確認する

キーボードでもポインターでも、ネイティブのコントロールを使って搭乗者数を選び、どちらかの手荷物オプションを切り替えられます。確認結果はステータス領域に表示されます。任意の手荷物オプションについて、存在しない入力検証を作り出すことはありません。この架空の運賃では、追加オプションをどちらも選択しない状態も正当です。

1. 搭乗者を2人選び、機内持ち込み手荷物を追加してください。

2. 預け入れ手荷物を追加し、内訳の3つの金額を確認してください。

3. ローカルで選択内容を確認した後、選択肢を変更し、以前の成功メッセージが消えることを確認してください。

### 意図しない影響を生まない

フォームの上と合計金額の横に、このページが架空の例であることを説明します。アクション名は「ローカルで選択内容を確認」であり、「購入」や「予約」ではありません。変更はすべてページ内にとどまり、デモに不要な搭乗者の個人情報も求めません。

## Kiwi Orbitデザインシステムのプロバイダーとコンパイル済みスタイル

### 互換性のある安定版リリースを使う

このサンプルでは、コンポーネントのバージョンを27.7.0、トークン参照のバージョンを11.0.0に固定しています。OrbitProvider、パッケージのdefaultTheme、コンパイル済みのlib/tailwind.cssを読み込みます。このスタイルシートを省略すると、Reactツリーがレンダリングされても、ユーティリティベースのコンポーネントスタイルが不完全になります。

- OrbitProviderとパッケージのdefaultTheme。

- components 27.7.0のコンパイル済みlib/tailwind.css。

- パッケージのビルド環境にはNode.js 22以降が必要です。

### デプロイ要件を明確にする

このパッケージにはNode.js 22以降が必要です。付属のViteエントリは、この環境とバージョンを固定したコンポーネントパッケージで再現できます。元のCSSが担当するのは旅行プランの構成のみです。ネイティブコントロールには、公開済みのコンポーネントスタイルとプロバイダーの動作を使用します。

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

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

手荷物を選択して、合計金額の例を確認できます。以下のソースは、すべての状態と検証処理を含むReactエントリ全体です。

```
import React, { useState } from "react";
import { createRoot } from "react-dom/client";
import {
  OrbitProvider,
  Button,
  Checkbox,
  Select,
  Alert,
  Heading,
  Text,
} from "@kiwicom/orbit-components";
import defaultTheme from "@kiwicom/orbit-components/lib/defaultTheme";
import "@kiwicom/orbit-components/lib/tailwind.css";
import "./orbit.css";
function App() {
  const [travellers, setTravellers] = useState("1"),
    [cabin, setCabin] = useState(false),
    [checked, setChecked] = useState(false),
    [saved, setSaved] = useState(null);
  const count = Number(travellers),
    extras = (cabin ? 18 : 0) + (checked ? 32 : 0),
    total = count * (96 + extras);
  function update(fn) {
    fn();
    setSaved(null);
  }
  return (
    <OrbitProvider theme={defaultTheme}>
      <main className="trip">
        <header>
          <Text size="small">ORIGINAL TRAVEL SPECIMEN</Text>
          <Heading as="h1" type="title1">Choose what travels with you</Heading>
          <Text>
            Fictional one-way fare. Prices illustrate the interface, not a
            bookable flight.
          </Text>
        </header>
        <div className="trip-grid">
          <section>
            <div className="route">
              <div>
                <strong>PRG</strong>
                <span>Prague</span>
              </div>
              <div className="route-line">
                <span>1h 45m · direct</span>
                <i></i>
              </div>
              <div>
                <strong>AMS</strong>
                <span>Amsterdam</span>
              </div>
            </div>
            <div className="options">
              <Heading as="h2" type="title3">Travellers and baggage</Heading>
              <Select
                label="Travellers"
                ariaLabel="Travellers"
                value={travellers}
                options={[1, 2, 3, 4].map((n) => ({
                  value: String(n),
                  label: n + " adult" + (n === 1 ? "" : "s"),
                }))}
                onChange={(e) => update(() => setTravellers(e.target.value))}
              />
              <div className="bag-option">
                <div>
                  <Heading as="h3" type="title4">Personal item</Heading>
                  <Text size="small">
                    Fits under the seat · included in this example fare
                  </Text>
                </div>
                <strong>Included</strong>
              </div>
              <div className="bag-option">
                <Checkbox
                  label="Add cabin baggage"
                  info="One 10 kg bag per traveller · fictional allowance"
                  checked={cabin}
                  onChange={(e) => update(() => setCabin(e.target.checked))}
                />
                <strong>
                  €18<span>/ traveller</span>
                </strong>
              </div>
              <div className="bag-option">
                <Checkbox
                  label="Add checked baggage"
                  info="One 20 kg bag per traveller · fictional allowance"
                  checked={checked}
                  onChange={(e) => update(() => setChecked(e.target.checked))}
                />
                <strong>
                  €32<span>/ traveller</span>
                </strong>
              </div>
            </div>
          </section>
          <aside>
            <Heading as="h2" type="title3">Your example selection</Heading>
            <dl>
              <dt>Base fare × {count}</dt>
              <dd>€{96 * count}</dd>
              {cabin && (
                <>
                  <dt>Cabin baggage × {count}</dt>
                  <dd>€{18 * count}</dd>
                </>
              )}
              {checked && (
                <>
                  <dt>Checked baggage × {count}</dt>
                  <dd>€{32 * count}</dd>
                </>
              )}
            </dl>
            <div className="trip-total">
              <span>Total</span>
              <strong>€{total}</strong>
            </div>
            <Text size="small">
              All amounts are illustrative. No payment or reservation will be
              created.
            </Text>
            <Button
              fullWidth
              onClick={() => setSaved({ count, cabin, checked, total })}
            >
              Review local selection
            </Button>
            {saved && (
              <div role="status" className="trip-confirm">
                <Alert type="success" title="Selection reviewed locally">
                  {saved.count} traveller{saved.count === 1 ? "" : "s"} · €
                  {saved.total}. No booking created.
                </Alert>
              </div>
            )}
          </aside>
        </div>
        <footer>
          Native Orbit 27.7.0 components and compiled package styles. Original
          layout and fictional pricing logic by OpenDesign.
        </footer>
      </main>
    </OrbitProvider>
  );
}
createRoot(document.getElementById("root")).render(<App />);
```

コードリファレンス

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

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

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

```
* {
  box-sizing: border-box;
}
body {
  margin: 0;
  background: #f5f7f9;
  color: #252a31;
  font:
    16px/1.5 Arial,
    sans-serif;
}
.trip {
  padding: 32px;
}
.trip header {
  max-width: 760px;
  margin-bottom: 28px;
}
.trip header h1 {
  margin: 8px 0 12px;
}
.trip-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) minmax(280px, 1fr);
  gap: 24px;
}
.route,
.options,
.trip aside {
  background: #fff;
  border-radius: 12px;
  border: 1px solid #e8edf1;
  padding: 24px;
}
.route {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 20px;
}
.route strong {
  font-size: 32px;
  display: block;
}
.route span {
  font-size: 14px;
  display: block;
  color: #4f5e71;
}
.route-line {
  flex: 1;
  text-align: center;
}
.route-line i {
  display: block;
  border-top: 2px dashed #bac7d5;
  margin-top: 12px;
}
.options > h3 {
  margin-bottom: 20px;
}
.options > div:first-of-type {
  margin-bottom: 12px;
}
.bag-option {
  display: flex;
  gap: 20px;
  align-items: center;
  justify-content: space-between;
  padding: 24px 0;
  border-top: 1px solid #e8edf1;
}
.bag-option:last-child {
  padding-bottom: 0;
}
.bag-option > strong {
  white-space: nowrap;
  font-size: 18px;
}
.bag-option > strong span {
  display: block;
  font-size: 12px;
  font-weight: 400;
  color: #657890;
}
.trip aside {
  align-self: start;
}
.trip dl {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  margin: 24px 0;
}
.trip dd {
  margin: 0;
  text-align: right;
  font-weight: 600;
}
.trip-total {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-top: 1px solid #bac7d5;
  padding: 20px 0;
}
.trip-total strong {
  font-size: 32px;
}
.trip aside > button {
  margin-top: 24px;
}
.trip-confirm {
  margin-top: 20px;
}
.trip footer {
  font-size: 12px;
  color: #657890;
  margin-top: 24px;
}
@media (max-width: 900px) {
  .trip-grid {
    grid-template-columns: 1fr;
  }
}
@media (max-width: 550px) {
  .trip {
    padding: 16px;
  }
  .route,
  .options,
  .trip aside {
    padding: 20px;
  }
  .route {
    gap: 12px;
  }
  .route strong {
    font-size: 28px;
  }
  .route-line span {
    font-size: 12px;
  }
  .bag-option {
    align-items: flex-start;
    gap: 12px;
  }
}
```

コードリファレンス

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

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

### 実装の出発点

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

```
npm create vite@latest orbit-trip -- --template react
cd orbit-trip
npm install
npm install react@18.3.1 react-dom@18.3.1 @kiwicom/orbit-components@27.7.0
# Use Node.js >=22. Replace src/main.jsx and add src/orbit.css.
npm run dev
```

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

```
Orbitのネイティブコンポーネントとコンパイル済みスタイルを使って、旅行の追加オプション選択画面を作成します。ルート情報、旅行者ごとの料金、選択したオプション、合計金額に一貫性を持たせます。価格が架空であり、確認処理がローカルで行われることを明示し、編集時には古い確認内容をクリアしてください。予約や決済が可能であるかのような表現は避けてください。
```

## Kiwi Orbitデザインシステムの情報源と適用範囲

OpenDesignのアプリケーションガイド。ルート、所要時間、料金、手荷物許容量は架空のものです。Orbitのネイティブコントロールはローカルで動作し、航空券の検索、予約、決済は行いません。

- Orbit はじめに 現在のコンポーネントとトークンのバージョン、および実装リソース。

- Orbitコンポーネントのソース ネイティブのprops、スタイル、パッケージ要件。

- 固定されたトークンのエクスポート 製品、書体、余白、角丸の正確な値。

## Kiwi Orbitデザインシステムの関連リソース

### Maersk デザインシステム

実際のライトテーマのロール、見出しと本文の文字サイズ、入れ子状の角丸、識別子の扱いを通して、Maerskのオペレーション用インターフェースの表現を確認します。サンプルの貨物検索では、実際の物流データにアクセスできるとは示さず、参照情報との完全一致と、アクセシブルなイベント履歴を紹介します。

### Microsoft Fluent 2

実際のセマンティックトークン、Web 向けのタイポグラフィとスペーシングの段階、制御可能なタブ、検証済みのアクセスダイアログを備えた Fluent UI React v9 のワークスペースを構築します。テーマ値を比較し、コンポーネントの構造を確認して、Reactの完全な例を使う前にローカルで操作を試してください。

### Monday Vibe

Vibe 4のトークンとReactコントロールを使って、実用的なデリバリーボードを構成します。アクションを示すセマンティックカラーとボードラベルの違い、名前付きの余白ステップ、フォントのショートハンド、新しいアプリケーションに必要な明示的なCSSの設定について確認できます。


- [実装リファレンス](https://orbit.kiwi/getting-started/)
- [ソース](https://cdn.jsdelivr.net/npm/@kiwicom/orbit-design-tokens@11.0.0/dist/index.js)
- [コードリファレンス](https://orbit.kiwi/getting-started/)
- [Orbit はじめに 現在のコンポーネントとトークンのバージョン、および実装リソース。](https://orbit.kiwi/getting-started/)
- [Orbitコンポーネントのソース ネイティブのprops、スタイル、パッケージ要件。](https://github.com/kiwicom/orbit)
- [固定されたトークンのエクスポート 製品、書体、余白、角丸の正確な値。](https://cdn.jsdelivr.net/npm/@kiwicom/orbit-design-tokens@11.0.0/dist/index.js)
