Government & Public Services · New Resource

ONS Design System.

Build a survey answer that cannot contradict itself: native ONS checkboxes, mutually exclusive responses, exact type and color references, and a complete local review flow.

OpenDesign Guide8 Chapters26 Reference EntriesOriginal Application Guide
01

ONS Design System Interface Preview

Try several travel methods, the opposing answer, empty validation, local review and preserved edits.

A survey answer that cannot contradict itselfOpen Full Example
Native ONS 73.13.1 Checkbox and Mutually Exclusive CSS/JavaScript. Original question, app validation/review and explicit Arial fallback. · Implementation reference
02

ONS Design System Design Reference

ONS Design System 73.13.1 compiled CSS, JavaScript and Sass variables, checked against the public service manual. Native Checkbox and Mutually Exclusive behavior is used in the specimen. Arial substitutes for OpenSans in the standalone example; the production copy recipe includes packaged fonts. The travel question and local review are original demonstration content.

Type matrix

Source
Name / RuleValue / ConfigurationUse
Primary familyOpenSans, Helvetica Neue, Arial, sans-serifOfficial font guidance specifies Open Sans stylistic set 1; demo intentionally uses Arial.
ons-u-fs-3xl32/44px → 48/56pxSmall → large at medium breakpoint; weight700.
ons-u-fs-2xl28/40px → 36/48pxWeight700; heading-sized hierarchy.
ons-u-fs-xl / ons-u-fs-l26/36 → 30/40px; 24/32 → 26/36pxNative responsive sizes and leading, not a fluid clamp.
ons-u-fs-m20/28px → 22/32pxWeight700.
ons-u-fs-r / ons-u-fs-s18/28px / 14/20pxRegular400; --b variants use700.

Semantic color roles

Source
Name / RuleValue / ConfigurationUse
--ons-color-text#222Maps to --ons-color-black.
--ons-color-text-link#206095 Ocean blue; hover/active night blue #003c57.
--ons-color-focus#fbc900 Sun-yellow focus indication.
--ons-color-button#0f8243 Leaf green; separate from link color.
--ons-color-errors#d0021b Ruby-red errors paired with a written explanation.
--ons-color-info-tint#e9eff4 Information panel background; not a selected checkbox replacement.

Actual spacing utilities

Source
Name / RuleValue / ConfigurationUse
ons-u-mb-xs / s / m12px /16px /20pxBottom-margin utility values at a16px root. These include steps outside the documented8px grid baseline.
ons-u-mb-l / xl24px /32pxUse the published release utilities; do not infer all values from a baseline statement.

Layout and responsive model

Source
Name / RuleValue / ConfigurationUse
Grid12 percentage-width columnsons-grid > ons-grid__col with responsive column classes.
Medium columnons-col-8@mEight columns from740px; full width below.
Breakpoints300,400,500,740,980,1300,1600px2xs,xs,s,m,l,xl,2xl.
BaselineMultiples of8pxGrid documentation rhythm; do not assume every border/font matches it.
Documented gutters16px below600;24px at600+Check the release CSS if overriding grid classes.
Default container64.6256rem maximum;1rem horizontal paddingVerified73.13.1 CSS, approximately1034px at16px root.

Mutual exclusion hooks

Source
Name / RuleValue / ConfigurationUse
Group rootons-js-mutually-exclusiveNative script finds this container on DOM readiness.
Regular optionsons-js-exclusive-group-itemCan be combined; selecting one clears an opposing exclusive option.
Opposing choiceons-js-exclusive-optionSelecting it clears the ordinary group values.
Explanationdata-deselect-messageWarning text for the opposing choice.
Announcementons-js-exclusive-alertLive region with data-group-adjective and data-option-adjective.
State updatesclick for checkbox/radio;input for textThe controller caches hasValue; application reset should use native events.
03

ONS Design System Complete Guide

A practical guide to choosing, applying, and reviewing this system for a real interface.

DESIGN-ons.md

Complete guidance, an implementation starting point, and source links.

Download Guide

ONS Design System Questionnaire-specific design

Protect the meaning of an answer

ONS serves statistical collection as well as information publishing. For a questionnaire, mutually exclusive responses are a data-quality issue: a user must not send both a travel method and an answer saying no journey took place. The native Mutually Exclusive component links those options and explains deselection to assistive technology.

From this OpenDesign guide

The specimen asks an original library-travel question and offers a local answer preview. It deliberately avoids ONS identity graphics and makes no claim that the answers are collected. A production survey would need its own consent, retention, routing and server validation.

Read the supporting specification

ONS Design System Readable question hierarchy

A legend can be the page heading

The primary family is Open Sans, with stylistic set 1 chosen for distinctive letterforms. The native Sass type matrix has fixed small and large values rather than an invented continuous scale. Body text remains 18px with 28px leading. The main large class moves from 32/44 to 48/56 at the medium breakpoint.

A single-question page can place its h 1 inside the fieldset legend so the group’s accessible name and visible title agree. Do not create a second unrelated h 1 above it. The example keeps the service context as a smaller paragraph and the choice instruction beneath the legend.

The standalone demo explicitly uses Arial so that it has no missing-font requests. The installation recipe copies fonts alongside the CSS; this is necessary if the adopter wants the published OpenSans face rather than a fallback.

Read the supporting specification

ONS Design System Roles in a survey interface

Focus is separate from status

ONS assigns semantic variables to primitive colors. Text is black, ordinary links Ocean Blue and the primary button Leaf Green. Sun Yellow is the focus color. Ruby Red communicates errors, but the error message must still say which action is needed. A green Continue button is not a promise that the answer has already passed validation.

The local questionnaire uses the native checkbox border and selected treatment. It does not paint every answer as a separate marketing card. A short neutral top rule separates the independent specimen from the question without reproducing the ONS masthead.

  • Keep the native visible focus treatment on both checkbox input and action button.
  • Use the written instruction “Select all that apply” before regular options.
  • Separate the opposing answer with “Or” so its difference is visible before interaction.

Read the supporting specification

ONS Design System Columns and answer width

Use the questionnaire measure

The twelve-column grid expresses widths through classes such as ons-col-8@m. At 740px and above, that class occupies eight columns; below it, the same element fills the available content width. The local example uses that native column so the long question wraps at a readable measure instead of stretching across the whole desktop.

The standard container has a 64.6256rem maximum in the inspected release and 1rem horizontal padding. The public grid guide additionally describes an 8px baseline and 16/24px gutters around its 600px spacing boundary. Keep those concepts separate from the 740px medium column breakpoint; they are not a single universal mobile switch.

The answer review replaces the question within the same column, and Change answers returns to the existing controls. Values stay in memory without a route change or network request.

The executable spacing utilities are more granular than the 8px baseline sentence: xs, s, m, l and xl bottom margins are 12,16,20,24 and 32px at a 16px root. The reference therefore lists actual utility values separately from the grid guidance.

Read the supporting specification

ONS Design System Build the answer group

Native checkbox anatomy

A checkbox uses ons-checkbox__input and an associated ons-checkbox__label inside ons-checkbox. The input keeps its ordinary name and value attributes so native form semantics still work. The broader ons-checkboxes__item structure supplies the spacing and hit area expected by the stylesheet.

The regular choices share ons-js-exclusive-group-item. The final choice uses ons-js-exclusive-option instead, with data-deselect-message explaining the effect. The live-region span must be present with both adjective attributes: it is not decorative extra markup. Removing it would break the native controller’s assumptions.

This source example is complete for three ordinary options and one opposing response. Adapt the nouns and values to a real question; do not merely rename an unrelated validation control as “exclusive.”

html
<fieldset class="ons-fieldset"><legend class="ons-fieldset__legend"><h1 class="ons-fieldset__legend-title">How did you travel to your local library last week?</h1></legend>
<div class="ons-js-mutually-exclusive ons-mutually-exclusive">
<p class="ons-checkboxes__label">Select all that apply</p><div class="ons-checkboxes__items"><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="walk" name="travel" value="walk" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="walk" id="walk-label">Walk or wheel</label></span></span><br><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="cycle" name="travel" value="cycle" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="cycle" id="cycle-label">Cycle</label></span></span><br><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="bus" name="travel" value="bus" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="bus" id="bus-label">Bus or tram</label></span></span><br></div>
<p class="ons-checkboxes--mutually-exclusive__item ons-u-mt-s"><span class="ons-checkboxes__label ons-u-fs-r--b" aria-hidden="true">Or</span><span class="ons-checkbox"><input type="checkbox" id="none" name="travel" value="none" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-option" data-deselect-message="Selecting this will uncheck all other options"><label class="ons-checkbox__label" for="none" id="none-label"><span class="ons-u-vh">Or, </span>I did not visit the library</label></span></p>
<span class="ons-js-exclusive-alert ons-u-vh" role="alert" aria-live="polite" data-group-adjective="deselected" data-option-adjective="deselected"></span></div></fieldset>

Code reference

Read the supporting specification

ONS Design System Validation and change behavior

Library state and application state

The library owns which opposing options are cleared. The example’s small application handler only checks that at least one answer exists before displaying a local review. With no selection, it reveals a written error and focuses the linked message. The error link goes directly to the first choice, where the user can act.

The controller tracks cached hasValue state in addition to the DOM checkbox value. Resetting with checked=false alone could leave that cache stale. The reset action therefore clicks each checked input, letting the native listeners update their model, then returns focus to the question. This is a concrete integration concern that cannot be checked by looking at the stylesheet.

The review uses a list of the selected labels. Change answers preserves the controls and their selection. No success panel claims that a survey response has been received, because there is no server behind this specimen.

Read the supporting specification

ONS Design System Assets and template adoption

Two supported routes

The npm package includes compiled assets, Sass sources, Nunjucks macros and a base page template. This preview takes the compiled HTML route: copy the official CSS and main.js, reproduce the documented markup, then load the script after the body content. The script initializes matching component hooks when the DOM is ready.

A server-rendered project can instead use the Nunjucks macro files from components. The Checkbox macro accepts its checkbox array, labels, descriptions, error configuration and mutuallyExclusive configuration. Setting dontWrap transfers fieldset responsibility to the enclosing question component; it is not a way to omit the accessible group name.

If selecting individual Sass files, import the system variables, helpers, utilities, base and objects first, then the component rules and any component dependencies. The full compiled CSS avoids that dependency selection for this small standalone specimen.

  1. Pin the package version and serve css, scripts and fonts under one stable local asset directory.
  2. Choose compiled HTML for a static page or configure Nunjucks macro paths for a server-rendered application.
  3. Keep CSS, JavaScript and markup from the same release, and recheck mutual exclusion after an upgrade.

Read the supporting specification

ONS Design System Exercise contradictory answers

Verify the data meaning

Select Walk and Bus, then select “I did not visit.” Both previous choices should clear. Next select Cycle: the opposing answer must clear while Cycle remains checked. Repeat using Space on the focused inputs and inspect the announcement region rather than assuming a visual tick proves all behavior.

Continue with no selection to exercise the error, then review a valid answer and return with Change answers. Finally reset after a contradictory-answer sequence and make another selection; this catches stale native-controller state. At 390px the question and all labels must remain readable without horizontal page scrolling.

These tests verify the local interaction, not a production survey’s data submission, accessibility certification or statistical question quality. A real service still needs server validation of contradictory values and research on whether the response categories are complete.

Read the supporting specification

ONS Design System Design System Component Examples

A complete mutually exclusive question

Ordinary answer options and an opposing response with the native live-region hooks.

html
<fieldset class="ons-fieldset"><legend class="ons-fieldset__legend"><h1 class="ons-fieldset__legend-title">How did you travel to your local library last week?</h1></legend>
<div class="ons-js-mutually-exclusive ons-mutually-exclusive">
<p class="ons-checkboxes__label">Select all that apply</p><div class="ons-checkboxes__items"><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="walk" name="travel" value="walk" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="walk" id="walk-label">Walk or wheel</label></span></span><br><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="cycle" name="travel" value="cycle" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="cycle" id="cycle-label">Cycle</label></span></span><br><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="bus" name="travel" value="bus" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="bus" id="bus-label">Bus or tram</label></span></span><br></div>
<p class="ons-checkboxes--mutually-exclusive__item ons-u-mt-s"><span class="ons-checkboxes__label ons-u-fs-r--b" aria-hidden="true">Or</span><span class="ons-checkbox"><input type="checkbox" id="none" name="travel" value="none" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-option" data-deselect-message="Selecting this will uncheck all other options"><label class="ons-checkbox__label" for="none" id="none-label"><span class="ons-u-vh">Or, </span>I did not visit the library</label></span></p>
<span class="ons-js-exclusive-alert ons-u-vh" role="alert" aria-live="polite" data-group-adjective="deselected" data-option-adjective="deselected"></span></div></fieldset>

Code reference

Serve one matching release

Compiled asset route, including relative font assets for a full project.

bash / html
npm install --save-exact @ons/[email protected]
mkdir -p public/vendor/ons
cp -R node_modules/@ons/design-system/css public/vendor/ons/
cp -R node_modules/@ons/design-system/scripts public/vendor/ons/
cp -R node_modules/@ons/design-system/fonts public/vendor/ons/

<!-- In your page head -->
<link rel="stylesheet" href="/vendor/ons/css/main.css">
<!-- Place the compiled component markup in the body. -->
<!-- Immediately before </body>; initializes matching component hooks -->
<script src="/vendor/ons/scripts/main.js"></script>

Code reference

Complete standalone specimen

The full document includes its layout, controls and initialization. Extract the linked example archive to obtain the exact relative vendor assets, then serve it over HTTP.

html
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>ONS survey question specimen</title><link rel="stylesheet" href="vendor/ons-73.13.1/css/main.css"><style>body,input,button,select,textarea{font-family:Arial,sans-serif!important}body{margin:0}main{padding-top:32px;padding-bottom:32px}.specimen{border-top:4px solid var(--ons-color-ocean-blue);padding-top:16px}.actions{display:flex;gap:24px;align-items:center;flex-wrap:wrap;margin-top:32px}[hidden]{display:none!important}.error{border-left:4px solid var(--ons-color-errors);padding:16px;margin:24px 0;color:var(--ons-color-errors)}.quiet{color:var(--ons-color-text-light)}fieldset{min-width:0}.ons-checkbox__label{max-width:100%}</style><main class="ons-container"><p class="ons-u-fs-s specimen">Independent specimen · Original library survey</p><div class="ons-grid"><div class="ons-grid__col ons-col-8@m"><section id="question"><p class="quiet">Travel · Question 1 of 1</p><div id="error" class="error" tabindex="-1" hidden><strong>Select a travel method or tell us you did not visit.</strong><p><a href="#walk">Go to the answer choices</a></p></div><form id="survey" novalidate><fieldset class="ons-fieldset"><legend class="ons-fieldset__legend"><h1 class="ons-fieldset__legend-title">How did you travel to your local library last week?</h1></legend>
<div class="ons-js-mutually-exclusive ons-mutually-exclusive">
<p class="ons-checkboxes__label">Select all that apply</p><div class="ons-checkboxes__items"><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="walk" name="travel" value="walk" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="walk" id="walk-label">Walk or wheel</label></span></span><br><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="cycle" name="travel" value="cycle" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="cycle" id="cycle-label">Cycle</label></span></span><br><span class="ons-checkboxes__item"><span class="ons-checkbox"><input type="checkbox" id="bus" name="travel" value="bus" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-group-item"><label class="ons-checkbox__label" for="bus" id="bus-label">Bus or tram</label></span></span><br></div>
<p class="ons-checkboxes--mutually-exclusive__item ons-u-mt-s"><span class="ons-checkboxes__label ons-u-fs-r--b" aria-hidden="true">Or</span><span class="ons-checkbox"><input type="checkbox" id="none" name="travel" value="none" class="ons-checkbox__input ons-js-checkbox ons-js-exclusive-option" data-deselect-message="Selecting this will uncheck all other options"><label class="ons-checkbox__label" for="none" id="none-label"><span class="ons-u-vh">Or, </span>I did not visit the library</label></span></p>
<span class="ons-js-exclusive-alert ons-u-vh" role="alert" aria-live="polite" data-group-adjective="deselected" data-option-adjective="deselected"></span></div></fieldset><div class="actions"><button class="ons-btn" type="submit"><span class="ons-btn__inner">Review answer</span></button><button id="reset" type="button" class="ons-btn ons-btn--secondary"><span class="ons-btn__inner">Reset</span></button></div></form><p class="ons-u-mt-l ons-u-fs-s quiet">Practice only. Your selection stays in this page and is not submitted.</p></section><section id="review" hidden><h1 tabindex="-1">Review your answer</h1><h2 class="ons-u-fs-m">Travel to the library last week</h2><ul id="answer"></ul><p>No response has been sent. Return to the question to change your selection.</p><button id="change" class="ons-btn ons-btn--secondary"><span class="ons-btn__inner">Change answers</span></button></section></div></div></main><script src="vendor/ons-73.13.1/scripts/main.js"></script><script>const form=document.querySelector('#survey'),q=document.querySelector('#question'),r=document.querySelector('#review'),err=document.querySelector('#error'),checks=[...form.querySelectorAll('input[type=checkbox]')];form.onsubmit=e=>{e.preventDefault();const chosen=checks.filter(x=>x.checked);if(!chosen.length){err.hidden=false;err.focus();return}err.hidden=true;document.querySelector('#answer').replaceChildren(...chosen.map(x=>{let li=document.createElement('li');li.textContent=document.querySelector('label[for="'+x.id+'"]').textContent.replace(/^Or, /,'');return li}));q.hidden=true;r.hidden=false;r.querySelector('h1').focus()};document.querySelector('#change').onclick=()=>{r.hidden=true;q.hidden=false;checks[0].focus()};document.querySelector('#reset').onclick=()=>{checks.filter(x=>x.checked).forEach(x=>x.click());err.hidden=true;checks[0].focus()};window.demoReady=true;</script></html>

Code reference

  • Download the complete example from Sources. Its README gives the exact local launch command.
  • Keep vendor paths relative to this document; the archive includes the complete assets used by this preview.
04

ONS Design System Agent Setup

Implementation Starting Point

Native 73.13.1 compiled CSS and JavaScript run in the local specimen. Arial is an explicit local fallback; production copy instructions include packaged OpenSans fonts. The complete working-example ZIP in Sources also provides the exact preview dependencies and full document. Extract it, run python3 -m http.server 8080 in that directory, then open http://localhost:8080/ons.html. Do not open module-based examples through file://.

bash / html
npm install --save-exact @ons/[email protected]
mkdir -p public/vendor/ons
cp -R node_modules/@ons/design-system/css public/vendor/ons/
cp -R node_modules/@ons/design-system/scripts public/vendor/ons/
cp -R node_modules/@ons/design-system/fonts public/vendor/ons/

<!-- In your page head -->
<link rel="stylesheet" href="/vendor/ons/css/main.css">
<!-- Place the compiled component markup in the body. -->
<!-- Immediately before </body>; initializes matching component hooks -->
<script src="/vendor/ons/scripts/main.js"></script>

A Prompt for Your Project

Agent Prompt
Build an independent ONS73.13.1 survey specimen using the native Checkbox and Mutually Exclusive hooks, associated fieldset/legend, ordinary answer group and one opposing response. Include the required live region and deselection attributes. Serve matching native CSS and main.js; do not write a substitute exclusivity controller. Add local empty validation and answer review with preserved edits, no server receipt claim. Reset through native events so cached state stays consistent. Use ons-col-8@m and the verified type/semantic color rules without official identity marks.
05

ONS Design System Sources and Scope

Independent implementation specimen with original survey wording. Native code is MIT-licensed; ONS identity and content licensing are separate. No answers are transmitted, persisted or presented as official statistics.