Active theme set to Nord LightNord Dark and saved in preferences.
Copied to clipboard.
Error submitting your feedback! Please try again.

Web Components New

Nord makes it effortless to implement and use its components across any framework or no framework at all. We accomplish this by using standardized web platform APIs and Web Components.

Web Components are a set of technologies that provide a standards based component model for the Web. They allow us to create reusable Custom Elements with their functionality encapsulated away from the rest of the code.

We’ve chosen to use Web Components because there is a strong requirement for Nord to be used in many different contexts and with varying technologies — from static HTML pages to server-rendered apps, through to single page applications authored with frameworks such as React and Vue.js. Web Components work great for Nord, because they:


Browse components

Quick start #

There are two necessary parts to using Nord’s components — the Web Components themselves, and the CSS Framework. Everything else is optional. The fastest way to get started is to include the following directly into your page with <script> and <link> tags:

<link rel="stylesheet" href="https://nordcdn.net/ds/css/1.2.1/nord.min.css" integrity="sha384-p92xkSmw+NPs+cABRe9ixFUkPNZiw3zDpQJ1kH+LyDaUEuejeNKbpF/d0QzFKu4J" crossorigin="anonymous" />
<script type="module" src="https://nordcdn.net/ds/components/1.5.0/index.js" integrity="sha384-pkrdEkWcYc1LLhZxo3DCAVKKlhCfRYrjYjDfmxKEgPmRVaackTAhjQDQ2X4Vqsfi" crossorigin="anonymous"></script>

With these, you now have access to all of Nord’s components! You can now for example add a button to your page:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Nord Design System</title>
<link rel="stylesheet" href="https://nordcdn.net/ds/css/1.2.1/nord.min.css" integrity="sha384-p92xkSmw+NPs+cABRe9ixFUkPNZiw3zDpQJ1kH+LyDaUEuejeNKbpF/d0QzFKu4J" crossorigin="anonymous" />
<script type="module" src="https://nordcdn.net/ds/components/1.5.0/index.js" integrity="sha384-pkrdEkWcYc1LLhZxo3DCAVKKlhCfRYrjYjDfmxKEgPmRVaackTAhjQDQ2X4Vqsfi" crossorigin="anonymous"></script>
</head>
<body>
<nord-button variant="primary">Hello Nordie</nord-button>
</body>
</html>
Edit in CodePen
Whilst this is a fast way to get started, the above method is not recommended for production since it will result in many small HTTP requests. This has a negative effect on page load times. We recommend using a bundler for production, for optimal performance.

Installation #

We strive to support as many use-cases as possible for consuming Nord’s components. In its purest form, you can include our components and styles via <script> and <link> tags served from our CDN.

This approach is best for rapid prototyping, for use in static HTML pages, or for integrating into existing apps which do not have a JavaScript build step. For all other cases we recommend installing the packages locally via npm/yarn.

CDN installation #

Include the following in the <head> of your web page:

<link rel="stylesheet" href="https://nordcdn.net/ds/css/1.2.1/nord.min.css" integrity="sha384-p92xkSmw+NPs+cABRe9ixFUkPNZiw3zDpQJ1kH+LyDaUEuejeNKbpF/d0QzFKu4J" crossorigin="anonymous" />
<script type="module" src="https://nordcdn.net/ds/components/1.5.0/index.js" integrity="sha384-pkrdEkWcYc1LLhZxo3DCAVKKlhCfRYrjYjDfmxKEgPmRVaackTAhjQDQ2X4Vqsfi" crossorigin="anonymous"></script>

If working on a custom themed app, you should also include the theme after the CSS Framework:

<link rel="stylesheet" href="https://nordcdn.net/ds/css/1.2.1/nord.min.css" integrity="sha384-p92xkSmw+NPs+cABRe9ixFUkPNZiw3zDpQJ1kH+LyDaUEuejeNKbpF/d0QzFKu4J" crossorigin="anonymous" />
<link rel="stylesheet" href="https://nordcdn.net/ds/themes/6.0.0/nord-dark.css" integrity="sha384-w/DlTgKpMRdSi47wP2OOHTntpFzP8UaDpFFNvsorIvHOv4WfidwcHkyfr17b2T1m" crossorigin="anonymous" />
<script type="module" src="https://nordcdn.net/ds/components/1.5.0/index.js" integrity="sha384-pkrdEkWcYc1LLhZxo3DCAVKKlhCfRYrjYjDfmxKEgPmRVaackTAhjQDQ2X4Vqsfi" crossorigin="anonymous"></script>

Local installation #

Before moving further with the installation, please make sure you have Node.js installed on your machine. You can install the latest version through their website.

If you’re planning on using Nord’s Web Components in a project that doesn’t yet use Node Package Manager, you’ll have to first create a package.json file. To do this, run npm init and follow the steps provided. Once finished, you can install Nord’s Web Components by following the instructions below.

Run in your project or website root directory (where package.json lives):

# With NPM
npm install @nordhealth/css @nordhealth/components --save

# With Yarn
yarn add @nordhealth/css @nordhealth/components

Required styles #

It’s a requirement that you use our CSS framework alongside the Web Components. The CSS framework includes all our design tokens, a default theme for the components, as well as a number of helpful utility classes.

Outside of the components themselves, we recommend leveraging the included design tokens and utility classes as much as possible to achieve a consistent look and feel.

If working in Veterinary or Healthcare space, you will also need a specific theme from our themes package in your application:

# With NPM
npm install @nordhealth/themes --save

# With Yarn
yarn add @nordhealth/themes

Bundling #

Bundling and transpiling are considered application concerns. We cannot anticipate all requirements, loading strategies, and so on. So we publish our components as ES modules, written for modern browsers. These can then be bundled, tree shaken, and optimised by individual applications.

Browser support #

Nord Design System is tested in the latest two versions of the following browsers. Our team addresses critical bug fixes in earlier versions based on their severity and impact. If you need to support IE11 or pre-Chromium Edge, this library isn’t for you.


Chrome Safari Chrome Chrome Chrome

Usage #

Properties #

In browsers, elements have attributes in HTML and properties in JavaScript. Our attributes are always in dash-case, and the properties are in camelCase.

All attributes have corresponding underlying properties, but not all properties have corresponding attributes. Since HTML only has two types of values, strings and booleans, any property which is not a string or a boolean cannot exist as an attribute. For instance, a function cannot be passed via an attribute, so it must be passed via JavaScript:

<nord-calendar></nord-calendar>

<script type="module">
const calendar = document.querySelector("nord-calendar")

// this could not be set via an attribute
calendar.isDateDisabled = function isWeekend(date) {
return date.getDay() === 0 || date.getDay() === 6
}
</script>

Boolean attributes are considered false by omission, and true by inclusion. For instance, to set the hideLabel property of an input to true, you include the hide-label attribute without a value:

<!-- hideLabel property is set to true -->
<nord-input label="Name" hide-label></nord-input>

It’s recommended, as much as possible, to leverage attributes in HTML rather than properties in JavaScript.


Events #

Components emit custom DOM events, which can be listened to via addEventListener or whatever mechanism your framework of choice offers. It’s worth noting that all our events bubble.

Where our components are drop-in replacements for native elements we follow native event names. For instance, our Input and other form components, emit change, input, blur, focus events.

<nord-input id="events-example" label="Name"></nord-input>

<script type="module">
document.querySelector("#events-example").addEventListener("focus", e => {
console.log("focus", e.target)
})
</script>
Edit in CodePen

Where there is no equivalent native event, we prefix our event names with nord-. For instance, the Command Menu emits a nord-select event when a command is chosen from the menu.

It’s best to consult the documentation for each component to be sure of event names.

Methods #

Some components offer methods which you can call to invoke behavior. Interactive components like Input, Button etc. offer focus(), blur(), and click() methods, which behave like the native equivalents. Some components offer methods for which there is no native equivalent. For instance, Date Picker offers a show() and hide() method:

Open date picker
<nord-stack>
<nord-button id="methods-example-button">Open date picker</nord-button>
<nord-date-picker id="methods-example-picker" label="Date of birth"></nord-date-picker>
</nord-stack>

<script type="module">
const button = document.querySelector("#methods-example-button")
const picker = document.querySelector("#methods-example-picker")

button.addEventListener("click", () => {
picker.show()
})
</script>
Edit in CodePen
It’s best to consult the documentation for each component to get a full description of methods and their parameters.

Slots #

Web components offer a feature called slots. As with events, properties and methods, slots form part of the public API of a component. Slots allow web components to receive content as children, and place the content into their internal DOM.

The most common slot is the default slot, which captures any content placed as a child of a component that does not have a slot attribute. For instance, the Button component has a default slot:

Log in
<nord-button>Log in</nord-button>
Edit in CodePen

In the above example the text “Log in” is placed into the Button’s default slot. You can also place elements inside the default slot, as can be seen here with the Card component:

Hello world

<nord-card>
<p>Hello world</p>
</nord-card>
Edit in CodePen

Some components also offer named slots. Slot names are decided by the components themselves. Named slots are used to differentiate certain types of content, giving components control over style and position. Here we use the Button component’s start slot to position an icon. Notice the slot="start" attribute:

Delete
<nord-button variant="danger">
<nord-icon slot="start" name="interface-delete"></nord-icon>
Delete
</nord-button>
Edit in CodePen

Slotted elements can be placed anywhere inside a component. The component will always place it in the correct place internally. Therefore, the below example will produce the exact same result as above, despite the order being changed:

Delete
<nord-button variant="danger">
Delete
<nord-icon slot="start" name="interface-delete"></nord-icon>
</nord-button>
Edit in CodePen
Refer to a component’s documentation for a complete list of available slots.

Themes #

We offer light and dark themes for components. Themes operate at a global level, rather than per component. The CSS Framework includes the Nord Light theme by default. For theme specific documentation, please see themes documentation. Make sure to try theme builder as well to get familiar with theming and how to customize it.

# Install themes using NPM
npm install @nordhealth/themes --save

# Install themes using Yarn
yarn add @nordhealth/themes
Nord ThemesThemes documentation

Waiting for components to load #

Web components are entirely self-contained (both styles and behavior), and can be loaded/defined asynchronously. Therefore a component may not be ready for use immediately.

When a component is loading, it should be hidden from view to avoid a Flash Of Un-styled Component (see FOUC). Our CSS framework will do this for you, as long as it is loaded before the components.

If you set a property/attribute on a custom element before it’s loaded, it will be applied correctly and will use the values once it’s loaded. However, you cannot call a method on a component before the component is loaded.

Most of the time this is not an issue, as you will be calling methods in event handlers etc, when the component has already loaded. In cases where you want to call a method as soon as possible, for example on page load, you need to wait for the component to be defined, using customElements.whenDefined:

<nord-date-picker id="loading-example" label="Enter date"></nord-date-picker>

<script type="module">
const picker = document.querySelector("#loading-example")

// It's fine to set properties while components are still loading
picker.isDateDisabled = function isWeekend(date) {
return date.getDay() === 0 || date.getDay() === 6
}

// but if you want to immediately call a method,
// you should wait for the component to be defined
await customElements.whenDefined("nord-date-picker")
picker.focus({ preventScroll: true })
</script>
Edit in CodePen

Code completion for VS Code #

We generate TypeScript type definitions for all our Web Components, including the React wrappers. This will allow VS Code, and other editors, to offer code completion and type information for properties and methods, whether using TypeScript or not.


Form controls #

All our input components raise change events, and where it makes sense input events. These are useful for client-side validation, or for gathering values in javascript-based apps like with Vue.js or React.

Submit
<form id="form-events-example">
<nord-stack>
<nord-input label="First name" name="firstName"></nord-input>
<nord-input label="Last name" name="lastName"></nord-input>
<nord-button variant="primary" type="submit">Submit</nord-button>
<output></output>
</nord-stack>
</form>

<script type="module">
const data = {}
const form = document.querySelector("#form-events-example")
const output = form.querySelector("output")

// Input events bubbling up from input components
form.addEventListener("input", e => {
data[e.target.name] = e.target.value
})

form.addEventListener("submit", e=> {
e.preventDefault()
output.innerHTML = `<code>${JSON.stringify(data)}</code>`
})
</script>
Edit in CodePen

For server-rendered apps, our components hook into the browser’s formdata event, which means that our components’ values will be submitted as part of POST/GET traditional form submissions, like native HTML elements:

Submit
<form id="form-submission-example">
<nord-stack>
<nord-input label="First name" name="firstName"></nord-input>
<nord-input label="Last name" name="lastName"></nord-input>
<nord-button variant="primary" type="submit">Submit</nord-button>
<output></output>
</nord-stack>
</form>

<script type="module">
const form = document.querySelector("#form-submission-example")
const output = form.querySelector("output")

const url = new URL(location.href)

if (url.searchParams) {
output.innerHTML = `<code>${url.searchParams}</code>`
}
</script>
Edit in CodePen

The browser’s built-in FormData object can also be used to get all values from a form via JavaScript:

Submit
<form id="form-data-example">
<nord-stack>
<nord-input label="First name" name="firstName"></nord-input>
<nord-input label="Last name" name="lastName"></nord-input>
<nord-button variant="primary" type="submit">Submit</nord-button>
<output></output>
</nord-stack>

</form>

<script type="module">
const form = document.querySelector("#form-data-example")
const output = form.querySelector("output")

form.addEventListener("submit", e => {
e.preventDefault()
const data = new FormData(form)

// This is an example, refer to MDN for more info about FormData.
output.innerHTML = `<code>${JSON.stringify(Object.fromEntries(data))}</code>`
})
</script>
Edit in CodePen

Localization #

This section is still under work.

React #

Whilst React supports Web Components, they are very awkward to use as-is. For this reason, we provide React-specific wrapper components in the package @nordhealth/react. This will allow you to use the Nord components as you would any other React component.

A planned future release of React will greatly improve support for Web Components, which will make the wrapper components unnecessary. But until then, we recommend their use.

View example React project

Installation #

Install with npm:

npm install @nordhealth/react @nordhealth/css --save

or yarn:

yarn add @nordhealth/react @nordhealth/css

Usage #

You must import @nordhealth/css once in your main entry point, then import components from @nordhealth/react wherever they are needed:

import { useState } from "react"
import ReactDOM from "react-dom"
import "@nordhealth/css"
import { Button } from "@nordhealth/react"

function App() {
const [count, setCount] = useState(0)

return (
<Button
variant="primary"
onClick={() => setCount(count + 1)}
>
Clicks: {count}
</Button>
)
}

ReactDOM.render(
<App />,
document.querySelector("#app")
)
Note: as of React 18, there is a new API for rendering to the DOM. Please see the react docs for more info.

Vue #

Vue.js has excellent support for Web Components out of the box, it only requires a little configuration.

View example Vue.js project

Installation #

Install with npm:

npm install @nordhealth/components @nordhealth/css --save

or yarn:

yarn add @nordhealth/components @nordhealth/css

Configuration #

Vue.js needs to be configured to recognize Web Components. If you’re using Vite, it can be done like this:

// vite.config.js
import vue from '@vitejs/plugin-vue'

export default {
plugins: [
vue({
template: {
compilerOptions: {
// treat all tags with a dash as custom elements
isCustomElement: (tag) => tag.includes('-')
}
}
})
]
}

For more information, and how to configure for other setups (e.g. Vue CLI), please see the Vue docs.

Usage #

You must import the @nordhealth/components and @nordhealth/css packages in your main entry point:

// main.js
import '@nordhealth/css';
import '@nordhealth/components';

import { createApp } from 'vue';
import App from './App.vue';

createApp(App).mount('#app');

Then you can use the Nord’s components throughout your app. For instance, here is an example using a single-file component:

<script setup>
import { ref } from 'vue';

const count = ref(0);
</script>

<template>
<nord-button variant="primary" @click="count++">
Count is: {{ count }}
</nord-button>
</template>

Our components also support the v-model directive for two-way data binding:

<script setup>
import { ref } from 'vue';

const name = ref("")
</script>

<template>
<nord-input label="Name" v-model="name"></nord-input>
<output>{{ name }}</output>
</template>

Sometimes, you may need to pass complex data such as objects, arrays, and functions. These must be passed to a web component as properties rather than attributes. For the most part, Vue.js does the correct thing, and will handle this without any particular treatment.

However, there may be rare cases where you need to be more explicit that you’re supplying a property. For this, Vue.js has the syntax .propName="value", where propName is the name of the property.

For instance, here is an example of passing a function to a component:

<script setup>
const isWeekend = (date) => date.getDay() === 0 || date.getDay() === 6
</script>

<template>
<nord-date-picker label="Date of birth" .isDateDisabled="isWeekend"></nord-date-picker>
</template>

Can I use this in my own project? #

Nord Design System is solely meant for building digital products and experiences for Nordhealth. Please see the terms of use for full license details.


Support #

Need help with our Web Components? Please head over to the Support page for more guidelines and ways to contact us.


Attribution #

Special thanks to the following projects that help make Nord possible.


Was this page helpful?

YesNo
Send feedback

We use this feedback to improve our documentation.

 
Edit page