旅游出行 · 新资源

Kiwi Orbit 设计系统.

面向旅行场景的 Orbit 指南,采用真实的产品颜色和间距,提供原生行李选项、一致的价格明细,以及完整的本地审核流程。

OpenDesign 指南8 个章节38 条参考条目原始应用指南
01

Kiwi Orbit 设计系统界面预览

更改旅客人数和附加项目,查看费用明细;编辑选项后,清除过时的审核结果。

选择行李并查看示例总价打开完整示例
Native Orbit React 组件 27.7.0,搭配 defaultTheme 和编译后的 Tailwind CSS;令牌参考版本 11.0.0。· 实现参考
02

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 主要操作状态参考。悬停、激活和焦点状态应各自承担不同作用。
buttonPrimaryBorderColorFocusrgba(0, 143, 123, 0.5)主要操作状态参考。悬停、激活和焦点状态应各自承担不同作用。

组件间距

来源
名称 / 规则值 / 配置用途
space502px已发布令牌包中的实际像素间距档位。
space1004px已发布令牌包中的实际像素间距档位。
space1506px已发布令牌包中的实际像素间距档位。
space2008px已发布令牌包中的实际像素间距档位。
space30012px已发布令牌包中的实际像素间距档位。
space40016px已发布令牌包中的实际像素间距档位。
space50020px已发布令牌包中的实际像素间距档位。
space60024px已发布令牌包中的实际像素间距档位。
space80032px已发布令牌包中的实际像素间距档位。
space100040px已发布令牌包中的实际像素间距档位。
space120048px已发布令牌包中的实际像素间距档位。

圆角半径

来源
名称 / 规则值 / 配置用途
borderRadius502px不同的圆角半径适用于控件和较大的旅行信息界面表面。
borderRadius1004px不同的圆角半径适用于控件和较大的旅行信息界面表面。
borderRadius1506px不同的圆角半径适用于控件和较大的旅行信息界面表面。
borderRadius2008px不同的圆角半径适用于控件和较大的旅行信息界面表面。
borderRadius30012px不同的圆角半径适用于控件和较大的旅行信息界面表面。
borderRadius40016px不同的圆角半径适用于控件和较大的旅行信息界面表面。
borderRadiusNone0不同的圆角半径适用于控件和较大的旅行信息界面表面。
borderRadiusFull9999px不同的圆角半径适用于控件和较大的旅行信息界面表面。

正文文字样式

来源
名称 / 规则值 / 配置用途
fontSizeTextSmall13px已发布的正文样式;自定义页面标题由应用组合实现。
fontSizeTextNormal15px已发布的正文样式;自定义页面标题由应用组合实现。
fontSizeTextLarge16px已发布的正文样式;自定义页面标题由应用组合实现。
fontSizeTextExtraLarge18px已发布的正文样式;自定义页面标题由应用组合实现。

产品色与中性色界面表面

来源
名称 / 规则值 / 配置用途
paletteCloudLight#F5F7F9 使用平和的界面表面和清晰易读的文字,衬托产品操作色。
paletteCloudNormal#E8EDF1 使用平和的界面表面和清晰易读的文字,衬托产品操作色。
paletteInkDark#252A31 使用平和的界面表面和清晰易读的文字,衬托产品操作色。
paletteInkLight#657890 使用平和的界面表面和清晰易读的文字,衬托产品操作色。
paletteInkNormal#4F5E71 使用平和的界面表面和清晰易读的文字,衬托产品操作色。
paletteProductLight#E1F4F3 使用平和的界面表面和清晰易读的文字,衬托产品操作色。
paletteProductNormal#008F7B 使用平和的界面表面和清晰易读的文字,衬托产品操作色。
paletteProductDark#007061 使用平和的界面表面和清晰易读的文字,衬托产品操作色。
03

Kiwi Orbit 设计系统完整指南

实用指南,介绍如何为真实界面选择、应用和评审此系统。

DESIGN-kiwi-orbit.md

完整指导、实现起点和源代码链接。

下载指南

Kiwi Orbit 设计系统行程选择布局

先展示行程,再展示附加选项

行程摘要会在行李选项之前显示两个机场代码、城市名称和虚构的行程时长。这样用户比较附加选项时,购买背景信息始终清晰可见。虚线连接线是原创的 CSS 插图,并非航空公司的航线图,也不代表真实服务承诺。

摘自本 OpenDesign 指南

将选项与总价分开展示

旅客人数和行李选项放在一侧,价格明细则显示在旁边。所选控件和金额均由同一状态生成。在手机上,摘要会按文档顺序显示在选项之后,让用户清楚了解哪些输入决定了总价。

Kiwi Orbit 设计系统产品配色与反馈

主要操作使用产品色系

令牌包提供绿色产品操作色,并为悬停和激活状态设置了不同色阶。参考内容列出了按钮对应的精确令牌值,而非依赖臆测的品牌绿。云雾色中性背景衬托可选附加项,同时避免每个面板都与查看操作争夺注意力。

让反馈与结果相对应

原生成功提示会显示“已在本地查看选项”,并列出旅客人数和总价。每当选项发生变化,提示就会清除。因此,之前的绿色确认不会继续显示,造成新编辑的附加选项也已通过验证的错觉。

Kiwi Orbit 设计系统排版与价格层级

使用原生文字样式展示说明文案

Orbit 提供 13px 小号和 15px 常规正文样式,以及更大的字号选项。示例使用原生 Text 和 Heading 组件,行程代码和总价则采用自定义强调样式。此处浏览器使用文档中说明的备用字体栈;不会暗中加载 Kiwi.com 品牌字体。

将单位与金额放在一起

每项行李价格都注明“每位旅客”。价格明细会将所选附加项的单价乘以旅客人数,总价的视觉权重也高于各项明细。在移动设备上仍应保留计价单位,因为醒目却未说明适用范围的大数字很容易被误读。

Kiwi Orbit 设计系统圆角与间距比例

区分控件与较大的界面表面

当前圆角半径比例包含 2、4、6、8、12 和 16px 档位,以及 none 和 full。自定义行程面板和摘要面板使用 12px 圆角,原生控件则保留各自的主题规则。如果所有嵌套元素都使用最大圆角,表单就会失去层次感。

换行时保持选项行完整

Kiwi Orbit 设计系统 受控复选框与选择框

使用组件标签和信息字段

Checkbox 通过公开属性接收可见标签和辅助说明。Select 接收标签以及从一到四位旅客的明确选项。这些原生组件组合保留了交互和标签行为,不会用可点击的 div 假装成行李控件。

分别建模每项附加服务

随身行李和托运行李分别使用独立的布尔值。应用不会暗示选择其中一项就会自动取消另一项。这是一个刻意简化的示例规则;真实航空公司可能提供互斥套餐,或按旅客设置行李额度,届时需要采用不同的数据模型。

Kiwi Orbit 设计系统选择计算与查看

通过一个公式计算总价

示例按旅客人数乘以基础票价与已选的每人附加费用之和。它不会另外存储一个可独立编辑、可能与可见选项不一致的总价。所有价格和额度均为虚构,并非 Kiwi.com 当前提供的产品。

保存查看时的状态快照

查看操作会将旅客人数、行李选项和总价一并保存。更改任何控件都会清除此快照。因此,这个示例展示了状态一致性,但不会把本地点击说成预订、付款、实时余量查询或最终报价。

Kiwi Orbit 设计系统无障碍选项反馈

同时检查标签与重新计算结果

键盘或指针用户都可以使用原生控件选择旅客人数,并切换任一行李选项。查看结果会显示在状态区域中。对于非必选行李,不会伪造验证要求:在这张虚构票价中,两项附加服务都不选也是有效状态。

  1. 选择两位旅客并添加随身行李。
  2. 添加托运行李,并核对明细中的三项金额。
  3. 在本地查看选项,然后更改一项选择,确认之前的成功提示已消失。

避免隐藏后果

页面会在表单上方和总价旁说明示例的虚构性质。操作按钮写的是“查看本地选项”,而非“购买”或“预订”。所有更改都仅在页面内生效;对于不需要个人旅客信息的演示,也不会索取这类信息。

Kiwi Orbit 设计系统 Provider 与编译后的样式

使用匹配的稳定版本

此示例固定使用 React 组件 27.7.0 和令牌引用 11.0.0。它导入 OrbitProvider、软件包的 defaultTheme,以及编译后的 lib/tailwind.css。即使 React 树能够渲染,省略该样式表也会导致依赖工具类的组件样式不完整。

  • OrbitProvider 和软件包的 defaultTheme。
  • 来自 components 27.7.0 的编译后 lib/tailwind.css。
  • 软件包构建环境需要 Node.js 22 或更高版本。

明确说明部署要求

Kiwi Orbit 设计系统组件示例

main.jsx — 完整可运行示例

选择行李并查看示例总价。下方是完整的 React 入口代码,包含所有状态和验证逻辑。

jsx
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 — 原始响应式布局

围绕原生组件构建的应用布局。

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 旁边。这些自定义组合规则有别于库的设计令牌参考。
04

Kiwi Orbit 设计系统 Agent 设置

实现起点

已打包固定的原生示例,并在本地浏览器中完成检查。该示例仅使用本地应用状态。

sh
npm create vite@latest orbit-trip -- --template react
cd orbit-trip
npm install
npm install [email protected] [email protected] @kiwicom/[email protected]
# Use Node.js >=22. Replace src/main.jsx and add src/orbit.css.
npm run dev

适用于你项目的提示词

Agent 提示词
使用 Orbit 原生组件和编译后的样式,构建旅行附加服务选择器。确保路线信息、每位旅客的价格、已选服务和总价保持一致。明确标注虚构价格和本地预览;编辑时清除过期的预览内容,并避免暗示具备预订或支付功能。
05

Kiwi Orbit 设计系统来源与范围

OpenDesign 应用指南。路线、时长、价格和行李额度均为虚构内容。Orbit 原生控件在本地运行;不会执行航班搜索、预订或支付。