Stepper
Ready
This template shows how to use Duet’s Stepper and Step components to create a purchase flow. Please note that the example below does not represent a real use case.
Hint: Press F
on your keyboard to view both templates and components in fullscreen and
ESC
to exit the fullscreen mode. You can also open the template in
a new browser window.
<!DOCTYPE html>
<html class="duet-bg-gradient duet-sticky-footer" lang="fi">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>LähiTapiola</title>
<link rel="stylesheet" href="https://cdn.duetds.com/api/fonts/1.3.14/lib/localtapiola.css" integrity="sha384-5JYmtSD7nykpUvSmTW1CHMoBDkBZUpUmG0vuh+NUVtZag3F75Kr7+/JU3J7JV6Wq" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdn.duetds.com/api/css/1.5.9/lib/duet.min.css" integrity="sha384-cHX7qxsSfeUXP2Tf8b/MGbtDLnSqAHzrVc+mZifscbVQ3EopINZDcHN92Gl7k9p9" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdn.duetds.com/api/tokens/2.2.0/lib/tokens.custom-properties.css" integrity="sha384-3eJu0Du/l2+ojLsW1c3OJn6nBhM6VTq557/x8gQ629TNppo9qTg9u8TmxN8pJ7B0" crossorigin="anonymous" />
<script type="module" src="/components/duet.esm.js"></script>
<script nomodule src="/components/duet.js"></script>
</head>
<body>
<style>
html {
scroll-behavior: smooth;
}
.price,
#links {
display: none;
}
.has-price .price,
.has-price #links {
display: block;
}
.has-price .price-placeholder {
display: none;
}
.breakdown-list {
list-style: none;
font-weight: var(--font-weight-semi-bold);
padding: 0;
margin: 0;
margin-bottom: var(--space-small);
}
.breakdown-list li {
font-size: var(--font-size-small);
}
.breakdown-list li + li {
margin-top: var(--space-xx-small);
}
.link-list a {
border-bottom: 1px solid var(--color-gray-light);
font-weight: var(--font-weight-semi-bold);
font-size: var(--font-size-small);
padding: var(--space-x-small) 0;
justify-content: space-between;
text-decoration: none;
align-items: center;
display: flex;
width: 100%;
}
.link-list a:first-of-type {
border-top: 1px solid var(--color-gray-light);
}
</style>
<duet-header language="fi" skip-to-id="#content"></duet-header>
<duet-hero
heading="Eläinvakuutus. Vaivattomasti. Vain muutamassa minuutissa."
image="/work/duet-design-system/assets/illustrations/placeholder-dark.svg"
button-label="Aloita tästä"
variation="light"
button-url="#start"
margin="none"
icon="navigation-arrow-down"
icon-right
id="content">
</duet-hero>
<duet-layout id="start" sticky sticky-distance="without-links">
<div slot="main">
<duet-tray>
<duet-grid alignment="center">
<duet-grid-item margin="none" fill>
<duet-paragraph size="small" margin="none">Vuosimaksu</duet-paragraph>
</duet-grid-item>
<duet-grid-item margin="none">
<span class="duet-font-size-m duet-font-weight-semi-bold">189,90 €</span>
</duet-grid-item>
</duet-grid>
<div slot="additional">
<div class="link-list">
<a href="#" target="_blank">
<span class="duet-mr-xx-small">Liikennevakuutuksen tiedot</span>
<duet-icon name="action-new-window-small" size="xx-small" margin="none"></duet-icon>
<duet-visually-hidden>Aukeaa uuteen ikkunaan</duet-visually-hidden>
</a>
<a href="#" target="_blank">
<span class="duet-mr-xx-small">Kaskovakuutuksen tiedot</span>
<duet-icon name="action-new-window-small" size="xx-small" margin="none"></duet-icon>
<duet-visually-hidden>Aukeaa uuteen ikkunaan</duet-visually-hidden>
</a>
<a href="#" target="_blank">
<span class="duet-mr-xx-small">Liikennevakuutusehdot</span>
<duet-icon name="action-new-window-small" size="xx-small" margin="none"></duet-icon>
<duet-visually-hidden>Aukeaa uuteen ikkunaan</duet-visually-hidden>
</a>
<a href="#" target="_blank">
<span class="duet-mr-xx-small">Kaskovakuutuksehdot</span>
<duet-icon name="action-new-window-small" size="xx-small" margin="none"></duet-icon>
<duet-visually-hidden>Aukeaa uuteen ikkunaan</duet-visually-hidden>
</a>
<a href="#" target="_blank">
<span class="duet-mr-xx-small">Tuoteseloste</span>
<duet-icon name="action-new-window-small" size="xx-small" margin="none"></duet-icon>
<duet-visually-hidden>Aukeaa uuteen ikkunaan</duet-visually-hidden>
</a>
</div>
</div>
</duet-tray>
<duet-stepper margin="none">
<duet-step heading="Perustiedot">
<form>
<duet-caption>
Tee valinnat ja täytä kaikki kentät, ellei toisin mainita. Huomaathan, että vakuutuksen myöntämiseen
vaikuttaa eläimen terveyden tila.
</duet-caption>
<duet-spacer size="x-small"></duet-spacer>
<duet-choice-group
value="1"
label="Millainen lemmikkisi on?"
direction="horizontal"
name="pet"
responsive
>
<duet-choice label="Koira" type="radio" value="1" expand></duet-choice>
<duet-choice label="Kissa" type="radio" value="2" expand></duet-choice>
<duet-choice label="Hevonen" type="radio" value="3" expand></duet-choice>
</duet-choice-group>
<duet-input label="Rotu" name="breed" placeholder="Labradorinnoutaja" expand required></duet-input>
<duet-grid responsive breakpoint="medium" direction="horizontal" alignment="stretch">
<duet-input label="Syntymäaika" name="dob" placeholder="24.8.2011" expand required></duet-input>
<duet-grid-item min-width="calc(66.666% + 8px)" fill></duet-grid-item>
</duet-grid>
<duet-grid responsive breakpoint="medium" direction="horizontal" alignment="stretch">
<duet-input label="Nimi" name="name" placeholder="Lila" expand required></duet-input>
<duet-grid-item min-width="calc(33.333% + 8px)" fill></duet-grid-item>
</duet-grid>
<duet-spacer size="large"></duet-spacer>
<duet-grid responsive breakpoint="medium" direction="horizontal" alignment="stretch">
<duet-button variation="primary" submit expand wrapping="none">Laske hinta</duet-button>
<duet-grid-item min-width="calc(66.666% + 8px)" fill></duet-grid-item>
</duet-grid>
</form>
</duet-step>
<duet-step heading="Tarkemmat tiedot">
<form>
<duet-caption>
Lorem ipsum dolor sit amet consectetuer adipiscing elit no nummy laoreet ipsum dolor sit amet
consectetuer adipiscing elit no nummy laoreet consectetuer adipiscing.
</duet-caption>
<duet-button variation="primary" submit>Seuraava</duet-button>
</form>
</duet-step>
<duet-step heading="Vakuutustiedot">
<form>
<duet-caption>
Lorem ipsum dolor sit amet consectetuer adipiscing elit no nummy laoreet ipsum dolor sit amet
consectetuer adipiscing elit no nummy laoreet consectetuer adipiscing.
</duet-caption>
<duet-button variation="primary" submit>Seuraava</duet-button>
</form>
</duet-step>
<duet-step heading="Yhteenveto">
<form>
<duet-caption>
Lorem ipsum dolor sit amet consectetuer adipiscing elit no nummy laoreet ipsum dolor sit amet
consectetuer adipiscing elit no nummy laoreet consectetuer adipiscing.
</duet-caption>
<duet-button variation="primary" submit>Seuraava</duet-button>
</form>
</duet-step>
<duet-step heading="Terveysselvitys">
<duet-caption>
Lorem ipsum dolor sit amet consectetuer adipiscing elit no nummy laoreet ipsum dolor sit
amet consectetuer adipiscing elit no nummy laoreet consectetuer adipiscing.
</duet-caption>
</duet-step>
</duet-stepper>
</div>
<div slot="sidebar">
<duet-card padding="small" id="price">
<duet-heading level="h2" visual-level="h4">Vakuutusmaksu</duet-heading>
<div class="price">
<ul class="breakdown-list" role="list">
<li>Matkustajan hoitoturva</li>
<li>Tapaturmaisen pysyvän haitan turva</li>
<li>Tapaturmaisen kuoleman turva</li>
<li>Matkatavaravakuutus</li>
</ul>
<duet-grid distribution="space-between" alignment="center">
<duet-grid-item margin="none">
<span class="duet-font-weight-semi-bold duet-font-size-small">Yhteensä</span>
</duet-grid-item>
<duet-grid-item margin="none">
<span class="duet-font-weight-semi-bold duet-font-size-small">189,90 €</span>
</duet-grid-item>
</duet-grid>
</div>
<duet-caption class="price-placeholder">Täytä perustiedot nähdäksesi hinta.</duet-caption>
</duet-card>
<duet-card id="links" padding="small">
<duet-heading level="h2" visual-level="h4">Vakuutukseen liittyvät asiakirjat</duet-heading>
<duet-spacer size="x-small"></duet-spacer>
<div class="link-list">
<a href="#" target="_blank">
<span class="duet-mr-xx-small">Liikennevakuutuksen tiedot</span>
<duet-icon name="action-new-window-small" size="xx-small" margin="none"></duet-icon>
<duet-visually-hidden>Aukeaa uuteen ikkunaan</duet-visually-hidden>
</a>
<a href="#" target="_blank">
<span class="duet-mr-xx-small">Kaskovakuutuksen tiedot</span>
<duet-icon name="action-new-window-small" size="xx-small" margin="none"></duet-icon>
<duet-visually-hidden>Aukeaa uuteen ikkunaan</duet-visually-hidden>
</a>
<a href="#" target="_blank">
<span class="duet-mr-xx-small">Liikennevakuutusehdot</span>
<duet-icon name="action-new-window-small" size="xx-small" margin="none"></duet-icon>
<duet-visually-hidden>Aukeaa uuteen ikkunaan</duet-visually-hidden>
</a>
<a href="#" target="_blank">
<span class="duet-mr-xx-small">Kaskovakuutuksehdot</span>
<duet-icon name="action-new-window-small" size="xx-small" margin="none"></duet-icon>
<duet-visually-hidden>Aukeaa uuteen ikkunaan</duet-visually-hidden>
</a>
<a href="#" target="_blank">
<span class="duet-mr-xx-small">Tuoteseloste</span>
<duet-icon name="action-new-window-small" size="xx-small" margin="none"></duet-icon>
<duet-visually-hidden>Aukeaa uuteen ikkunaan</duet-visually-hidden>
</a>
</div>
</duet-card>
</div>
</duet-layout>
<duet-footer logo-href="#" language="fi"></duet-footer>
<script>
// Save references to components we want to adjust below
var header = document.querySelector("duet-header")
var footer = document.querySelector("duet-footer")
var stepper = document.querySelector("duet-stepper")
var nextButtons = document.querySelectorAll("duet-button.next")
var tray = document.querySelector("duet-tray")
var hero = document.querySelector("duet-hero")
// Set the language menu items
header.languageItems = [
{ label: "Suomeksi", country: "fi", href: "/work/duet-design-system/?lang=fi" },
{ label: "På Svenska", country: "sv", href: "/work/duet-design-system/?lang=sv" },
{ label: "In English", country: "en", href: "/work/duet-design-system/?lang=en" }
]
// Set the contact menu items
header.contactItems = [
{ label: "Lähetä viesti", href: "/work/duet-design-system/viestit/laheta" },
{ label: "Avaa chat", href: "/work/duet-design-system/chat/" },
{ label: "Yhteystiedot", href: "/work/duet-design-system/yhteystiedot/" }
]
// Set label and href for session link
header.session = {
label: "Kirjaudu ulos",
href: "/work/duet-design-system/?logout",
type: "logout"
}
// Set label and href for user profile link
header.user = {
label: "Laura",
href: "/work/duet-design-system/?userId=1234"
}
// Listen for change events inside the navigation component
// prevent header links causing a navigation
function preventDefault(e) {
e.detail.originalEvent.preventDefault()
}
header.addEventListener("duetSessionClick", preventDefault)
header.addEventListener("duetUserClick", preventDefault)
header.addEventListener("duetLanguageSelect", preventDefault)
header.addEventListener("duetLogoClick", preventDefault)
header.addEventListener("duetContactClick", preventDefault)
// piece of state to track whether page is "loading"
var isLoading = false
function updateSelectedStep(stepIndex) {
stepper.selected = stepIndex
window.scrollTo(0, stepper.getBoundingClientRect().top + window.pageYOffset - 140)
tray.active = stepper.selected !== 0
document.documentElement.classList.toggle("has-price", stepper.selected !== 0)
}
// disables/enables all inputs associated with the given form.
// sets the loading state of the submit button.
function setFormLoadingState(form, loading) {
isLoading = loading
form.setAttribute("aria-busy", loading)
var button = form.querySelector("duet-button[submit]")
button.loading = isLoading
Array.from(form.elements).forEach(function(input) {
input.disabled = isLoading
})
}
function handleFormSubmit(e) {
e.preventDefault()
if (isLoading) {
return
}
// random loading duration of 2-3 seconds
var loadingDuration = 2000 + Math.random()
var form = e.target
setFormLoadingState(form, true)
setTimeout(function() {
setFormLoadingState(form, false)
updateSelectedStep(stepper.selected + 1)
}, loadingDuration)
}
function handleStepChange(e) {
if (!isLoading) {
updateSelectedStep(e.detail.toStep)
}
}
// when each step is completed, advance to next step after loading
document.addEventListener("submit", handleFormSubmit)
// duetStepChange event is raised whenever a step heading is clicked
// when this happens, change to that step
stepper.addEventListener("duetStepChange", handleStepChange)
// basic dirty tracking, used to show warning on navigation
var isDirty = false
function handleChange(e) {
isDirty = true
}
document.querySelector("[name='pet']").addEventListener("duetChange", handleChange)
document.querySelector("[name='breed']").addEventListener("duetChange", handleChange)
document.querySelector("[name='dob']").addEventListener("duetChange", handleChange)
document.querySelector("[name='name']").addEventListener("duetChange", handleChange)
window.addEventListener("beforeunload", function(e) {
if (isDirty) {
e.preventDefault()
e.returnValue = ""
}
})
// Set the main links in footer
footer.items = [
{ label: 'Hae korvausta', href: '#', icon: 'navigation-make-claim' },
{ label: 'Osta vakuutus', href: '#', icon: 'action-buy-insurance' },
{ label: 'Yhteystiedot', href: '#', icon: 'form-tel' }
]
// Set the help menu items in footer
footer.menu = [
{ label: 'Turvallisuus ja käyttöehdot', href: '#' },
{ label: 'Evästeet', href: '#' },
{ label: 'Henkilötietojen käsittely', href: '#' },
]
</script>
</body>
</html>
Integration
To install this template’s dependencies into your project, run:
npm install @duetds/components
npm install @duetds/css
npm install @duetds/fonts
For further guidelines, please see each package’s documentation.
Tutorials
Follow these practical tutorials to learn how to build simple page layouts using Duet’s CSS Framework, Web Components and other features:
Tutorials
Abstract
TutorialsCreating Custom Patterns
TutorialsServer Side Rendering
TutorialsVS Code
TutorialsZeplin
TutorialsUsage With Markdown
TutorialsBuilding Layouts
TutorialsUsing CLI Tools
TutorialsSharing Prototypes
Troubleshooting
If you experience any issues while using a template, please head over to the Support page for more guidelines and help.