HDS는 Core CSS, React 컴포넌트 및 디자인 토큰을 제공합니다. 이 예시에서는 다운로드하여 확인한 패키지인 hds-core5.2.2를 고정 버전으로 사용합니다. 저장소 릴리스 번호와 개별 패키지 버전은 다를 수 있으므로, 저장소의 최신 태그만으로 이 예시가 해당 버전에서 실행된다고 볼 수는 없습니다.
Core는 기본 변수와 개별 구성 요소 스타일을 제공합니다. 여기서 사용되는 폼 애플리케이션 상태는 제공하지 않습니다. 선택, 유효성 검사, 검토 및 변경 로직은 네이티브 HTML 입력 요소와 문서화된 HDS 폼 패턴을 기반으로 독자적으로 구현한 JavaScript입니다.
글꼴 변수는 HelsinkiGroteskPro를 우선 지정하고, Arial과 sans-serif를 차례로 대체 글꼴로 사용합니다. Core README에는 저작권 문제로 Helsinki 글꼴 파일이 제외되어 있다고 명시되어 있습니다. 미리보기는 제한된 글꼴을 다운로드하거나 브랜드 글꼴을 정확히 재현한다고 오해를 부르지 않도록 대체 글꼴을 그대로 사용합니다.
기본 본문 토큰은16px이며 줄 높이는1.5입니다. Heading-xl은48px이고 모바일 토큰은40px입니다. 미리보기는576px에서 두 값 사이를 전환합니다. 이는 이름이 지정된 값이지만, 중단점이 포함된 CSS 변수만으로 반응형 동작이 자동 적용되지는 않습니다. 명시적인 미디어 규칙은 애플리케이션 구성에 속합니다.
HDS는 컴포넌트 간격 체계와 더 큰 레이아웃 간격 체계를 구분합니다. 컴포넌트 간격은2,4,8,12,16,24px에서 시작해72px까지 커집니다. 레이아웃 간격은128px까지 이어집니다. spacing-layout-xl은 유효한 변수이지만, 서로 붙어 있는 체크박스 사이 간격으로 사용하면 지나치게 넓어집니다.
체크박스 컴포넌트는24px 컨트롤,2px 테두리 및3px 포커스 윤곽선을 정의합니다. 버튼의 최소 크기는56px이며 모서리는 각이 져 있습니다. 미리보기는 이러한 기본 형태를 유지하고, 양식은 게시된 참조 너비인720px을 최대 너비로 하는 애플리케이션 컨테이너 안에 배치됩니다.
기본 인터랙션 테마에는 버스 블루를 사용하고, 포커스 윤곽선에는 국장 블루를 사용합니다. 오류 피드백에는 별도의 베리 계열 색조와 옅은 오류 표면을 사용합니다. 코퍼와 같은 팔레트 강조색을 헤더에 사용할 수 있지만, 더 눈에 띈다는 이유만으로 오류 역할에 사용해서는 안 됩니다.
선택 그룹의 인라인 오류에는 텍스트, 대비가 뚜렷한 왼쪽 테두리, 아이콘 표현이 함께 사용됩니다. 빨간색에만 의존하지 않습니다. 오류 요약의 링크에는 익숙한 인터랙션 색상을 사용해 사용자가 해당 필드로 돌아가는 경로를 알아볼 수 있게 합니다.
네이티브 구조는 fieldset, legend, 항목 컨테이너, 개별 체크박스 래퍼로 이루어집니다. 스타일시트에서 시각적 상태를 표현할 때 이 관계를 사용하므로 각 input은 해당 label 바로 앞에 놓입니다. legend는 선택 과제를 설명하고, 각 label은 선택 가능한 항목의 이름을 나타냅니다.
데모에서는 두 개 이상의 항목을 선택하도록 합니다. 이는 비즈니스 규칙을 예시로 만든 것입니다. 여러 항목을 선택한 상태로 둘 수 있으므로 체크박스가 적합합니다. 라디오 그룹은 하나만 선택하는 경우에 사용하며, 이 과제에는 맞지 않습니다. 필드 안내는 유효성 검사 전후에 계속 표시됩니다.
html
<fieldset class="hds-selection-group" aria-describedby="topics-hint">
<legend class="hds-selection-group__legend">Topics for your afternoon</legend>
<p id="topics-hint">Choose at least two topics.</p>
<div class="hds-selection-group__items hds-selection-group__items--vertical">
<div class="hds-checkbox">
<input class="hds-checkbox__input" type="checkbox" id="repair" value="Repair and reuse">
<label class="hds-checkbox__label" for="repair">Repair and reuse</label>
</div>
<div class="hds-checkbox">
<input class="hds-checkbox__input" type="checkbox" id="garden" value="Urban gardening">
<label class="hds-checkbox__label" for="garden">Urban gardening</label>
</div>
</div>
</fieldset>
HDS는 제출에 실패한 경우 양식 제목 아래에 오류 요약을 표시할 것을 권장합니다. 오류 요약의 목록은 오류가 있는 컨트롤로 연결되며, 포커스는 요약 제목으로 이동합니다. 데모도 이 순서를 따릅니다. 항목을 0개 또는 1개만 선택하고 검토하면 요약과 인라인 메시지가 표시되고, 링크를 선택하면 첫 번째 체크박스에 포커스가 놓입니다.
첫 시도 이후에는 선택 항목이 바뀔 때마다 최소 선택 수를 다시 확인합니다. 두 항목 이상을 선택하면 선택된 입력값은 지우지 않고 두 오류 표시를 모두 숨깁니다. 다시 검토에 실패하면 포커스는 요약 제목으로 돌아갑니다. 검토할 때마다 규칙을 다시 확인합니다. 실제 서비스에서는 클라이언트 측 피드백이 서버 유효성 검사를 대신할 수 없습니다.
항목을 하나도 선택하지 않고 검토한 뒤 요약에 포커스가 놓이는지 확인합니다.
요약의 링크를 따라가 두 항목을 선택하고 오류가 사라지는지 확인합니다.
로컬 검토를 열고 항목을 변경한 뒤 돌아와 두 선택 항목이 그대로 남아 있는지 확인합니다.
Core 패키지에서는 base.css와 구성 요소 스타일을 분리합니다. base만 불러오면 변수와 타이포그래피는 제공되지만 체크박스나 알림의 구조는 제공되지 않습니다. 이 설정에서는 이 예시에 사용된 정확한 파일을 지정하므로 전체 구성 요소 번들보다 에셋을 적게 사용할 수 있습니다.
전체 예시에는 애플리케이션 유효성 검사와 초기화 기능이 포함됩니다. 마지막 상태를 ‘로컬 검토’라고 부르는 이유는 어떤 정보도 등록하거나 전송하지 않기 때문입니다. 선택 항목 지우기는 의도적으로 실행하는 동작입니다. 선택과 유효성 검사 기록을 초기화한 뒤 첫 번째 입력에 포커스를 둡니다. 일반적인 필드 오류로 실행되지는 않습니다.
base.css는 색상, 간격, 타이포그래피, 기준 치수를 제공합니다.
checkbox 및 selection-group 스타일은 그룹 컨트롤과 인라인 피드백을 제공합니다.
notification 및 button 스타일은 오류 요약 표면과 동작 버튼을 제공합니다.
미리보기에서는 1440, 768, 390px 화면에서 실제 HDS 구성 요소 스타일, 키보드 포커스, 입력 수정, 데이터 보존을 확인할 수 있습니다. 접근성을 빠짐없이 감사했다고 주장하지는 않습니다. 실제 다국어 도시 서비스에는 현지화된 레이블, 적절한 언어 메타데이터, 서버 측 규칙, 서비스 백엔드의 응답 확인도 필요합니다.
소스 코드는 MIT 라이선스가 적용되지만, 사용자 지정 도시 글꼴에는 별도의 권리 경계가 있습니다. 이 독립적인 학습용 예시에는 가상의 프로그램 주제를 사용하며 공식 Helsinki 아이덴티티는 사용하지 않습니다. 화면에 보이는 모습과 로컬 상태를 실제 행사 등록으로 오인해서는 안 됩니다.
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Plan a skills afternoon</title><link rel="stylesheet" href="vendor/hds-core-5.2.2/base.css"><link rel="stylesheet" href="vendor/hds-core-5.2.2/checkbox.css"><link rel="stylesheet" href="vendor/hds-core-5.2.2/selection-group.css"><link rel="stylesheet" href="vendor/hds-core-5.2.2/notification.css"><link rel="stylesheet" href="vendor/hds-core-5.2.2/button.css"><style>*{box-sizing:border-box}body{margin:0;padding:var(--spacing-layout-s) var(--spacing-s);font-family:var(--font-default);color:var(--color-black-90)}main{max-width:720px;margin:auto}h1{margin-top:8px}header{border-top:8px solid var(--color-copper);padding-top:var(--spacing-m)}.hds-selection-group{margin:24px 0}.hds-notification{margin:24px 0}.actions{display:flex;gap:16px;flex-wrap:wrap;margin-top:32px}footer{font-size:14px;line-height:1.5;margin-top:32px;border-top:1px solid var(--color-black-20);padding-top:16px}#review{background:var(--color-silver-light);padding:24px;margin-top:24px}[hidden]{display:none!important}@media(max-width:575px){.heading-xl{font-size:var(--fontsize-heading-xl-mobile)}}button{max-width:100%}</style><main class="text-body"><header><small>COMMUNITY SKILLS · LOCAL PLAN</small><h1 class="heading-xl">Plan a skills afternoon</h1><p>Select at least two topics for an example programme. Nothing is registered or sent.</p></header><form id="form" novalidate><div id="summary" class="hds-notification hds-notification--error" hidden><div class="hds-notification__content"><h2 id="summary-heading" class="hds-notification__label" tabindex="-1">Check your topic selection</h2><div class="hds-notification__body"><ul><li><a href="#repair" id="error-link">Choose at least two topics</a></li></ul></div></div></div><fieldset class="hds-selection-group" aria-describedby="hint field-error"><legend class="hds-selection-group__legend">Topics for your afternoon</legend><p id="hint">Choose two or more. You can change your selection before reviewing the plan.</p><div class="hds-selection-group__items hds-selection-group__items--vertical"><div class="hds-checkbox"><input id="repair" type="checkbox" class="hds-checkbox__input" value="Repair and reuse"><label class="hds-checkbox__label" for="repair">Repair and reuse</label></div><div class="hds-checkbox"><input id="digital" type="checkbox" class="hds-checkbox__input" value="Everyday digital skills"><label class="hds-checkbox__label" for="digital">Everyday digital skills</label></div><div class="hds-checkbox"><input id="garden" type="checkbox" class="hds-checkbox__input" value="Urban gardening"><label class="hds-checkbox__label" for="garden">Urban gardening</label></div></div><div id="field-error" class="hds-selection-group__error-text" hidden>Choose at least two topics.</div></fieldset><p id="count" role="status">0 topics selected.</p><div class="actions"><button class="hds-button hds-button--primary" type="submit">Review local plan</button><button id="reset" class="hds-button hds-button--secondary" type="button">Clear selection</button></div></form><section id="review" hidden tabindex="-1"><h2 class="heading-m">Your selected topics</h2><ul id="selected"></ul><p>This is a local review, not a booking confirmation.</p><button id="change" class="hds-button hds-button--secondary">Change topics</button></section><footer>Native HDS Core5.2.2 styles with Arial fallback. Original selection rule and local review. No Helsinki branding, registration or backend.</footer></main><script>let attempted=false;const boxes=[...document.querySelectorAll('input[type=checkbox]')];const values=()=>boxes.filter(x=>x.checked);function validate(focus=false){const n=values().length;document.querySelector('#count').textContent=n+' topics selected.';const bad=attempted&&n<2;document.querySelector('#summary').hidden=!bad;document.querySelector('#field-error').hidden=!bad;boxes.forEach(x=>{if(bad)x.setAttribute('aria-invalid','true');else x.removeAttribute('aria-invalid')});if(bad&&focus)document.querySelector('#summary-heading').focus();return !bad}boxes.forEach(x=>x.onchange=()=>validate());document.querySelector('#error-link').onclick=e=>{e.preventDefault();boxes[0].focus()};document.querySelector('#form').onsubmit=e=>{e.preventDefault();attempted=true;if(!validate(true))return;const list=document.querySelector('#selected');list.replaceChildren();values().forEach(x=>{const li=document.createElement('li');li.textContent=x.value;list.append(li)});document.querySelector('#form').hidden=true;document.querySelector('#review').hidden=false;document.querySelector('#review').focus()};document.querySelector('#change').onclick=()=>{document.querySelector('#form').hidden=false;document.querySelector('#review').hidden=true;boxes[0].focus()};document.querySelector('#reset').onclick=()=>{boxes.forEach(x=>x.checked=false);attempted=false;validate();boxes[0].focus()};</script></html>
정확한 Core 에셋 경로입니다. 유효성 검사와 검토는 애플리케이션 코드에서 처리하며 HelsinkiGroteskPro는 번들에 포함되지 않습니다. Sources의 전체 실행 예시 ZIP에는 정확한 미리보기 종속 항목과 전체 문서도 포함되어 있습니다. 해당 디렉터리에 압축을 푼 다음 python3 -m http.server 8080을 실행하고 http://localhost:8080/helsinki.html을 여세요. 모듈 기반 예시를 file://로 열지 마세요.
bash
npm install [email protected]
# CSS imports in a bundler:
# import 'hds-core/lib/base.css';
# import 'hds-core/lib/components/checkbox/checkbox.css';
# import 'hds-core/lib/components/selection-group/selection-group.css';
# import 'hds-core/lib/components/notification/notification.css';
# import 'hds-core/lib/components/button/button.css';
# In plain HTML, copy these files into public assets and link base.css first.
# HelsinkiGroteskPro is not bundled; the native font stack falls back to Arial.
프로젝트를 위한 프롬프트
에이전트 프롬프트
HDS Core5.2.2의 base와 선택한 구성 요소 CSS를 사용하세요. 관련 체크박스는 fieldset/legend로 그룹화하고, 레이블과 안내를 유지하며, 의미에 맞는 오류 토큰을 사용하세요. 검토에 실패하면 양식 제목 아래에 링크가 포함된 오류를 표시하고 요약 제목에 포커스를 둡니다. 수정 후에는 다시 확인하고 선택값을 보존하며, 로컬 검토와 서버에서 확인된 제출을 구분하세요.
05
Helsinki 디자인 시스템: 출처와 범위
독립적인 OpenDesign 예시입니다. Helsinki 글꼴 에셋이나 서비스 아이덴티티는 포함되지 않으며, 등록이나 백엔드 결과도 없습니다.