Skip to main content
LocalTapiola Turva

Using Components #

Duet makes it easy 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.

Integrating Duet’s components to a project without a JavaScript framework is straight forward. If you’re working on a simple HTML page, you can start using the components immediately by adding these script tags to the <head>:

<script type="module" src="https://cdn.jsdelivr.net/npm/@duetds/components@latest/lib/duet/duet.esm.js"></script>
<script nomodule src="https://cdn.jsdelivr.net/npm/@duetds/components@latest/lib/duet/duet.js"></script>

Once included, components can be used in your markup like any other regular HTML elements:

<duet-input label="Your name" placeholder="John Doe"></duet-input>
<duet-button variation="primary">Send</duet-button>

To load the correct webfonts as well, add either one of these tags to the <head>, depending on which theme you’re working on:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@duetds/fonts@latest/lib/localtapiola.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@duetds/fonts@latest/lib/turva.css" />

Please note: While including components directly from JSDelivr is convenient for quick prototyping and building simple websites, we recommend that for production usage you install the packages using NPM and host the different parts yourself. Below you can find instructions on how to do that with and without different JavaScript frameworks.

For an up-to-date list of components included and their respective documentations, see Component status page.


Installation #

Before moving further, 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 Duet Components in a project that doesn’t yet use Node Package Manager, you’ll have to first create a package.json file. To do so, run npm init and follow the steps provided.

Once finished, you can install components by running one of:

// WEB COMPONENTS for Angular, Ember, Vue.js, and Vanilla JS:
// (The recommended way if you’re not using React)
npm install @duetds/components
// REACT COMPONENTS (experimental):
npm install @duetds/react
// ANGULAR COMPONENTS (experimental):
// (For stable releases, use @duetds/components instead)
npm install @duetds/angular

While components work without these packages, it’s also recommended to install @duetds/css and @duetds/fonts for the best user experience:

// CSS FRAMEWORK (platform independent):
npm install @duetds/css

// WEBFONTS (platform independent):
npm install @duetds/fonts

Usage with basic HTML #

Once you’ve installed @duetds/components package into your project, it’s recommended to create a copy task that copies the component library from node_modules to a location you’ve speficied. One such tool that can do this is NCP. You can install ncp by running:

npm install ncp

Once installed, add a script to your package.json that copies the component library from Duet’s package into a location you’ve specified:

"scripts": {
  "copy:components": "ncp node_modules/@duetds/components/lib src/SPECIFY_YOUR_PATH"
}

You can call this script while starting up your app to make sure you’ve always got the latest component library copied over. If you’re using an UNIX-like environment, you can use & as the separator:

"start": "copy:components & dev"

Otherwise, if you need a cross-platform solution, use npm-run-all module:

"start": "npm-run-all copy:components dev"

Once you have a copy task in place and have copied the component library over, you can put script tags similar to these in the <head> of your index.html:

<script type="module" src="SPECIFY_YOUR_PATH/duet.esm.js"></script>
<script nomodule src="SPECIFY_YOUR_PATH/duet.js"></script>

Once included, components can be used in your basic HTML markup as in the following example:

<duet-button variation="primary">Send</duet-button>

For more concrete usage examples see the templates section and individual component examples in the documentation.


Usage with Angular #

Using @duetds/components within an Angular CLI project is a two-step process. To get started, you need to:

  1. Include the CUSTOM_ELEMENTS_SCHEMA in the modules that use the components.
  2. Call defineCustomElements(window) from main.ts (or other appropriate place).

1. Including the Custom Elements Schema #

Including the CUSTOM_ELEMENTS_SCHEMA in the module allows the use of the web components in the HTML markup without the compiler producing errors. Here is a simplified example of adding it to AppModule:

// ...
// Import custom elements schema
import { CUSTOM_ELEMENTS_SCHEMA } from "@angular/core";
@NgModule({
  // ...
  // Add custom elements schema to NgModule
  schemas: [CUSTOM_ELEMENTS_SCHEMA]
})
export class AppModule { }

The CUSTOM_ELEMENTS_SCHEMA needs to be included in any module that uses custom elements.

2. Calling defineCustomElements #

Duet Components include a main function that is used to load the components. That function is called defineCustomElements() and it needs to be called once during the bootstrapping of your application. One convenient place to do this is in main.ts as such:

// Import Duet Web Components
import { defineCustomElements } from "@duetds/components/lib/loader";
// ...
// Register Duet Web Components
defineCustomElements(window);

Once included, components can be used in your HTML markup as in the following example:

<duet-button variation="primary">Send</duet-button>

For more concrete usage examples see the templates section and individual component examples in the documentation.`

Edge and IE11 polyfills #

If you want your custom elements to be able to work on older browser, you should add the applyPolyfills() that surrond the defineCustomElements() function.

import { applyPolyfills, defineCustomElements } from "@duetds/components/lib/loader";
// ...
applyPolyfills().then(() => {
  defineCustomElements(window)
})

Accessing using ViewChild and ViewChildren #

Once included, components could also be referenced in your code using ViewChild and ViewChildren as shown in the Stencil.js documentation.

Angular wrapper for Web Components #

In addition to our Core Web Component library, we have an Angular wrapper that is currently in beta testing. This means that the support is experimental at the moment and subject to change. If you want to help us test it you can install the below package instead of @duetds/components:

npm install @duetds/angular

Once you’ve installed the package you can import Duet Angular components in your application:

import { DuetComponents } from "@duetds/angular";

@NgModule({
  //...
  imports: [
    DuetComponents
  ],
  //...
})
export class AppModule { }

Angular specific version gives types for your components and you also get the ability to use ngmodel on inputs and other form fields.


Usage with Vue.js #

To integrate @duetds/components into a Vue.js application, edit src/main.js to include:

// Import Duet Web Components
import { applyPolyfills, defineCustomElements } from "@duetds/components/lib/loader";
// ...
// configure Vue.js to ignore Duet Web Components
Vue.config.ignoredElements = [/duet-\w*/];
// Register Duet Web Components
applyPolyfills().then(() => {
    defineCustomElements(window);
});

new Vue({
    render: h => h(App)
}).$mount("#app");

Note that in the above scenario applyPolyfills is only needed if you are targeting Edge or IE11. Once included, components can be used in your HTML markup as in the following example:

<duet-button variation="primary">Send</duet-button>

For more concrete usage examples see the templates section and individual component examples in the documentation.`


Usage with React #

With an application built using the create-react-app script you can directly import the needed components from @duetds/react, which is a React specific wrapper created for Duet’s Web Components:

import React, { Component } from "react";
import { DuetButton } from "@duetds/react/lib";

export class ReactExample extends Component {
    handleEvent(ev) {
      ev.preventDefault()
      // Perform an action
    }
    render() {
        return (
            <DuetButton variation="primary" onClick={handleEvent}>
              Click me
            </DuetButton>
        );
    }
}

React wrapper for @duetds/components includes two key differences to our core components bundle that you need to take into account:

  1. Component names start with an uppercase letter and use CamelCase format instead of kebab-case. For example <DuetNav> or <DuetButton>.

  2. All events start with on. So if you consider for example the navigation component that has custom duetChange event, that translates to onDuetChange when using Duet’s React library:

import React, { Component } from "react";
import { DuetNav } from "@duetds/react/lib";

export class ReactExample extends Component {
    handleEvent(ev) {
      const event = ev.detail.originalEvent
      event.preventDefault()
      // Perform an action
    }
    render() {
        return (
            <DuetNav
              current-href="/"
              language="fi"
              region="Pääkaupunkiseutu"
              contact="Ota yhteyttä"
              onDuetChange={handleEvent}
              items={[
                { label: "Etusivu", href: "/" },
                { label: "Vakuutukset", href: "#" },
                { label: "Vahinkoasiat", href: "#" },
                { label: "Säästöt ja sijoitukset", href: "#" },
                { label: "Laskut", href: "#", badge: true },
                { label: "Viestit", href: "#" }
              ]}>
            </DuetNav>
        );
    }
}

Please keep in mind that Duet Design System’s React support is experimental at the moment and subject to change.


Usage with Ember #

Duet components can be easily integrated into Ember thanks to the ember-cli-stencil addon that handles:

Start by installing the Ember addon:

ember install ember-cli-stencil

When you build your application, Stencil collections in your dependencies will be automatically discovered and pulled into your application. For more information, see ember-cli-stencil documentation.


Events #

We encourage the use of DOM events, but additionally provide custom events to make handling of certain event types easier. All custom events are always documented in component’s own documentation page.

One example of this is the Input component that provides custom events for detecting user input and value changes inside the input field:

<duet-input label="My input"></duet-input>

<script>
  // Select the above web component
  var input = document.querySelector("duet-input")

  // Add event listeners
  input.addEventListener("duetInput", function(e) {
    console.log("User input detected", e)
  })
  input.addEventListener("duetChange", function(e) {
    console.log("Change detected in input", e)
  })
</script>

Events in Angular #

example-component.html:

<duet-input #input
  [value]="textValue"
  (duetChange)="handleChange($event)">
</duet-input>

example-component.ts:

@Component({
  selector: "example-component",
  templateUrl: "./example-component.html",
})
export class ExampleComponent {
  @ViewChild("input") input: HTMLDuetInputElement;
  textValue = "Duet";
  handleChange(event) {
    // Value change event
  }
}

The typing information for all components is included in Duet Components package. To find it, see @duetds/components/lib/types/components.d.ts.

Events in Vue #

<template>
  <duet-input :value="textValue" v-on:duetChange="handleChange">
  </duet-input>
</template>

<script>
  export default {
    name: "InputExample",
    data: () => ({
      textValue: "Duet",
    }),
    methods: {
      handleChange(event) {
        // value change event
      },
    }
  }
</script>

Events in React #

import React, { Component } from "react";
import { DuetButton, DuetNav } from "@duetds/react/lib";

export class ReactExample extends Component {
  handleClick(ev) {
    // Perform an action
  }
  handleNavigation(ev) {
    const event = ev.detail.originalEvent
    event.preventDefault()
    // Perform an action
  }
  render() {
    return (
      <div>
        <DuetNav onDuetChange={handleNavigation}></DuetNav>
        <DuetButton onClick={handleClick}>Button</DuetButton>
      </div>
    );
  }
}

Theming #

Duet Design System’s components come in two themes: LocalTapiola and Turva. By default components use the LocalTapiola theme, but Duet allows you to define through a global CSS className or a local component property the currently active theme.

Changing theme globally #

To change a layout or the whole application to use Turva’s theme add .duet-theme-turva class to <html>:

<html class="duet-theme-turva">

Please note that there’s no dynamic watch task for the html class changes so the above only works if it’s in the html when the components are initialized.

Changing theme for a component #

To permanently set the theme of one or a few components, use the theme property:

<duet-component theme="turva"></duet-component>
<duet-component theme="default"></duet-component>

CSS Styles #

Duet’s components encapsulate their CSS styles and structure within Shadow DOM that prevents the injection of external styles. This means that you can’t override a component’s style with your own CSS. Instead, if the component looks or behaves incorrectly in your application and none of the provided component properties help, it’s most likely an issue in Duet and should be fixed here instead.

The components do however provide a way to disable their automatic space handling (margin and padding). All components come built-in with a property called margin that allows you to set it to either "auto" or "none".

When the margin property is set to "auto" the component will automatically take care of its surrounding space, but for cases when you want to remove the margins completely, you can use the "none" setting.

Additionally, some components come with more granular options for the margin property and also provide a property called padding that controls the inner spacing.

Finally, Duet also includes a component called Spacer that allows you to tweak the horizontal and vertical space between UI parts using Space Tokens.

You can’t override component’s styles with your own CSS. Instead, if the component looks or behaves incorrectly and none of the provided props help, it’s an issue in Duet and should be fixed here instead.


Troubleshooting #

If you experience any issues while setting up the Components, please head over to the Support page for more guidelines and help.

Additionally, you might find Stencil.js’s documentation helpful as we use Stencil to compile Duet’s Web Components.