# Nord 设计系统

## Nord 设计系统 界面预览

从五种房间容量中选择一项，验证标题，并生成本地请求摘要。

## Nord 设计系统 设计参考

Nord 令牌 9.0.4 和当前组件文档。以下数值描述的是默认 Therapy 主题，并非所有 Nordhealth 品牌的主题。公开文档并不授予在 Nordhealth 预期范围之外使用 Nord 的权限。

### Therapy 角色值

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| --n-color-accent | #3559c7 | 主要操作。 |
| --n-color-text | #0c1a3d | 主要内容。 |
| --n-color-text-weak | #36434a | 辅助性文本。 |
| --n-color-background | #fafbfb | 页面。 |
| --n-color-surface | #ffffff | 面板。 |
| --n-color-border | #d8dee4 | 分隔线。 |
| --n-color-border-strong | #bcc5cc | 控件边框。 |
| --n-color-text-error | #d24023 | 错误消息。 |
### 间距

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| --n-space-xs | 4px | 紧密。 |
| --n-space-s | 8px | 相关内容。 |
| --n-space-m | 16px | 分组。 |
| --n-space-l | 24px | 区块。 |
| --n-space-xl | 36px | 大号。 |
| --n-space-xxl | 72px | 主要。 |
### 字体与形状

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| --n-font-size-m | 0.875rem | 正文。 |
| --n-font-size-l | 1rem | 大号文本。 |
| --n-font-size-xl | 1.25rem | 区块标题。 |
| --n-font-size-xxl | 1.5rem | 标题。 |
| --n-line-height | 1.5 | 正文缩放系数。 |
| --n-line-height-form | 20px | 控件行。 |
| --n-font-weight-heading | 600 | 标题。 |
| --n-border-radius-s | 3px | 控件。 |
| --n-border-radius | 5px | 界面表面。 |
### 输入控件约定

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| label / hint / error | Built-in field text | 独立使用的输入框需自行提供标签。 |
| expand | Boolean, default false | 填满父元素宽度。 |
| size | s / m / l | 默认中等尺寸。 |
| readonly versus disabled | Submitted versus excluded | 只读元素仍可获得焦点。 |
| --n-input-inline-size | 240px | 默认固定宽度；响应式表单优先使用 expand。 |
### Select 约定

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| Default slot | Native option elements | 不要臆造 nord-option。 |
| value | String | 受控选择。 |
| required | Boolean | 使用 novalidate 和应用级错误消息。 |
| change | User selection event | 读取 component.value。 |
| focus() | Component method | 等待定义完成后再调用。 |
### 按钮约定

| 名称 / 规则 | 值 / 配置 | 用途 |
| --- | --- | --- |
| type | submit by default | 非提交操作请指定 button。 |
| variant | default / primary / dashed / plain / danger | 每个区段只使用一个主按钮。 |
| href | Creates anchor semantics | 用于导航。 |
| size | s / m / l | 默认中等尺寸。 |
| loading | Busy presentation | 搭配已播报的状态信息使用。 |
## Nord 设计系统 完整指南

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

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

## Nord 设计系统 Nord 是一套内部产品系统，并提供公开参考资料

### 明确标示预期用途

> Nord 的文档介绍了一套为 Nordhealth 产品体验打造的系统。其可公开查看的组件可作为参考，但本示例并不表示品牌或组件条款允许任意商业复用。此处的房间名称和申请流程均为原创演示数据。

默认令牌表代表 Therapy 主题。兽医或医疗应用应选择其预期使用的主题，而不是假定蓝色强调色适用于 Nordhealth 的所有产品。主题选择应由应用层负责。

阅读配套规范

## Nord 设计系统 Therapy 角色让工作区保持克制

### 区分文本、边框和界面表面角色

该示例使用主要文本角色呈现请求详情，使用次要文本角色呈现说明。白色面板位于米白色页面背景之上；更醒目的边框用于标识可编辑字段。错误文本显示在无效标题旁，而不是让整个界面泛红。预览中不包含任何临床或患者信息。

阅读配套规范

## Nord 设计系统 紧凑文本需要足够的行距

### 将文档规定的字号与行高搭配使用

该令牌将 0.875rem 的正文字号与 1.5 的正文行高配对使用，而表单文本则采用独立的 20px 行框。这是两套不同的规则：将表单的数值用于长段落会造成不必要的压缩。在线参考使用 Nordhealth Sans 字体系列令牌；此离线演绎稿特意使用可用的系统字体，不会暗示已提供授权字体。

阅读配套规范

## Nord 设计系统 在应用网格中扩展控件

### 组件不会决定页面断点

Input 的初始内联尺寸变量为 240px。文档规定使用 expand 来占据可用的字段列。我们的示例在桌面端将房间列表放在编辑器旁，在移动端则改为纵向排列；断点由应用决定，并非 Nord 令牌的一部分。选中某一行时，房间名称、容量和可用状态标签仍会显示。

离线演绎稿中的房间列表使用原生单选按钮组。单独提供的库示例使用包含五个选项的 Select。两者都用于选择一个房间，但展示的是不同布局，不能视为相同的组件运行时实现。

阅读配套规范

## Nord 设计系统 为标签和错误消息各指定一个负责人

### 此表单使用独立字段就已足够

Input 或 Select 可以自行提供标签、提示和错误信息。使用较新的 Field 组合模式时，这些职责会由 Field 接管，因此同时重复配置两套内容会产生冗余说明。此示例采用独立组件方案，并在去除首尾空格后的标题为空时设置一条简短错误信息。

禁用字段不会随表单提交，而只读字段会保留相关值，以便聚焦和提交。如果房间标识仍需随请求一并提交，就不要仅为禁止编辑而将其禁用。

- 确保请求标题标签始终可见。

- 提示信息应说明预期内容，不要用它代替标签。

- 将验证消息与无效控件关联起来。

阅读配套规范

## Nord 设计系统 Select 包含普通的 option 元素

### 从宿主组件读取值

默认插槽接受原生 option 元素。每个房间都有稳定的值，以及包含其容量的描述性可见标签。change 事件会通知应用根据宿主组件的值重新计算摘要。此组合中没有自定义的 nord-option 标签。

Nord 建议在选项较多时使用 Select；如果直接展示少量选项很有帮助，则建议使用单选按钮。示例提供五个房间；离线单选按钮样式让容量差异一目了然。

阅读配套规范

## Nord 设计系统 Button 默认行为会影响表单组合

### 明确指定操作、链接和加载状态的语义

Nord Button 的默认类型为 type="submit"。因此，如果表单中的次要预览或类似重置的操作不应提交表单，就需要显式指定 type。为组件设置 href 会将其语义改为链接；导航时应使用这种方式，而不是用点击处理程序模拟锚点。

加载状态会让按钮保持可聚焦，同时阻止重复激活。其旋转指示器对辅助技术隐藏，因此应用必须用文字说明进度。不要一概改用 disabled：操作不可用与操作正在执行，对焦点和反馈的需求不同。

房间请求示例会同步计算草稿，因此不需要加载时段。主按钮会验证标题并读取所选房间；修改任一项都会移除过时的草稿句子。上方的字段和 Select 部分说明了由哪些 Nord API 负责这些输入项。

阅读配套规范

## Nord 设计系统 调用组件方法前，先加载所需的 CSS

### 原型加载与生产环境打包有所不同

官方快速入门将组件模块与 CSS 框架搭配使用。后者提供共享令牌和基础样式。对于经过打包的应用，请安装 @nordhealth/css 和 @nordhealth/components，导入一次 CSS，并且只导入实际使用的组件模块。软件包模块会通过副作用注册其自定义元素。

React 19 可以直接使用这些自定义元素。根据当前指南，较旧的 @nordhealth/react 封装已弃用。服务器端渲染不包含组件的 Shadow DOM；在 Next.js 中导入时需要设置客户端边界。请将这些集成限制与离线 HTML 预览区分开来，后者无需该库即可运行交互。

1. 先加载框架 CSS，再加载组件模块。

2. 初始化时调用 focus 前，先等待 customElements.whenDefined。

3. 添加验证和本地状态处理程序。

4. 在生产环境中打包依赖，不要依赖大量 CDN 模块请求。

阅读配套规范

## Nord 设计系统组件示例

### 完整的独立交互示例

将完整文档保存为 index.html 并在浏览器中打开。这是对 Nord Therapy 设计令牌的离线 HTML/CSS 演绎；原生 Web Component 集成将在另一处展示。

```
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Nord room request interpretation</title><style>*{box-sizing:border-box}body{margin:0;background:#fafbfb;color:#0c1a3d;font:14px/1.5 system-ui,sans-serif}button,input{font:inherit}header{height:52px;background:white;border-bottom:1px solid #d8dee4;padding:0 24px;display:flex;align-items:center;justify-content:space-between}header small{color:#36434a}main{max-width:960px;margin:36px auto;padding:0 24px}h1{font-size:24px;line-height:1.2;margin:0 0 8px}h2{font-size:20px;line-height:1.2;margin:0 0 16px}p{margin:0 0 24px}.muted{color:#36434a}.layout{display:grid;grid-template-columns:310px 1fr;gap:24px}.panel{background:white;border:1px solid #d8dee4;border-radius:5px;padding:24px}fieldset{margin:0;padding:0;border:0;min-width:0}legend{font-weight:600;margin-bottom:16px}.room{display:flex;gap:12px;padding:12px;border:1px solid #d8dee4;border-radius:3px;margin-bottom:8px;cursor:pointer;align-items:center}.room:has(:checked){border-color:#3559c7;background:#f0f4ff}.room input{accent-color:#3559c7}.room span{flex:1}.room small{display:block;color:#36434a}.room b{font-size:12px;font-weight:500}.diagram{height:120px;background:#f6f8f8;display:grid;place-items:center;margin:-24px -24px 24px;border-radius:5px 5px 0 0;border-bottom:1px solid #d8dee4}.table{height:50px;border:2px solid #bcc5cc;border-radius:5px;background:#fff;position:relative;transition:width .2s ease}.chair{position:absolute;width:12px;height:10px;border:1px solid #bcc5cc;background:white;border-radius:3px;top:-16px}.chair.bottom{top:auto;bottom:-16px}label.field{display:block;font-weight:600;margin:16px 0 8px}#title{width:100%;border:1px solid #bcc5cc;border-radius:3px;height:36px;padding:7px 12px;color:inherit;background:white}#title[aria-invalid=true]{border-color:#d24023}.error{color:#d24023;min-height:20px;font-size:12px;margin:4px 0 12px}button{background:#3559c7;color:white;border:1px solid transparent;box-shadow:0 1px 3px #0c0c0c17;border-radius:3px;padding:7px 16px;cursor:pointer}button:focus-visible,input:focus-visible{outline:2px solid #3559c7;outline-offset:3px}.summary{margin-top:24px;background:#f0f4ff;border:1px solid #c6d4f9;padding:16px;border-radius:5px;overflow-wrap:anywhere}.summary:empty{display:none}.boundary{font-size:12px;color:#36434a;margin-top:24px}#selected{font-weight:600}.facts{display:flex;gap:24px;margin-bottom:24px}.facts strong{font-size:20px;display:block}.facts span{font-size:12px;color:#36434a}@media(max-width:650px){main{margin:24px auto;padding:0 16px}.layout{grid-template-columns:1fr;gap:16px}.panel{padding:16px}.diagram{margin:-16px -16px 16px}.room{padding:8px 12px}header{padding:0 16px}header small{display:none}}</style><header><strong>◈ Workplace</strong><small>Room request workspace</small></header><main><h1>A room for your next conversation</h1><p class="muted">Choose a room and prepare a request draft.</p><div class="layout"><section class="panel"><fieldset><legend>Choose a room</legend><div id="rooms"></div></fieldset></section><section class="panel"><div class="diagram" aria-hidden="true"><div class="table" id="table"></div></div><h2 id="selected">Birch</h2><div class="facts"><div><strong id="capacity">4</strong><span>Seats</span></div><div><strong>Draft</strong><span>Request status</span></div></div><form novalidate><label class="field" for="title">Request title</label><input id="title" type="text" aria-describedby="hint error" placeholder="e.g. Design review"><div id="error" class="error" role="alert"></div><p id="hint" class="muted">Use a non-sensitive meeting title. Availability is not checked in this example.</p><button type="submit">Prepare request</button></form><div class="summary" id="result" role="status"></div></section></div><p class="boundary">Independent HTML interpretation of Nord Therapy tokens. Nord is intended for Nordhealth products. This example creates a local draft only; it does not reserve a room.</p></main><script>const rooms=[['Birch',4],['Cedar',6],['Elm',8],['Maple',10],['Pine',12]],field=document.querySelector('#title'),result=document.querySelector('#result');let selected=0;document.querySelector('#rooms').innerHTML=rooms.map(([name,n],i)=>`<label class="room"><input type="radio" name="room" value="${i}" ${i===0?'checked':''}><span>${name}<small>Meeting room</small></span><b>${n} seats</b></label>`).join('');function update(){let [name,n]=rooms[selected];document.querySelector('#selected').textContent=name;document.querySelector('#capacity').textContent=n;let table=document.querySelector('#table');table.style.width=(n*12+44)+'px';table.innerHTML=Array.from({length:n},(_,i)=>`<i class="chair ${i>=n/2?'bottom':''}" style="left:${12+(i%(n/2))*24}px"></i>`).join('');result.textContent=''}document.querySelectorAll('[name=room]').forEach(input=>input.onchange=()=>{selected=Number(input.value);update()});document.querySelector('form').onsubmit=e=>{e.preventDefault();if(!field.value.trim()){document.querySelector('#error').textContent='Enter a request title.';field.setAttribute('aria-invalid','true');field.focus();return}result.textContent='Draft prepared: '+field.value.trim()+' · '+rooms[selected][0]+' · '+rooms[selected][1]+' seats. No room is reserved.'};field.oninput=()=>{field.removeAttribute('aria-invalid');document.querySelector('#error').textContent='';result.textContent=''};update();</script></html>
```

代码参考

- 此示例将房间选项呈现为单选按钮；原生 Nord 示例使用带有普通 option 元素的 Select。两者都不会预留真实房间。

### 带明确验证的房间申请表

独立的 nord-input 和 nord-select 无需可选的 Field 系列组件即可提供标签。提交时会读取组件值，并设置 Input 的 error 属性。

```
<!doctype html>
<html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Room request draft</title>
<link rel="stylesheet" href="https://nordcdn.net/ds/css/5.2.4/nord.min.css">
<script type="module" src="https://nordcdn.net/ds/components/5.3.0/index.js"></script>
<style>main{max-width:560px;margin:auto;padding:var(--n-space-l)}form{display:grid;gap:var(--n-space-l)}</style>
<main><h1>Prepare a room request</h1><p>For an authorized Nordhealth product. Local demonstration only.</p>
<form novalidate>
<nord-input id="request" name="request" label="Request title" hint="Use a non-sensitive meeting title." required expand></nord-input>
<nord-select id="room" name="room" label="Room" value="Birch" expand>
<option value="Birch">Birch · 4 seats</option><option value="Cedar">Cedar · 6 seats</option>
<option value="Elm">Elm · 8 seats</option><option value="Maple">Maple · 10 seats</option><option value="Pine">Pine · 12 seats</option>
</nord-select>
<nord-button type="submit" variant="primary">Prepare request</nord-button>
</form><p id="result" role="status"></p></main>
<script type="module">
await Promise.all(['nord-input','nord-select','nord-button'].map(name=>customElements.whenDefined(name)));
const form=document.querySelector('form'), title=document.querySelector('#request'),room=document.querySelector('#room'),result=document.querySelector('#result');
form.addEventListener('submit',event=>{
 event.preventDefault();title.error=title.value.trim()?'':'Enter a request title.';
 if(title.error){title.focus();return;}
 result.textContent=`Draft: ${title.value.trim()} in ${room.value}. No room is reserved.`;
});
form.addEventListener('input',()=>{result.textContent='';title.error='';});
form.addEventListener('change',()=>{result.textContent='';});
</script></html>
```

代码参考

- 五个房间选项让 Select 成为紧凑实用的选择方式。

- Button 的默认类型为 submit；此示例显式指定了该类型。

- 使用方法前会先等待自定义元素就绪。不会调用任何预订服务。

## Nord 设计系统 Agent 设置

### 实现起点

供获授权的 Nordhealth 用途使用的完整公共 CDN 原型。文档目前指定使用 CSS 5.2.4 和组件 5.3.0。生产环境应打包 npm packages；以下离线视觉演示不会加载这些远程包。

```
<!doctype html>
<html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Room request draft</title>
<link rel="stylesheet" href="https://nordcdn.net/ds/css/5.2.4/nord.min.css">
<script type="module" src="https://nordcdn.net/ds/components/5.3.0/index.js"></script>
<style>main{max-width:560px;margin:auto;padding:var(--n-space-l)}form{display:grid;gap:var(--n-space-l)}</style>
<main><h1>Prepare a room request</h1><p>For an authorized Nordhealth product. Local demonstration only.</p>
<form novalidate>
<nord-input id="request" name="request" label="Request title" hint="Use a non-sensitive meeting title." required expand></nord-input>
<nord-select id="room" name="room" label="Room" value="Birch" expand>
<option value="Birch">Birch · 4 seats</option><option value="Cedar">Cedar · 6 seats</option>
<option value="Elm">Elm · 8 seats</option><option value="Maple">Maple · 10 seats</option><option value="Pine">Pine · 12 seats</option>
</nord-select>
<nord-button type="submit" variant="primary">Prepare request</nord-button>
</form><p id="result" role="status"></p></main>
<script type="module">
await Promise.all(['nord-input','nord-select','nord-button'].map(name=>customElements.whenDefined(name)));
const form=document.querySelector('form'), title=document.querySelector('#request'),room=document.querySelector('#room'),result=document.querySelector('#result');
form.addEventListener('submit',event=>{
 event.preventDefault();title.error=title.value.trim()?'':'Enter a request title.';
 if(title.error){title.focus();return;}
 result.textContent=`Draft: ${title.value.trim()} in ${room.value}. No room is reserved.`;
});
form.addEventListener('input',()=>{result.textContent='';title.error='';});
form.addEventListener('change',()=>{result.textContent='';});
</script></html>
```

### 适用于你项目的提示词

```
使用 Nord Therapy 语义角色和带标签的控件。在响应式应用布局中展开字段。验证去除首尾空格后的请求标题，保留单个选定房间，并且仅显示本地草稿结果。实际实现 Nordhealth 产品时，请遵循文档所述的软件包和主题使用权限。
```

## Nord 设计系统 来源与范围

独立的 OpenDesign 参考。Nord 表示其预期用途是 Nordhealth 产品。本原创的 HTML 演绎既不会预订房间，也不授予品牌或组件的使用权。

- 令牌参考 Therapy 的取值、间距和字体排版。

- Web Components 设置 必需的 CSS、导入项和框架边界。

- 输入 标签、错误和响应式尺寸。

- Select 选项与值处理。

- Button 提交语义和操作变体。

## Nord 设计系统 相关资源

### Oracle Redwood

通过一份完整、可编辑且原创的股票审查工作表，研究 Oracle JET 19 Redwood 的实际配色、语义角色、间距和密度边界。

### Orange OUDS Web

通过完整的响应式对比研究，查看 Orange OUDS 1.4 的实际语义设计令牌、主题软件包和原生 Offcanvas 行为。

### Palantir Blueprint

使用 Blueprint 构建密集的数据工作区：经验证的字体和意图令牌、可选择的数据集表、审核检查器，以及完整的 React 源码。


- [实现参考](https://nordhealth.design/core/tokens/)
- [来源](https://nordhealth.design/core/tokens/)
- [来源](https://nordhealth.design/components/input/)
- [来源](https://nordhealth.design/components/select/)
- [来源](https://nordhealth.design/components/button/)
- [阅读配套规范](https://nordhealth.design/docs/developer/web-components/)
- [阅读配套规范](https://nordhealth.design/core/tokens/)
- [阅读配套规范](https://nordhealth.design/components/input/)
- [阅读配套规范](https://nordhealth.design/components/select/)
- [阅读配套规范](https://nordhealth.design/components/button/)
- [代码参考](https://nordhealth.design/core/tokens/)
- [代码参考](https://nordhealth.design/components/input/)
- [令牌参考 Therapy 的取值、间距和字体排版。](https://nordhealth.design/core/tokens/)
- [Web Components 设置 必需的 CSS、导入项和框架边界。](https://nordhealth.design/docs/developer/web-components/)
- [输入 标签、错误和响应式尺寸。](https://nordhealth.design/components/input/)
- [Select 选项与值处理。](https://nordhealth.design/components/select/)
- [Button 提交语义和操作变体。](https://nordhealth.design/components/button/)
