01Akselデザインシステムのインターフェースプレビュー
数値の待機日数で並べ替え、レコードを選択し、密度を切り替えて、ライト/ダークテーマの役割を比較します。
セマンティックなHTMLを備えたネイティブAksel 8.18.0の表CSSとトークンを使用。ローカルで並べ替え・選択を実装し、Arialを明示的な代替フォントに指定。·
実装リファレンス 02Akselデザインシステムのデザインリファレンス
@navikt/ds-css 8.18.0のネイティブスタイルシートと現行v8ドキュメントを確認しました。ライト/ダークの値はスコープごとに定義されています。プレビューでは外部フォントをArialに置き換え、元のサンプルレコードを使用しています。
| 名前 / ルール | 値 / 設定 | 用途 |
|---|
--ax-font-family | Source Sans 3, Source Sans Pro, Arial, sans-serif | プレビューではArialを代替フォントとして明示的に使用しています。 |
--ax-font-weight-regular / bold | 400 / 600 | 太字を示すトークン名を、font-weight 700と同一視しないでください。 |
--ax-font-size-medium / large | 1rem / 1.125rem | 標準のルートサイズで16px / 18px。 |
--ax-font-size-heading-xlarge / 2xlarge | 2rem / 2.5rem | 32px / 40px。 |
| 名前 / ルール | 値 / 設定 | 用途 |
|---|
--ax-space-8 / 16 / 24 / 32 | 0.5 / 1 / 1.5 / 2rem | トークン名は標準的なピクセル相当値を表します。 |
--ax-radius-2 / 4 / 8 / 12 / 16 | 2 / 4 / 8 / 12 / 16px | 角丸の役割。 |
sm / md / lg / xl / 2xl | 480 / 768 / 1024 / 1280 / 1440px | バージョン指定されたCSSで値を確認しました。 |
| 名前 / ルール | 値 / 設定 | 用途 |
|---|
Medium cell padding | 12px 8px | デフォルトの縦/横パディング。 |
Small / large vertical padding | 4px / 16px | ネイティブの密度修飾子。横方向は8pxのままです。 |
Header divider | 2px | 本文行の区切り線は1pxのままです。 |
| 名前 / ルール | 値 / 設定 | 用途 |
|---|
--ax-bg-default | #fff light / #0e151f dark | ルートの背景。 |
--ax-text-neutral | #202733 light / #dfe1e5 dark | 解決済みのneutral-1000値。 |
--ax-bg-accent-strong | #2176d4 light / #4580ca dark | 解決済みのaccent-600値。コードでは役割を使用してください。 |
03Akselデザインシステム完全ガイド
実際のインターフェースで、このデザインシステムを選び、適用し、レビューするための実践ガイドです。
DESIGN-nav-aksel.md詳しいガイダンス、実装の出発点、ソースへのリンクをまとめています。
ガイドをダウンロードAkselデザインシステム:まずv8の仕様を確認
古いクラスと新しいトークンを混在させないでください
Aksel v8では--ax-*トークンと.akselコンポーネントクラスを使用します。移行ガイドによると、以前の.navdsクラスは動作せず、コンポーネント固有のトークンは削除されています。そのため、古いスクリーンショットをもとに作成したチュートリアルは一見もっともらしく見えても、実装方法の説明に誤りがある可能性があります。
このページではネイティブのCSSを8.18.0に固定し、対応するReactのインストール方法を示します。プレビューでは、調査したネイティブのテーブルクラスと通常のHTMLを使用し、選択と並べ替えはアプリケーションのJavaScriptで管理します。スタイルシートをダウンロードすればReactのTableが生成される、とは説明していません。
関連する仕様を確認する
Akselデザインシステムのタイポグラフィの役割とフォントの読み込み
太字トークンには600を使用
トークンリファレンスでは、フォントファミリーにSource Sans 3、Source Sans Pro、Arial、sans-serifを指定しています。通常は400、太字トークンは600です。本文サイズは14、16、18、20px、見出しの役割には24、28、32、40pxがあります。
ローカルプレビューではフォントトークンにArialを指定し、継承されたフォントの使用を明示的に上書きしているため、外部のフォントを読み込みません。これはフォールバックを選択したことを明示するものであり、ArialがAkselの主要な書体だと主張するものではありません。コンポーネントのテキストサイズはCSSが引き続き指定します。
関連する仕様を確認する
Akselデザインシステムのスペーシング、角丸、レイアウト
ピクセル名のトークンはremに変換される
--ax-space-16は1rem、--ax-space-24は1.5remです。v8のプリミティブでは、名前に対応する構文を使用します。例:padding="space-16"、gap={{xs:"space-8",md:"space-16"}}。移行ガイドを確認せずに、以前の数値指定のプロパティを代わりに使わないでください。
ドキュメントに記載されている角丸の役割には、2、4、8、12、16pxとfullがあります。プレビューではネイティブのテーブル形状を維持し、アプリケーションのコントロールの周囲にspace-24を使用しています。読みやすさを考慮した64remの幅はこのページ独自の設定です。ブレークポイントの値は調査したスタイルシートに基づいています。
関連する仕様を確認する
Akselデザインシステムのテーマに応じて変化するセマンティックカラー
単一のHEX値ではなく、色の役割を維持する
ネイティブのスタイルシートでは、--ax-text-neutralはneutral-1000に対応し、ライトモードでは#202733、ダークモードでは#dfe1e5になります。--ax-bg-defaultは、ライトモードでは白、ダークモードでは#0e151fです。ライトモードの文字色をダークコンテナに固定すると、色の役割に基づくマッピングが機能しなくなります。
プレビューでは.light/.darkテーマクラスを切り替え、テーブルのストライプ、境界線、選択行の色を公式トークンに従わせます。選択状態はチェック済みのチェックボックスと見える件数でも示します。行に色を付けるだけでは、選択インターフェースにはなりません。
関連する仕様を確認する
Akselデザインシステムのセマンティックなテーブル構造
ヘッダーは通常のセルとは異なる
ネイティブのテーブルには、ヘッダー、ボディ、行、ヘッダーセル、データセルにそれぞれ異なるクラスがあります。Reactでは、Table.Header、Table.Body、Table.Row、Table.HeaderCell、Table.DataCellに相当します。参照列は行ヘッダーで、各列ヘッダーにはscope=colを指定します。
キャプションでデータのまとまりを説明します。待機日数は数値なので右揃えにし、参照IDは左揃えのままにします。画面幅が狭い場合は、行をカード状に変えてテーブルの関係性を損なうのではなく、ラベル付きのキーボードフォーカス可能な領域内で横スクロールできるようにします。
- 列見出しと行識別子の両方にヘッダーセルを使用する。
- 郵便番号や識別子ではなく、数量を右揃えにする。
- テーブルに意味のある名前を付けるため、キャプションを指定する。
関連する仕様を確認する
Akselデザインシステムの密度と並べ替え
密度を変更するとパディングが変わる
調査したネイティブのCSSでは、中密度のセルは上下にspace-12、左右にspace-8を使用します。小密度では上下にspace-4、大密度では上下にspace-16を使用します。密度セレクターはネイティブの修飾クラスを切り替えるもので、表示領域に多くの情報を押し込むために本文のフォントサイズを小さくするものではありません。
「待機日数」ヘッダーはネイティブのスタイルに沿った並べ替えボタンです。ハンドラーは数値を並べ替え、該当するヘッダーのaria-sortを更新します。この処理はアプリケーションが担います。ReactのAPIも並べ替えの状態とonSortChangeを提供しますが、任意のドメインレコードを自動的に並べ替えるわけではありません。
関連する仕様を確認する
Akselデザインシステムのキーボード操作に対応した行選択
各行に明示的な操作コントロールを用意する
Tableのドキュメントでは、onRowClickだけではキーボードで操作できないと説明されています。そのため、この例では各参照項目にラベル付きチェックボックスを設け、すべて選択するためのチェックボックスも用意しています。一部の行だけが選択されている場合、全体選択のチェックボックスは不確定状態になります。
並べ替え後も、安定した参照IDを使って選択状態を維持します。順序が変わったときに別のレコードにチェックが移らないよう、現在の行インデックスを選択キーには使いません。選択件数は、丁寧な通知を行うステータス領域で更新します。選択したレコードが外部に送信されることはありません。
関連する仕様を確認する
Akselデザインシステムに対応するCSSとReactを読み込む
パッケージのバージョンを揃える
@navikt/ds-reactと@navikt/ds-cssは同じバージョンでインストールし、アプリケーションのルート付近でCSSを一度だけインポートします。パッケージにはトークンが含まれています。公式のCSSインポートガイドでは、グローバルファイルとコンポーネントファイルを個別に読み込む方法も紹介されていますが、baselineは必須です。また、フォントとトークンを読み込むか、明示的に置き換える必要があります。
AkselはCSSのレイヤーを使用します。コンポーネントのスタイルを意図せず上書きするような、広範囲に適用されるレイヤー外のセレクターは避けてください。アプリケーション独自のレイアウトは、独自のクラスに設定します。単体プレビューではローカルのバージョン固定されたCSSを使用し、フォントを意図的に置き換えています。Reactの例は、ソースを確認済みの別の連携方法です。
- ReactとCSSのパッケージは一緒にバージョンを固定する。
- スタイルシートを一度だけインポートし、セマンティックなTableの子要素をレンダリングする。
- 並べ替えと選択はアプリケーションの状態で管理する。
- テーマ切り替え、キーボード操作、狭い画面でのスクロール領域を確認する。
関連する仕様を確認する
Akselデザインシステムのコンポーネント例
セマンティックなReactのTable
実際のTableの子要素と行ヘッダーを使用し、数量を右揃えにします。
jsx
import { Table } from '@navikt/ds-react';
import '@navikt/ds-css';
export function CaseTable() {
return <Table size="medium" zebraStripes>
<caption>Fictional follow-up records</caption>
<Table.Header><Table.Row>
<Table.HeaderCell scope="col">Reference</Table.HeaderCell>
<Table.HeaderCell scope="col">Next activity</Table.HeaderCell>
<Table.HeaderCell scope="col" align="right">Waiting days</Table.HeaderCell>
</Table.Row></Table.Header>
<Table.Body><Table.Row>
<Table.HeaderCell scope="row">DEMO-204</Table.HeaderCell>
<Table.DataCell>Confirm appointment preference</Table.DataCell>
<Table.DataCell align="right">4</Table.DataCell>
</Table.Row></Table.Body>
</Table>;
}コードリファレンス
現在のレスポンシブプリミティブ構文
プリミティブのプロパティではv8のトークン名を使用する。
jsx
import { HStack, Box } from '@navikt/ds-react';
<HStack gap={{ xs: 'space-8', md: 'space-16' }}>
<Box padding="space-16">First region</Box>
<Box padding="space-16">Second region</Box>
</HStack>コードリファレンス
単体で動作するサンプル一式
レイアウト、操作要素、初期化処理を含むドキュメント全体です。リンク先のサンプルアーカイブを展開すると、このプレビューで使用する正確な相対パスのベンダーアセットが得られます。その後、HTTP経由で配信してください。
html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Aksel table workbench</title><link rel="stylesheet" href="vendor/aksel-8.18.0/index.css"><style>:root{--ax-font-family:Arial,sans-serif}body,body *,body *:before,body *:after{font-family:Arial,sans-serif!important}body{background:var(--ax-bg-default);color:var(--ax-text-neutral);font-size:18px;line-height:1.5}main{max-width:64rem;padding:32px 24px;margin:auto}h1{font-size:32px;font-weight:600;line-height:1.25;margin:16px 0 24px}p{margin:16px 0}.toolbar{display:flex;gap:24px;flex-wrap:wrap;padding:24px;background:var(--ax-bg-sunken);margin:24px 0}select{font-size:16px;padding:8px;background:var(--ax-bg-input);color:var(--ax-text-neutral);border:1px solid var(--ax-border-neutral)}label{font-size:16px;display:flex;gap:8px;align-items:center}.scroll{overflow-x:auto}table{min-width:38rem}caption{text-align:left;font-weight:600;margin-bottom:16px}input[type=checkbox]{width:20px;height:20px;accent-color:var(--ax-bg-accent-strong);cursor:pointer}small{font-size:14px;display:block;margin-top:24px;color:var(--ax-text-neutral-subtle)}:focus-visible{outline:3px solid var(--ax-border-focus);outline-offset:3px}@media(max-width:767px){main{padding:24px 16px}.toolbar{padding:16px;gap:16px}h1{font-size:28px}}</style><body class="light"><main><p>AKSEL v8 · NATIVE TABLE CSS</p><h1>Follow-up record workbench</h1><p>Compare density and theme while sorting and selecting fictional records. Selection follows each reference when the rows move.</p><div class="toolbar"><label>Density <select id="density"><option value="medium">Medium</option><option value="small">Small</option><option value="large">Large</option></select></label><label>Theme <select id="theme"><option value="light">Light</option><option value="dark">Dark</option></select></label></div><p id="selection" role="status">0 records selected</p><div class="scroll" tabindex="0" role="region" aria-label="Fictional follow-up records, horizontally scrollable"><table class="aksel-table aksel-table--zebra-stripes" id="records"><caption>Fictional follow-up records</caption><thead class="aksel-table__header"><tr class="aksel-table__row"><th class="aksel-table__header-cell" scope="col"><input id="all" type="checkbox" aria-label="Select all records"></th><th class="aksel-table__header-cell" scope="col">Reference</th><th class="aksel-table__header-cell" scope="col">Next activity</th><th class="aksel-table__header-cell" id="sort-header" scope="col" aria-sort="ascending"><button id="sort" type="button" class="aksel-table__sort-button">Waiting days ↑</button></th></tr></thead><tbody class="aksel-table__body" id="rows"></tbody></table></div><small>OpenDesign specimen using native Aksel 8.18.0 CSS and an explicit Arial fallback. Fictional data, no NAV identity or external actions.</small></main><script>const data=[{id:'DEMO-204',activity:'Confirm appointment preference',days:4},{id:'DEMO-218',activity:'Read the submitted example note',days:12},{id:'DEMO-231',activity:'Arrange an example callback',days:7}];let ascending=true;const selected=new Set(),all=document.querySelector('#all');function render(){const body=document.querySelector('#rows');body.replaceChildren();for(const r of [...data].sort((a,b)=>ascending?a.days-b.days:b.days-a.days)){const tr=document.createElement('tr');tr.className='aksel-table__row'+(selected.has(r.id)?' aksel-table__row--selected':'');const td=document.createElement('td');td.className='aksel-table__data-cell';const c=document.createElement('input');c.type='checkbox';c.setAttribute('aria-label','Select '+r.id);c.checked=selected.has(r.id);c.onchange=()=>{c.checked?selected.add(r.id):selected.delete(r.id);updateSelection();tr.classList.toggle('aksel-table__row--selected',c.checked)};td.append(c);const th=document.createElement('th');th.scope='row';th.className='aksel-table__header-cell';th.textContent=r.id;const activity=document.createElement('td');activity.className='aksel-table__data-cell';activity.textContent=r.activity;const days=document.createElement('td');days.className='aksel-table__data-cell aksel-table__data-cell--align-right';days.textContent=r.days;tr.append(td,th,activity,days);body.append(tr)}updateSelection()}function updateSelection(){all.checked=selected.size===data.length;all.indeterminate=selected.size>0&&selected.size<data.length;document.querySelector('#selection').textContent=selected.size+' records selected'}all.onchange=()=>{selected.clear();if(all.checked)data.forEach(r=>selected.add(r.id));render()};document.querySelector('#sort').onclick=()=>{ascending=!ascending;document.querySelector('#sort-header').setAttribute('aria-sort',ascending?'ascending':'descending');document.querySelector('#sort').textContent='Waiting days '+(ascending?'↑':'↓');render()};document.querySelector('#density').onchange=e=>document.querySelector('table').className='aksel-table aksel-table--zebra-stripes aksel-table--'+e.target.value;document.querySelector('#theme').onchange=e=>document.body.className=e.target.value;render();</script></body></html>
コードリファレンス
- 完全なサンプルは「ソース」からダウンロードできます。READMEに正確なローカル起動コマンドが記載されています。
- ベンダーのパスはこのドキュメントからの相対パスのままにしてください。アーカイブには、このプレビューで使用するアセット一式が含まれています。
実装の出発点
プレビューではネイティブのCSS 8.18.0をローカルでレンダリングしています。Reactの構成はソースを確認済みですが、個別のビルドは行っていません。バージョンを揃え、v7のnavdsクラスとv8のCSSを組み合わせないでください。「ソース」にある動作するサンプル一式のZIPには、プレビューで使用する正確な依存関係と完全なドキュメントも含まれています。ZIPを展開し、そのディレクトリでpython3 -m http.server 8080を実行してから、http://localhost:8080/nav-aksel.htmlを開いてください。モジュールを使用するサンプルはfile://経由で開かないでください。
bash
npm install @navikt/[email protected] @navikt/[email protected]
# React entry:
# import "@navikt/ds-css";
# import { Table, HStack, Box } from "@navikt/ds-react";あなたのプロジェクト向けプロンプト
AI エージェント用プロンプト
対応する8.18.0のCSS/Reactパッケージを使い、セマンティックなAksel v8テーブルを構築します。キャプション、列見出し、行見出しを維持します。実際のaxトークンとspace-*プリミティブプロパティを使用します。aria-sortによる数値ソート、安定したIDを使ったチェックボックス選択、不確定状態に対応した全選択を実装します。キーボード操作にonRowClickを頼らないでください。ライト/ダークのロールトークンに対応し、狭い画面ではラベル付きの横スクロール領域を設けます。
独立したサンプルレコードであり、NAVのアイデンティティは使用していません。ネイティブのスタイルシートを使い、フォントのフォールバックを明示しています。ソート、選択、レイアウトはアプリケーション側の動作です。実際の成果や事例のデータは表示していません。