行政・公共サービス · 新しいリソース

Suomi.fi デザインシステム.

Source Sans 3と明示的なスペーシングトークンを使い、書類選択から復帰できるパターンを取り入れて、フィンランドの公共サービス向けに読みやすいフォームを作成します。

OpenDesign ガイド8章リファレンス項目 16 件オリジナルアプリケーションガイド
01

Suomi.fi デザインシステム インターフェースのプレビュー

PDFを試し、未対応のファイルを拒否して、選択した書類を削除します。ファイルはブラウザー内に保持されます。

添付ファイルを選択・削除する完全な例を開く
ドキュメントに記載された単一ファイルのパターンをHTML/CSSとして独自に解釈したもの。Arialのフォールバックを使用。 · 実装リファレンス
02

Suomi.fi デザインシステム デザインリファレンス

公式ドキュメント、調査済みのトークンリポジトリ、suomifi-ui-components 18.0.0のメタデータを参照しています。プレビューは独自の解釈であり、ネイティブなReactのランタイムではありません。

タイポグラフィ

ソース
名前 / ルール値 / 設定用途
FamilySource Sans 3バージョン18。バージョン17以前ではSource Sans Proを使用していました。フォントは別途読み込んでください。
Body text18pxモバイルとデスクトップで同じデフォルト値。
Small body16pxテキストのsmallScreen処理であり、ビューポートに応じて自動的に切り替わる設定ではありません。
Lead22px / 20px smallScreen1つのビューにつき導入文は1つにしてください。すべての段落にleadを使わないでください。
Weights300 / 400 / 600コンポーネントパッケージで必要なフォントアセット。

スペーシングと背景レイヤー

ソース
名前 / ルール値 / 設定用途
Space scale5, 10, 15, 20, 25, 30, 40, 60, 80px調査したリポジトリのJSONにあるxxsからxxxxlまで。
Inset scale2, 4, 6, 8, 10, 16, 20pxinsetXxsからinsetXxlまで。外側のスペーシングスケールとは異なります。
Basic radius2pxリポジトリのradius.basic。大きなカードの角丸だと推測しないでください。
Highlight basehsl(212, 63%, 45%)インタラクションに使う標準の青。
Highlight dark 1hsl(212, 63%, 37%)より暗いインタラクション用の役割。
Highlight light 2hsl(212, 63%, 90%)明るい背景レイヤー用の役割。選択したテキストとのコントラストを確認してください。

FileInputのレイアウトと言語

ソース
名前 / ルール値 / 設定用途
Default maximum width600pxコンポーネント固有の幅であり、サイト全体のグリッド幅ではありません。
fullWidthBoolean layout optionフォームで必要な場合は、親要素の幅いっぱいに広げます。
smallScreenExplicit compact presentation optionこのプロパティから、グローバルな自動ブレークポイントを設定しないでください。
Single selectionChosen file replaces picker and drop area複数ファイルの選択は別のパターンで、選択したファイルは下に一覧表示します。
Required copy roleslabelText, hintText, dragAreaText, removeFileText, addedFileAriaText各役割の文言をローカライズしてください。ファイル名だけでは、アクセシブルな読み上げとして不十分です。
03

Suomi.fi デザインシステム 完全ガイド

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

DESIGN-suomi-fi.md

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

ガイドをダウンロード

Suomi.fi デザインシステム 実装の境界

React コンポーネントシステム

Suomi.fiでは、styled-componentsでスタイルを適用したReactのコンポーネントと、別のトークンパッケージを提供しています。バージョン18では、標準フォントがSource Sans 3に変更されています。既存のバージョン17のページでは引き続きSource Sans Proを使用している場合があります。パッケージのバージョンを確認せずにスクリーンショットを比較すると、誤ったタイポグラフィ修正につながる可能性があります。

この OpenDesign ガイドから

埋め込みプレビューは、ドキュメントに記載された単一ファイルのパターンをHTML/CSSとして独自に解釈したものです。以下に、コールバック、制御対象の値、依存関係、フォントのインポートを検証済みの、別個のネイティブなReact FileInputの例を追加しました。どちらも同じローカルなファイル選択タスクを実装しています。ネイティブの例を追加しても、埋め込みのHTMLプレビューが遡ってReactコンポーネントになるわけではありません。

関連する仕様を確認する

Suomi.fi デザインシステム タイポグラフィとフォントの読み込み

読みやすい文章を保つ

モバイルとデスクトップの両方で、ドキュメントに記載された本文サイズ18pxを使用してください。画面幅が狭いからといって、フォームの説明文をすべて小さくしてはいけません。小さなテキスト用のサイズは16pxで、補足情報に使用します。リードテキストは22pxで、コンパクトな処理では20pxにします。ページの導入に限って使用してください。

改行位置を比較する前に、使用するフォントのウェイトを読み込んでください。コンポーネントパッケージではSource Sans 3のアセットを想定していますが、この独立したプレビューでは意図的にArialを使用しています。この置き換えはプレビューの注記に明記し、ネイティブコンポーネントの正確な再現として示してはいけません。

関連する仕様を確認する

Suomi.fi デザインシステム スペーシングと幅

異なる2つのスペーシングスケール

トークンの情報源では、通常のスペーシングとインセットのスペーシングを分けています。調査したJSONでは、通常のlは25pxです。lを32pxとする古いREADMEの例を転用しないでください。インセットは2pxから始まり、異なる間隔で段階的に増加します。スタイルを生成する際は、インストール済みバージョンの実際のエクスポート値を使用してください。

FileInputには、600pxの最大幅とfullWidthオプションがドキュメントに記載されています。これはコンポーネントの制約であり、ページ全体に共通する600pxのコンテナ幅を示すものではありません。書類受付フォームでは、説明文をラベルの近くに保ちつつ、より広いレイアウト内にフィールドを配置できます。

関連する仕様を確認する

Suomi.fi デザインシステム ファイル選択欄の構成

文言もコンポーネントの仕様の一部

表示ラベルでは、必要な書類を明示します。ヒントでは、選択画面を開く前に、対応形式、ファイルサイズ、ファイル数を説明します。ドロップ領域はポインター操作のショートカットを追加しますが、ファイル入力欄の代わりにはなりません。公式ガイドでは、選択コントロールを非表示のネイティブファイル入力欄のラベルとして説明しています。

単一ファイルモードでは、ファイルを選択すると、選択欄とドロップ領域がその書類に置き換わります。書類の横に、わかりやすい削除操作を配置してください。複数ファイルモードでは別のリスト形式を使います。単一ファイルの選択欄に、追加のファイルを暗黙に追加しないでください。

  • labelText:単に「アップロード」とするのではなく、提出を求める証拠書類や文書の名前を示します。
  • removeFileText:ファイルの削除操作だと文脈からわかるようにします。
  • addedFileAriaText:ファイル名を読み上げる前に、選択内容を伝えます。

関連する仕様を確認する

Suomi.fi デザインシステム 選択と復旧

ローカルな添付ファイルの状態遷移

この例では、5,000,000バイト以下のPDFを1つ受け付けます。これらは、このワークショップのシナリオ向けに設定したアプリケーションのルールです。パッケージの既定値でも、Suomi.fiの公式アップロードポリシーでもありません。ブラウザーのacceptによるフィルタリングはファイル選択画面へのヒントにすぎません。この例では、選択またはドロップされた後にファイル名とサイズを個別に検証します。

メタデータが無効でもファイル選択欄は使用でき、再試行方法が表示されます。有効なファイルを選ぶと、その名前をtextContentで表示し、バイト数を通知して、フォーカスを削除コントロールに移します。削除すると元の入力値がクリアされ、ファイル選択欄が再表示されてフォーカスが戻るため、同じファイルをもう一度選択できます。

  1. ファイルを1つだけ選択またはドロップします。複数のファイルは、専用のメッセージを表示して拒否します。
  2. この例のローカルルールに照らして確認し、エラーまたは選択したファイル名を通知します。
  3. 添付ファイルを削除し、元の選択方法を再表示します。

関連する仕様を確認する

Suomi.fi デザインシステム ネイティブ連携

依存関係のバージョンを揃えてインストールする

公開されているバージョン18.0.0のFileInput実装では、onChangeにReactのchangeイベントではなくFileListが渡されます。制御対象のvalueはファイル項目オブジェクトの配列です。この例では、受け付けた各Fileを{ file }に変換します。組み込みの削除操作でリストが変わった場合も同じコールバックが実行されるため、空のFileListを受け取ると制御対象の配列がクリアされます。これらの仕様は、公開済みのdist/esm/core/Form/FileInput/FileInput.jsモジュールで確認しました。

最初のレンダーからvalueを制御するため、空の配列で初期化します。受け取ったFileListを配列に変換する前に検証してください。この例では、ファイル名が.pdfで終わらないファイル、またはサイズが5,000,000バイトを超えるファイルを拒否し、拒否時に選択をクリアします。これらはこの例固有のルールであり、セキュリティチェックでもSuomi.fiのポリシーでもありません。実際にアップロードを受け付ける前に、サーバー側でコンテンツを検証する必要があります。

以下のネイティブ例では、Source Sans 3のウェイト400と600を読み込み、明示的に指定したルート要素にReactをマウントし、ライブラリ経由でstyled-componentsを使用します。tslibを明示的に含めてください。18.0.0のESMモジュールはそのヘルパーをインポートしており、この依存関係がないとクリーンビルドに失敗しました。以下の固定バージョン構成には、不足していたランタイムとフォントアセットが含まれています。このデフォルトテーマの例に、追加のテーマプロバイダーは必要ありません。

関連する仕様を確認する

検証済みのトークンエクスポートを使う

公式のスタイルガイドでは、suomifiDesignTokens.spacingとsuomifiDesignTokens.colorsが紹介されています。以下の例では、カスタムラッパーにこれらのエクスポートパスを使用します。FileInput内部の実装を置き換えるものではありません。

tsx
import { suomifiDesignTokens } from 'suomifi-design-tokens';
// Real exported token paths. Use values instead of copying README example numbers.
const attachmentStyle = {
  maxWidth: 600,
  padding: suomifiDesignTokens.spacing.m,
  borderColor: suomifiDesignTokens.colors.highlightBase
};

コードリファレンス

関連する仕様を確認する

Suomi.fi デザインシステム アクセシビリティとレスポンシブ対応

ドラッグせずにフィールドを操作する

ドロップ領域を目立たせる場合でも、キーボードで操作できるネイティブのファイル入力を維持してください。aria-describedbyでヒントとエラーを関連付けます。ページ全体を読み上げ直すことなく、選択内容の変更と削除を通知してください。フォーム内に削除ボタンが複数ある可能性がある場合は、どのファイルを削除するボタンなのかを明確にしてください。

公式のsmallScreen propを使うと、コンパクトな表示にできます。グローバルなブレークポイントが設定されるわけではありません。この独立したプレビューでは、本文の文字サイズを18pxに保ちながら、アプリケーション固有の調整として480pxでパディングを変更しています。長いファイル名、ズーム、翻訳済みラベルをテストしてください。ファイル名は折り返し、ページ全体の幅が広がらないようにします。

関連する仕様を確認する

Suomi.fi デザインシステム 本番環境での責任

ファイルを選択しても、アップロードされたことにはならない

このデモは文書の内容を読み取らず、リクエストも送信しません。選択したファイル名とバイト数だけでは、文書が有効であること、保存されたこと、または受け付けられたことは確認できません。実際のサービスには、サーバー側での検証、アップロードの進捗表示、復旧可能なエラー処理、保持ルール、実際の応答に基づく確認が必要です。

コンポーネントのコードはMITライセンスです。このコードライセンスは、独立したプロジェクトが自らをフィンランド政府のサービスとして示したり、使用が制限された公的機関の識別情報を使ったりすることを許可するものではありません。実験では中立的なプロジェクト名を使い、公式実装には適切なブランディングガイドラインを確認してください。

関連する仕様を確認する

Suomi.fi デザインシステムのコンポーネント例

公式のトークンエクスポートを使う

カスタムラッパー向けに検証済みのスペーシングとカラーのエクスポートパス。

tsx
import { suomifiDesignTokens } from 'suomifi-design-tokens';
// Real exported token paths. Use values instead of copying README example numbers.
const attachmentStyle = {
  maxWidth: 600,
  padding: suomifiDesignTokens.spacing.m,
  borderColor: suomifiDesignTokens.colors.highlightBase
};

コードリファレンス

ファイルの選択と削除(1ファイル)

ローカルでの処理を一通り示す例です。PDFとサイズの制限はシナリオ上の設定であり、アップロードは行いません。

html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Attachment example</title><style>*{box-sizing:border-box}body{margin:0;padding:30px 20px;font:18px/1.5 Arial,sans-serif;color:#202020;background:#fff}main{max-width:600px;margin:auto}h1{font-size:32px;line-height:1.2;font-weight:400;margin:0 0 20px}p{margin:0 0 20px}label{font-weight:600;display:block}small{display:block;font-size:16px}.drop{margin-top:15px;border:2px dashed hsl(212,63%,45%);padding:30px;text-align:center;background:hsl(212,63%,90%)}button,input::file-selector-button{font:600 18px Arial;padding:12px 20px;border:1px solid hsl(212,63%,37%);border-radius:2px;background:hsl(212,63%,45%);color:white;cursor:pointer}button:focus-visible,input:focus-visible{outline:3px solid #202020;outline-offset:3px}input{width:100%;font-size:16px;margin:15px 0}input::file-selector-button{margin-right:10px}.file{border:1px solid #777;padding:20px;margin:20px 0;overflow-wrap:anywhere}.file button{margin-top:15px;background:white;color:hsl(212,63%,37%)}#error{color:#a32020;font-weight:bold}footer{font-size:14px;margin-top:30px;border-top:1px solid #ccc;padding-top:15px}[hidden]{display:none!important}@media(max-width:480px){body{padding:20px 15px}.drop{padding:20px}h1{font-size:28px}}</style><main><small>COMMUNITY WORKSHOP · ATTACHMENT</small><h1>Add your project outline</h1><p>Choose one PDF up to 5 MB. This local example checks file metadata; it does not read or send the document.</p><div id="picker"><label for="file">Project outline</label><small id="hint">One PDF file. Maximum 5 MB (5,000,000 bytes).</small><input id="file" type="file" accept=".pdf,application/pdf" aria-describedby="hint error"><div class="drop" id="drop">Or drop one PDF here</div></div><p id="error" role="alert" hidden></p><section id="selected" class="file" hidden aria-label="Selected attachment"><strong id="name"></strong><small id="size"></small><button id="remove" type="button">Remove file</button></section><p id="status" role="status">No file selected.</p><footer>OpenDesign interpretation of the Suomi.fi attachment pattern. Arial fallback; no official identity or React component runtime. PDF and 5 MB are example rules.</footer></main><script>const input=document.querySelector('#file'),picker=document.querySelector('#picker'),selected=document.querySelector('#selected'),error=document.querySelector('#error'),status=document.querySelector('#status');function choose(files){error.hidden=true;if(files.length!==1){error.textContent='Choose exactly one file.';error.hidden=false;input.value='';return}const file=files[0];if(!/\.pdf$/i.test(file.name)||file.size>5000000){error.textContent='Choose a PDF no larger than 5 MB.';error.hidden=false;input.setAttribute('aria-invalid','true');input.value='';return}input.removeAttribute('aria-invalid');document.querySelector('#name').textContent=file.name;document.querySelector('#size').textContent=file.size.toLocaleString('en')+' bytes · selected locally';document.querySelector('#remove').setAttribute('aria-label','Remove '+file.name);picker.hidden=true;selected.hidden=false;status.textContent='Selected file: '+file.name;document.querySelector('#remove').focus()}input.addEventListener('change',()=>{if(input.files.length)choose(input.files)});document.querySelector('#drop').addEventListener('dragover',e=>e.preventDefault());document.querySelector('#drop').addEventListener('drop',e=>{e.preventDefault();choose(e.dataTransfer.files)});document.querySelector('#remove').onclick=()=>{input.value='';picker.hidden=false;selected.hidden=true;error.hidden=true;input.removeAttribute('aria-invalid');status.textContent='File removed. Choose another file.';input.focus()};</script></html>

コードリファレンス

  • ネイティブのReactコンポーネントではありません。
  • 本番サービスでは、サーバー側でファイルの内容を検証してください。

検証を制御するネイティブのFileInput

main.jsxとして保存してください。以下の3ファイルとセットアップコマンドで、ネイティブのReactの例を再現できます。

jsx
import React, { useState } from 'react';
import { createRoot } from 'react-dom/client';
import { FileInput } from 'suomifi-ui-components';
import '@fontsource/source-sans-3/400.css';
import '@fontsource/source-sans-3/600.css';
import './app.css';
function App() {
  const [value, setValue] = useState([]);
  const [error, setError] = useState('');
  function change(files) {
    const next = Array.from(files);
    const invalid = next.length > 1 || next.some(file => !/\.pdf$/i.test(file.name) || file.size > 5000000);
    if (invalid) {
      setValue([]);
      setError('Choose one PDF no larger than 5 MB.');
      return;
    }
    setValue(next.map(file => ({ file })));
    setError('');
  }
  return <main><h1>Select a workshop document</h1><p>This local example does not upload or read the document.</p>
    <FileInput id="document" labelText="Workshop document" hintText="One PDF, maximum 5 MB (5,000,000 bytes)."
      inputButtonText="Choose PDF" dragAreaText="or drop a PDF here" removeFileText="Remove file"
      addedFileAriaText="Selected file" accept=".pdf" value={value} onChange={change}
      status={error ? 'error' : 'default'} statusText={error} />
    <p role="status">{value.length ? `${value[0].file.name} selected locally.` : 'No file selected.'}</p>
  </main>;
}
createRoot(document.getElementById('root')).render(<App />);

コードリファレンス

  • 検証はアプリケーション側で行います。ネイティブコンポーネントは、選択、削除、アクセシブルなファイルコントロールを提供します。

ネイティブ例のページレイアウト

app.cssとして保存してください。以下の3ファイルとセットアップコマンドで、ネイティブのReactの例を再現できます。

CSS
body{margin:0;font:18px/1.5 'Source Sans 3',sans-serif;color:#292929;background:#fff}main{max-width:600px;margin:0 auto;padding:24px}h1{font-size:32px;line-height:1.2}*{box-sizing:border-box}

コードリファレンス

  • 検証はアプリケーション側で行います。ネイティブコンポーネントは、選択、削除、アクセシブルなファイルコントロールを提供します。

ネイティブ例のマウントと出力アセット

index.htmlとして保存してください。以下の3ファイルとセットアップコマンドで、ネイティブのReactの例を再現できます。

html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Native Suomi.fi FileInput</title><link rel="stylesheet" href="./app.css"><div id="root"></div><script type="module" src="./app.js"></script></html>

コードリファレンス

  • 検証はアプリケーション側で行います。ネイティブコンポーネントは、選択、削除、アクセシブルなファイルコントロールを提供します。
04

Suomi.fi デザインシステム エージェントのセットアップ

実装の出発点

ローカルのSource Sans 3フォントファイルを含む、以下のネイティブReactの例をビルドします。390pxと1440pxで、無効な形式、有効なファイルの選択、組み込みの削除、サイズ超過のPDFをテストしました。既存のダウンロード可能なプレビューZIPは、別のHTML/CSSによる解釈です。READMEの内容は引き続き正確です。

bash
npm install --save-exact [email protected] [email protected] [email protected] [email protected] [email protected] @fontsource/[email protected]
npm install --save-dev --save-exact [email protected]
# Save main.jsx, app.css and index.html from the complete examples below.
npx esbuild main.jsx --bundle --outdir=dist --entry-names=app --loader:.woff=copy --loader:.woff2=copy
cp index.html dist/index.html
python3 -m http.server 8080 --directory dist
# Open http://localhost:8080

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

AI エージェント用プロンプト
Source Sans 3とtslibを含む固定バージョンのランタイム依存関係を使い、付属のネイティブSuomi.fi FileInput 18.0.0 Reactの例を使用してください。valueは{ file }オブジェクトの配列として制御し、onChangeではFileListを直接受け取ります。このコールバックでevent.targetを読み取らないでください。ローカルで選択されたファイルを受け付ける前に形式とサイズを検証し、削除時に出力される空のリストを処理して、ヒントとエラーのテキストが常に表示されるようにしてください。埋め込みのHTMLプレビューは、別の解釈として明確に表示してください。どちらの実装もファイルをアップロードしません。サーバー側での検証、進捗表示、保存完了の確認には、実際のバックエンドとの契約が必要です。
05

Suomi.fi デザインシステム 出典と対象範囲

埋め込みプレビューとダウンロード可能なZIPは、OpenDesign HTML/CSSによる解釈です。別途用意した完全なReactの例では、suomifi-ui-components 18.0.0と、検証済みのFileInputのvalueおよびonChangeの仕様を使用しています。どちらの例もローカルでのファイル選択に対応していますが、サーバーへの文書のアップロードや保存は行いません。