Installing the design system Using Nunjucks
Using Nunjucks
The ONS Design System uses Nunjucks as its templating language. All components and templates are also compatible with applications that use Jinja .
How to set up Nunjucks
npm package
We recommend installing the design system through the npm package we publish on each release.
In your Nunjucks configuration you’ll need to add node_modules/@ons/design-system/components
and node_modules/@ons/design-system/layout
to your search paths.
Zip file
You can get all components and templates from a zip file that is created with each
design system release
. You need to create a script that gets the zip and unpacks the contents. For development, the script could run manually, and the folders added to a .gitignore
file. In production, it would need to be run within a build process as part of a continuous integration task.
If you are using Jinja, your script will need to copy the components
and layout
folders from the unzipped download into your templates
folder. This is where Jinja looks for templates as multiple search paths cannot be specified.
The zipped templates have already got the content delivery network (CDN) release version and paths set based on the version of the templates you have downloaded.
How to use Nunjucks with components
Each component contains examples and any context-specific variants. You can copy the Nunjucks code directly from the examples.
<div class="ons-panel ons-panel--info ons-panel--no-title">
<span class="ons-u-vh">Important information: </span>
<div class="ons-panel__body">
<p>Include all rooms built or converted for use as bedrooms</p>
</div>
</div>
{% from "components/panel/_macro.njk" import onsPanel %}
{{
onsPanel({
"body": '<p>Include all rooms built or converted for use as bedrooms</p>'
})
}}
{% macro onsPanel(params) %}
{% if params is defined and params and params.classes is defined and params.classes %}
{% set classes = ' ' + params.classes %}
{% endif %}
{% if params is not defined or params.title is not defined and params.type != "bare" %}
{% set noTitleClass = ' ons-panel--no-title' %}
{% endif %}
{% if params is defined and params and params.type is defined and params.type %}
{% set typeClass = ' ons-panel--' + params.type %}
{% else %}
{% set typeClass = ' ons-panel--info' %}
{% endif %}
{% if params is defined and params.type == "warn-branded" %}
{% set containerClass = 'ons-census-warning' %}
{% endif %}
{% if params is defined and params.type == "announcement" %}
{% set containerClass = 'ons-announcement' %}
{% endif %}
{% if params is defined and params and params.spacious is defined and params.spacious %}
{% set spaciousClass = ' ons-panel--spacious' %}
{% endif %}
{% if params is defined and params and params.type == "warn-branded" or params.type == "announcement" %}
<div class="{{containerClass}}">
<div class="ons-container">
{% endif %}
<div {% if params is defined and params and params.type == 'error' and params.title is defined and params.title %}aria-labelledby="error-summary-title" role="alert" tabindex="-1" {% if params.dsExample != true %}autofocus="autofocus" {% endif %}{% endif %}class="ons-panel{{ typeClass }}{{ iconClass }}{{ noTitleClass }}{{ spaciousClass }}{{ classes }}"{% if params is defined and params and params.attributes is defined and params.attributes %}{% for attribute, value in (params.attributes.items() if params is defined and params and params.attributes is mapping and params.attributes.items is defined and params.attributes.items else params.attributes) %}{{attribute}}="{{value}}" {% endfor %}{% endif %}{% if params is defined and params and params.id is defined and params.id %} id="{{params.id}}"{% endif %}>
{% if params is defined and params and params.type == "warn" or params.type == "warn-branded" %}
<span class="ons-panel__icon" aria-hidden="true">!</span>
<span class="ons-u-vh">{{ params.assistiveTextPrefix | default("Warning: ") }}</span>
{% endif %}
{% if params is defined and params and params.type == "announcement" %}
{% from "components/icons/_macro.njk" import onsIcon %}
<span class="ons-panel__icon" aria-hidden="true">
{{
onsIcon({
"iconType": 'arrow-forward'
})
}}
</span>
<span class="ons-u-vh">{{ params.assistiveTextPrefix | default("Announcement: ") }}</span>
{% endif %}
{% if params is defined and params %}
{% if params.title is defined and params.title %}
{% if params is defined and params and params.type == 'error' %}
{% set defaultTitleTag = "h2" %}
{% else %}
{% set defaultTitleTag = "div" %}
{% endif %}
{% set titleTag = params.titleTag | default(defaultTitleTag) %}
<div class="ons-panel__header">
<{{ titleTag }} id="error-summary-title" {% if params is defined and params and params.type is defined and params.type %}data-qa="{{ params.type }}-header"{% endif %} class="ons-panel__title ons-u-fs-r--b">{{ params.title | safe }}</{{ titleTag }}>
</div>
{% else %}
{% if params.type is not defined or params.type == "branded" %}
<span class="ons-u-vh">{{ params.assistiveTextPrefix | default("Important information: ") }}</span>
{% else %}
{% if params.type is defined and params.type == "success" %}
<span class="ons-u-vh">{{ params.assistiveTextPrefix | default("Completed: ") }}</span>
{% elif params.type is defined and params.type == "error" %}
<span class="ons-u-vh">{{ params.assistiveTextPrefix | default("Error: ") }}</span>
{% endif %}
{% endif %}
{% endif %}
{% if params.iconType is defined and params.iconType %}
{% from "components/icons/_macro.njk" import onsIcon %}
<span class= "ons-panel__icon ons-u-fs-{{ params.iconSize | default('r') }}">
{{
onsIcon({
"iconType": params.iconType,
"iconSize": params.iconSize
})
}}
</span>
{% endif %}
{% endif %}
<div class="ons-panel__body{% if params is defined and params and params.iconSize is defined and params.iconSize %} ons-svg-icon-margin--{{ params.iconSize }}{% endif %}">{{ (params.body if params else "") | safe }}
{{ caller() if caller }}
</div>
</div>
{% if params is defined and params and params.type == "warn-branded" or params.type == "announcement" %}
</div>
</div>
{% endif %}
{% endmacro %}
@mixin panel-type($name, $color, $color-bg) {
.ons-panel {
&--#{$name} {
background: $color-bg;
border-color: $color;
}
&--#{$name} & {
&__header {
background: $color;
}
}
}
}
.ons-census-warning {
background: $color-branded-tertiary;
}
.ons-announcement {
background-color: $color-black;
}
.ons-panel {
border-radius: 0;
position: relative;
// Removes inherited bottom margin to make whitespace inside panel equal
> *:last-child {
margin-bottom: 0;
}
.ons-field {
margin-bottom: 0;
}
&:focus {
box-shadow: none;
outline: 4px solid $color-focus !important;
outline-offset: 0;
}
&__header {
border-radius: 0;
color: $color-white;
margin: 0;
padding: 0.75rem 1rem;
}
&__timer {
white-space: nowrap;
}
&__title {
margin: 0;
}
&__body {
padding: 1rem;
// Removes inherited bottom margin to make whitespace inside panel equal
> *:last-child,
strong > *:last-child {
margin-bottom: 0;
}
&.ons-svg-icon-margin--xxxl {
padding-left: 2.7rem !important;
@include mq(m) {
padding-left: 3.5rem !important;
}
}
&.ons-svg-icon-margin--xxl {
padding-left: 2.45rem !important;
@include mq(m) {
padding-left: 2.9rem !important;
}
}
&.ons-svg-icon-margin--xl {
padding-left: 2.35rem !important;
@include mq(m) {
padding-left: 2.55rem !important;
}
}
&.ons-svg-icon-margin--l {
padding-left: 2.25rem !important;
@include mq(m) {
padding-left: 2.35rem !important;
}
}
&.ons-svg-icon-margin--m {
padding-left: 2.05rem !important;
@include mq(m) {
padding-left: 2.2rem !important;
}
}
&.ons-svg-icon-margin--s {
padding-left: 1.7rem !important;
}
}
&__error {
color: $color-errors;
}
&--warn {
border: 0 !important;
margin-bottom: 1rem;
padding: 0;
&--footer {
background-color: $color-grey-15 !important;
margin-bottom: 0;
padding: 1rem 0 !important;
}
}
&--warn-branded,
&--announcement {
border: 0 !important;
color: $color-white;
margin-bottom: 0;
padding: 1rem 0 !important;
a {
color: inherit;
text-decoration: underline solid $color-white 1px;
}
a:hover {
text-decoration-thickness: 2px;
}
}
&--announcement {
a:focus {
box-shadow: 0 -2px #fd0, 0 4px #fd0 !important; // Override focus style because the black border is not visible on a black background
}
}
&--no-title {
border-left: 8px solid transparent;
padding: 1rem;
.ons-panel__body {
background: none;
padding: 0;
}
&.ons-panel--warn {
padding: 0;
}
}
&--spacious {
padding: 1rem;
@include mq(m) {
padding: 2rem;
}
}
&--warn &,
&--warn-branded &,
&--announcement & {
&__body {
font-weight: $font-weight-bold;
min-height: 2rem; // Height of icon
padding: 0.222rem 0 0.222rem 2.8rem; // Alignment tweak
}
&__icon {
background: $color-black;
border-radius: 50%;
color: $color-white;
font-size: 1.5rem;
font-weight: 900;
line-height: 2rem;
min-height: 2rem;
min-width: 2rem;
text-align: center;
}
}
&--announcement & {
&__body div > *:last-child {
margin-bottom: 0;
}
&__icon {
background-color: $color-white;
color: $color-black;
display: flex;
svg {
margin: auto;
}
}
}
&--warn-branded & {
&__icon {
background-color: $color-white;
color: $color-branded-tertiary;
}
}
&--success & {
&__icon {
left: 0;
padding-left: 1rem;
.ons-svg-icon {
fill: $color-success !important;
margin-top: -15% !important;
}
}
}
&__icon + &__body {
padding-left: 2rem;
}
&--bare & {
&__icon {
height: 1.3rem;
width: 1.3rem;
}
&__body {
padding: 0 0 0 1.5rem;
}
}
&--info,
&--bare,
&--success,
&--warn,
&--warn-branded,
&--announcement {
.ons-panel__icon {
position: absolute;
}
}
}
@include panel-type(error, $color-errors, $color-errors-tint);
@include panel-type(success, $color-success, $color-success-tint);
@include panel-type(info, $color-info, $color-info-tint);
@include panel-type(branded, $color-branded, $color-branded-tint);
@include panel-type(warn, $color-white, $color-white);
@include panel-type(warn-branded, $color-branded-tertiary, $color-branded-tertiary);
@include panel-type(announcement, $color-black, $color-black);