Building Layouts #
Following this tutorial you will learn how to build simple page layouts using Duet’s Design Tokens, CSS Framework, Web Components and other features.
For the sake of simplicity, this tutorial is framework agnostic and imports the different parts of Duet directly from JSDelivr. For production usage we recommend that you install the packages using NPM and host the different parts yourself.
Getting started #
As the first step, you will want to create a basic HTML page that can be used for building the layout. There are no explicit requirements on what the HTML markup should look like, so let’s just go ahead and create a simple page with the correct lang
attribute and a placeholder <title>
:
<!doctype html>
<html lang="fi">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Ota yhteyttä | LähiTapiola</title>
</head>
<body></body>
</html>
Next, you need to import the necessary packages from Duet Design System in order to utilize them. For this particular layout, we want to use Fonts, CSS Framework and Web Components. To import these packages, add the following tags onto your page’s <head>
section:
<!-- Fonts -->
<link rel="stylesheet" href="https://cdn.duetds.com/api/fonts/3.0.51/lib/localtapiola.css" integrity="sha384-5JYmtSD7nykpUvSmTW1CHMoBDkBZUpUmG0vuh+NUVtZag3F75Kr7+/JU3J7JV6Wq" crossorigin="anonymous" />
<!-- CSS Framework -->
<link rel="stylesheet" href="https://cdn.duetds.com/api/css/4.0.45/lib/duet.min.css" integrity="sha384-UoMJnpXiN8f7fKVnTzfKfyi7LzQlApQ+WTS9O3PXlYr6CO9yzou4glfsHV747f3v" crossorigin="anonymous" />
<!-- Components -->
<script type="module" src="https://cdn.duetds.com/api/components/8.7.1/lib/duet/duet.esm.js" integrity="sha384-c3hLghWHTPntUxndMlK4myD7d59stA2U0EvBp2rPb3ibtacAwh56geBpq6z7nXLn" crossorigin="anonymous"></script>
<script nomodule src="https://cdn.duetds.com/api/components/8.7.1/lib/duet/duet.js" integrity="sha384-H7RH4Ssj/LmElXa1VCHFSIjvtCSoLXMiPXG/KQZTS9EvYujTo7tWaj0V6/GGkY16" crossorigin="anonymous"></script>
Once you’ve added each package shown above, the markup for the HTML page should look about like this:
<!doctype html>
<html lang="fi">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Ota yhteyttä | LähiTapiola</title>
<link rel="stylesheet" href="https://cdn.duetds.com/api/fonts/3.0.51/lib/localtapiola.css" integrity="sha384-5JYmtSD7nykpUvSmTW1CHMoBDkBZUpUmG0vuh+NUVtZag3F75Kr7+/JU3J7JV6Wq" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdn.duetds.com/api/css/4.0.45/lib/duet.min.css" integrity="sha384-UoMJnpXiN8f7fKVnTzfKfyi7LzQlApQ+WTS9O3PXlYr6CO9yzou4glfsHV747f3v" crossorigin="anonymous" />
<script type="module" src="https://cdn.duetds.com/api/components/8.7.1/lib/duet/duet.esm.js" integrity="sha384-c3hLghWHTPntUxndMlK4myD7d59stA2U0EvBp2rPb3ibtacAwh56geBpq6z7nXLn" crossorigin="anonymous"></script>
<script nomodule src="https://cdn.duetds.com/api/components/8.7.1/lib/duet/duet.js" integrity="sha384-H7RH4Ssj/LmElXa1VCHFSIjvtCSoLXMiPXG/KQZTS9EvYujTo7tWaj0V6/GGkY16" crossorigin="anonymous"></script>
</head>
<body></body>
</html>
That’s all that’s required to start building completele layouts with Duet. In the next chapter we’ll cover the basics of Duet’s layout components and how to create the foundations for the rest of the content.
Laying foundations #
Duet Design System contains certain components that should be used on most page layouts. One of those components is called Layout. Layout component, while not visible in the user interface itself, provides a structure for other components using a one or two column layout system.
To get started using Layout, add it inside your page’s <body>
:
<body>
<duet-layout></duet-layout>
</body>
<duet-layout>
has three content areas which are called top
, main
and sidebar
. To place content inside the main
content area you need to first create a new element and tell it which area you want to render it in:
<body>
<duet-layout>
<div slot="main">Some content…</div>
</duet-layout>
</body>
The above example renders “Some content…” text inside the Layout component’s main
content area. In Web Component terms content areas are called “slots” which is where the attribute name also comes from.
Most of the time we also want our page to contain a header and a footer. You can add them, together with a few additional menu links like so:
<!doctype html>
<html lang="fi" class="duet-sticky-footer">
<head>...</head>
<body>
<duet-header></duet-header>
<duet-layout>
<div slot="main">Some content…</div>
</duet-layout>
<duet-footer
menu='[
{ "label": "Turvallisuus ja käyttöehdot", "href": "#" },
{ "label": "Evästeet", "href": "#" },
{ "label": "Henkilötietojen käsittely", "href": "#" }
]'>
</duet-footer>
</body>
</html>
Notice how we’ve also added .duet-sticky-footer
class to <html>
element. This makes sure our Footer always stays sticky at the bottom of the page, no matter how little content there might be before it.
At this point our page looks like this:
To make it a little nicer, let’s split the main content into two columns, add a background gradient from Duet’s CSS Framework, and use Card component to wrap our content:
<!doctype html>
<html lang="fi" class="duet-sticky-footer duet-bg-gradient">
<head>...</head>
<body>
<duet-header></duet-header>
<duet-layout>
<div slot="main">
<duet-card heading="Main" padding="large">
<duet-paragraph>Main content</duet-paragraph>
</duet-card>
</div>
<div slot="sidebar">
<duet-card heading="Sidebar">Sidebar content</duet-card>
</div>
</duet-layout>
<duet-footer
menu='[
{ "label": "Turvallisuus ja käyttöehdot", "href": "#" },
{ "label": "Evästeet", "href": "#" },
{ "label": "Henkilötietojen käsittely", "href": "#" }
]'>
</duet-footer>
</body>
</html>
With the above markup we’ve now created a basic page layout to build upon:
Working with components #
The underlying idea with Duet’s Components is that a developer can simply lay them on a page and the components themselves will take care of the surrounding space. This means that most of the time there shoudn’t be a need to use custom, application specific margins or paddings, for anything that’s coming from Duet.
In cases when you do need to adjust the spacing or margins, you can use Duet’s Spacer component and the provided Space Design Tokens.
As the next step, let’s create a simple contact form on the page we just did. This will help you understand how Duet’s components automatically handle the spacing in-between components and how the Spacer component can be used.
Modify your previous markup to include a form in the Layout component’s main content area:
<duet-layout>
<div slot="main">
<duet-card padding="large">
<form novalidate>
</form>
</duet-card>
</div>
</duet-layout>
Next, let’s add in some form elements, including two inputs, a textarea and a submit button:
<duet-layout>
<div slot="main">
<duet-card padding="large">
<form novalidate>
<duet-input label="Nimi" placeholder="Matti Meikäläinen" expand></duet-input>
<duet-input label="Sähköposti" type="email" placeholder="nimi@email.com" expand></duet-input>
<duet-textarea label="Viesti asiakaspalveluun" placeholder="Kirjoita tähän" expand></duet-textarea>
<duet-button submit variation="primary">Lähetä</duet-button>
</form>
</duet-card>
</div>
</duet-layout>
Finally, we’ll also add a little bit of text content and adjust the spacing slightly by adding two <duet-spacer/>
components after the first paragraph and just before the submit button:
<duet-layout>
<div slot="main">
<duet-card padding="large">
<form novalidate>
<duet-heading level="h2">Ota yhteyttä</duet-heading>
<duet-paragraph>
Lähetä meille viesti kun haluat antaa palautetta tai pyytää
yhteydenottoa. Jos olet jo asiakkaamme, asiasi hoituu parhaiten,
kun kirjaudut verkkopalveluun.
</duet-paragraph>
<duet-spacer></duet-spacer>
<duet-input label="Nimi" placeholder="Matti Meikäläinen" expand></duet-input>
<duet-input label="Sähköposti" type="email" placeholder="nimi@email.com" expand></duet-input>
<duet-textarea label="Viesti asiakaspalveluun" placeholder="Kirjoita tähän" expand></duet-textarea>
<duet-spacer size="x-large"></duet-spacer>
<duet-button submit variation="primary">Lähetä</duet-button>
</form>
</duet-card>
</div>
<div slot="sidebar">
<duet-card padding="large" heading="Sivupalsta">
Sivupalstaa voidaan käyttää pääsisältöön liittyvän tiedon näyttämiseen
tai vaihtoehtoisesti nostamaan esiin aiheeseen liittyvää muuta sisältöä.
</duet-card>
</div>
</duet-layout>
The above markup produces now the following results:
As you can see the above webpage looks already pretty balanced without the need to add any custom CSS styles or elements onto the page.
Next, we could add a little more content to our Footer component. To achieve this, we can pass an array of items through a property called items
:
<duet-footer
items='[
{ "label": "Hae korvausta", "href": "#", "icon": "navigation-make-claim" },
{ "label": "Osta vakuutus", "href": "#", "icon": "action-buy-insurance" },
{ "label": "Yhteystiedot", "href": "#", "icon": "form-tel" }
]'
menu='[
{ "label": "Turvallisuus ja käyttöehdot", "href": "#" },
{ "label": "Evästeet", "href": "#" },
{ "label": "Henkilötietojen käsittely", "href": "#" }
]'>
</duet-footer>
The above markup produces an additional menu for the footer:
To make our page layout ready, let’s add the rest of the header functionality:
<duet-header
current-href="/yhteystiedot/"
session='{ "label": "Kirjaudu sisään", "href": "/?login", "type": "login" }'
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": "#" }
]'>
</duet-header>
<duet-layout>
..
</duet-layout>
With these final changes, we’ve finished our first page layout.
Ready page layout: #
Ready page markup: #
<!doctype html>
<html lang="fi" class="duet-sticky-footer duet-bg-gradient">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Ota yhteyttä | LähiTapiola</title>
<link rel="stylesheet" href="https://cdn.duetds.com/api/fonts/3.0.51/lib/localtapiola.css" integrity="sha384-5JYmtSD7nykpUvSmTW1CHMoBDkBZUpUmG0vuh+NUVtZag3F75Kr7+/JU3J7JV6Wq" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdn.duetds.com/api/css/4.0.45/lib/duet.min.css" integrity="sha384-UoMJnpXiN8f7fKVnTzfKfyi7LzQlApQ+WTS9O3PXlYr6CO9yzou4glfsHV747f3v" crossorigin="anonymous" />
<script type="module" src="https://cdn.duetds.com/api/components/8.7.1/lib/duet/duet.esm.js" integrity="sha384-c3hLghWHTPntUxndMlK4myD7d59stA2U0EvBp2rPb3ibtacAwh56geBpq6z7nXLn" crossorigin="anonymous"></script>
<script nomodule src="https://cdn.duetds.com/api/components/8.7.1/lib/duet/duet.js" integrity="sha384-H7RH4Ssj/LmElXa1VCHFSIjvtCSoLXMiPXG/KQZTS9EvYujTo7tWaj0V6/GGkY16" crossorigin="anonymous"></script>
</head>
<body>
<duet-header
current-href="/yhteystiedot/"
session='{ "label": "Kirjaudu sisään", "href": "/?login", "type": "login" }'
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": "#" }
]'>
</duet-header>
<duet-layout>
<div slot="main">
<duet-card padding="large">
<form novalidate>
<duet-heading level="h2">Ota yhteyttä</duet-heading>
<duet-paragraph>
Lähetä meille viesti kun haluat antaa palautetta tai pyytää
yhteydenottoa. Jos olet jo asiakkaamme, asiasi hoituu parhaiten,
kun kirjaudut verkkopalveluun.
</duet-paragraph>
<duet-spacer></duet-spacer>
<duet-input label="Nimi" placeholder="Matti Meikäläinen" expand></duet-input>
<duet-input label="Sähköposti" type="email" placeholder="nimi@email.com" expand></duet-input>
<duet-textarea label="Viesti asiakaspalveluun" placeholder="Kirjoita tähän" expand></duet-textarea>
<duet-spacer size="x-large"></duet-spacer>
<duet-button submit variation="primary">Lähetä</duet-button>
</form>
</duet-card>
</div>
<div slot="sidebar">
<duet-card padding="large" heading="Sivupalsta">
Sivupalstaa voidaan käyttää pääsisältöön liittyvän tiedon näyttämiseen
tai vaihtoehtoisesti nostamaan esiin aiheeseen liittyvää muuta sisältöä.
</duet-card>
</div>
</duet-layout>
<duet-footer
items='[
{ "label": "Hae korvausta", "href": "#", "icon": "navigation-make-claim" },
{ "label": "Osta vakuutus", "href": "#", "icon": "action-buy-insurance" },
{ "label": "Yhteystiedot", "href": "#", "icon": "form-tel" }
]'
menu='[
{ "label": "Turvallisuus ja käyttöehdot", "href": "#" },
{ "label": "Evästeet", "href": "#" },
{ "label": "Henkilötietojen käsittely", "href": "#" }
]'>
</duet-footer>
</body>
</html>