01 Nord デザインシステムインターフェースプレビュー 5種類の会議室定員から選び、タイトルを検証して、ローカルでリクエストの概要を作成します。
Nord Therapyトークンをオフライン環境でHTML/CSS向けに解釈した例。ネイティブのWeb Component連携は別途紹介しています。·
実装リファレンス 02
Nord デザインシステムデザインリファレンス Nordのトークン9.0.4と、現行のコンポーネントドキュメントを参照しています。以下の値はデフォルトのTherapyテーマを示すもので、Nordhealthのすべてのブランドに当てはまるわけではありません。公開ドキュメントを参照できることは、Nordを本来のNordhealthの用途以外で使用する許可を意味しません。
名前 / ルール 値 / 設定 用途 --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-xs4px狭い間隔。 --n-space-s8px関連要素。 --n-space-m16pxグループ。 --n-space-l24pxセクション。 --n-space-xl36px大。 --n-space-xxl72px特大。
名前 / ルール 値 / 設定 用途 --n-font-size-m0.875rem本文。 --n-font-size-l1rem大きなテキスト。 --n-font-size-xl1.25remセクションタイトル。 --n-font-size-xxl1.5remタイトル。 --n-line-height1.5本文の倍率。 --n-line-height-form20pxコントロールの行の高さ。 --n-font-weight-heading600見出し。 --n-border-radius-s3pxコントロール。 --n-border-radius5px背景面。
名前 / ルール 値 / 設定 用途 label / hint / errorBuilt-in field textスタンドアロンの入力にはラベルを付ける。 expandBoolean, default false親要素の幅いっぱいに広げる。 sizes / m / lデフォルトは中。 readonly versus disabledSubmitted versus excluded読み取り専用でもフォーカス可能にする。 --n-input-inline-size240pxデフォルトでは幅が固定される。レスポンシブフォームではexpandを優先する。
名前 / ルール 値 / 設定 用途 Default slotNative option elementsnord-optionを独自に作らない。 valueString選択状態を制御する。 requiredBooleannovalidateを使い、エラーはアプリケーション側で表示する。 changeUser selection eventcomponent.valueを読み取る。 focus()Component method呼び出す前に定義の完了を待つ。
名前 / ルール 値 / 設定 用途 typesubmit by default送信以外の操作にはbuttonを指定する。 variantdefault / primary / dashed / plain / danger各セクションでプライマリは1つにする。 hrefCreates anchor semanticsナビゲーションに使う。 sizes / m / lデフォルトは中。 loadingBusy presentation通知されるステータスと組み合わせる。
03 Nord デザインシステム完全ガイド 実際のインターフェースで、このデザインシステムを選び、適用し、レビューするための実践ガイドです。
DESIGN-nordhealth.md 詳しいガイダンス、実装の出発点、ソースへのリンクをまとめています。
ガイドをダウンロード Nord デザインシステム Nordは、公開リファレンスを備えた社内向けプロダクトシステムです 想定される用途を明示する Nordのドキュメントでは、Nordhealthの体験向けに構築されたシステムと説明されています。公開されているコンポーネントは参考になりますが、ブランドやコンポーネントの利用条件が、任意の商用利用を許可するという意味ではありません。ここで使う会議室名とリクエストのワークフローは、説明用に独自に作成したデータです。
デフォルトのトークン表はTherapyを示しています。獣医療または医療のアプリケーションでは、青いアクセントがNordhealthのすべての製品に使われると決めつけず、用途に合ったテーマを選んでください。テーマの選択はアプリケーション側で管理します。
関連する仕様を確認する
Nord デザインシステム Therapyの役割別の値で、ワークスペースを落ち着いた印象にする テキスト、境界線、背景面の役割を分ける このサンプルでは、依頼内容にメインのテキストロール、説明には控えめなロールを使用しています。オフホワイトのページ背景に白いパネルを重ね、編集可能なフィールドはより目立つボーダーで示しています。エラーテキストはインターフェース全体を赤く染めるのではなく、無効なタイトルの横に表示されます。プレビューには臨床情報や患者情報は含まれていません。
関連する仕様を確認する
Nord デザインシステム コンパクトなテキストにも十分な行間を サイズと行間は、仕様どおり組み合わせて使う このトークンでは、本文サイズの0.875remと本文の行の高さ1.5が組み合わされています。一方、フォームのテキストには独立した20pxの行ボックスがあります。これは別々のルールです。フォーム用の値を長い段落に適用すると、必要以上に詰まってしまいます。実際のリファレンスではNordhealth Sansファミリーのトークンを使用しています。このオフライン版では、ライセンス済みフォントが提供されていると誤解させないよう、利用可能なシステムフォントを使用しています。
関連する仕様を確認する
Nord デザインシステム アプリケーションのグリッド内でコントロールを広げる コンポーネントはページのブレークポイントを決めない Inputのインラインサイズは、初期値として240pxの変数が設定されています。利用可能なフィールド列全体に広げるには、仕様で定められたexpandを使います。このサンプルでは、デスクトップでは部屋の一覧をエディターの横に配置し、モバイルでは縦に並べています。このブレークポイントはアプリケーション側の判断であり、Nordのトークンではありません。行を選択しても、部屋名、収容人数、空き状況のラベルは表示されたままです。
オフライン版の部屋選択リストには、ネイティブのラジオグループを使用しています。別途提供されているライブラリの例では、5つの選択肢を持つSelectを使用しています。どちらも部屋を1つ選ぶためのものですが、レイアウトは異なります。同一のコンポーネント実装として示しているわけではありません。
関連する仕様を確認する
Nord デザインシステム ラベルとエラーメッセージの責任範囲を明確にする このフォームには単独のフィールドで十分 InputやSelectは、それぞれラベル、ヒント、エラーを設定できます。新しいFieldのコンポジションを使う場合は、これらの役割をFieldが担います。そのため、両方に設定すると案内が重複します。この例では単独のフィールドを使い、タイトルの前後の空白を取り除いた結果が空の場合に、短いエラーメッセージを1つ表示します。
無効化されたフィールドはフォーム送信から除外されますが、読み取り専用のフィールドは、フォーカスでき、送信時にも値が保持されます。依頼に含める必要がある部屋IDを、編集させないという理由だけで無効化しないでください。
依頼タイトルのラベルは常に表示する。 ヒントは入力内容の説明に使い、ラベルの代わりにしない。 検証メッセージを無効なコントロールに関連付ける。 関連する仕様を確認する
Nord デザインシステム Selectには通常のoption要素を使う 値はホストコンポーネントから取得する デフォルトスロットにはネイティブのoption要素を指定できます。各部屋には固定の値を設定し、収容人数を含む説明的なラベルを表示します。changeイベントを受け取ったアプリケーションは、ホストの値をもとにサマリーを再計算します。この構成では、独自のnord-optionタグは使いません。
Nordでは、選択肢が多い場合はSelect、少数の選択肢をそのまま表示するのが有用な場合はラジオボタンを推奨しています。この例には5つの部屋があります。オフライン版のラジオボタンを使った表示では、収容人数の違いを視覚的に確認できます。
関連する仕様を確認する
Nord デザインシステム Buttonのデフォルト設定はフォームの構成に影響する アクション、リンク、読み込みのセマンティクスを明示する Nord Buttonのtypeのデフォルト値は"submit"です。そのため、フォーム内のプレビューやリセットのような副次的なアクションを送信させたくない場合は、typeを明示する必要があります。コンポーネントにhrefを指定すると、リンクとしてのセマンティクスに切り替わります。アンカーをクリックハンドラーで模倣するのではなく、ナビゲーションにはこの方法を使ってください。
読み込み中もボタンはフォーカス可能な状態に保たれ、連続した操作は防止されます。スピナーは支援技術から隠されるため、アプリケーション側で進行状況を言葉で伝える必要があります。安易にdisabledに置き換えないでください。利用できないアクションと、処理中のアクションでは、フォーカスやフィードバックに求められることが異なります。
部屋の依頼の例では下書きを同期的に計算するため、読み込み時間は必要ありません。メインボタンはタイトルを検証し、選択された部屋を読み取ります。どちらかを編集すると、以前の下書き文は削除されます。各入力を制御するNord APIについては、上のフィールドとSelectのセクションで説明しています。
関連する仕様を確認する
Nord デザインシステム コンポーネントのメソッドを呼び出す前に、必要なCSSを読み込む プロトタイプの読み込みと本番用のバンドルは異なる 公式のクイックスタートでは、コンポーネントモジュールとCSSフレームワークを組み合わせています。後者は共有トークンと基盤スタイルを提供します。バンドルするアプリケーションでは、@nordhealth/cssと@nordhealth/componentsをインストールし、CSSを一度だけインポートして、使用するコンポーネントモジュールのみをインポートしてください。パッケージモジュールは副作用として要素を登録します。
React 19では、これらのカスタム要素を直接使用できます。旧式の@nordhealth/reactラッパーは、現行のガイダンスでは非推奨です。サーバーサイドレンダリングではコンポーネントのShadow DOMは出力されません。Next.jsでインポートする場合は、クライアント境界が必要です。こうした連携上の制約は、ライブラリなしでインタラクションを実行できるオフライン版のHTMLプレビューとは分けて考えてください。
コンポーネントモジュールの前にフレームワークCSSを読み込む。 初期化時にfocusを呼び出す前に、customElements.whenDefinedを待つ。 検証とローカル状態のハンドラーを設定する。 CDNへの多数のモジュールリクエストに頼らず、本番用の依存関係をバンドルする。 関連する仕様を確認する
Nord デザインシステムのコンポーネント例 完全なスタンドアロンのインタラクティブ見本 ドキュメント全体をindex.htmlとして保存し、ブラウザーで開いてください。Nord TherapyのトークンをHTML/CSSでオフライン解釈した例です。ネイティブのWeb Component連携は別途示しています。
html コードをコピー
<!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プロパティを設定します。
html コードをコピー
<!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> コードリファレンス
5つの部屋の選択肢があるため、コンパクトに選べるSelectが便利です。 Buttonのデフォルト値はsubmitです。この例ではtypeを明示しています。 メソッドを使う前にカスタム要素の定義完了を待ちます。予約サービスは呼び出しません。 04
Nord デザインシステム エージェントの設定 実装の出発点 Nordhealthでの使用を許可された方向けの、公開CDNを利用した完全なプロトタイプです。ドキュメントでは現在、CSS 5.2.4およびコンポーネント5.3.0が指定されています。本番環境ではnpmパッケージをバンドルしてください。以下のオフラインでのビジュアル表現では、これらのリモートパッケージを読み込みません。
html サンプルをコピー
<!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> あなたのプロジェクト向けプロンプト AI エージェント用プロンプト プロンプトをコピー
Nord Therapyのセマンティックロールを、ラベル付きのコントロールとともに使用します。レスポンシブなアプリケーションレイアウト内にフィールドを展開します。リクエストのタイトルは前後の空白を除いて検証し、選択できる部屋は1つに限定して、ローカルの下書き結果のみを表示します。実際にNordhealth向けに実装する場合は、ドキュメントに記載されたパッケージとテーマの使用許可に従ってください。 独自のOpenDesignリファレンスです。Nordが想定する用途はNordhealth製品です。この独自のHTML解釈は、部屋の予約を行うものでも、ブランドやコンポーネントの使用権を付与するものでもありません。