Skip to main content

Stepper
New

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.


Open in new 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.13/lib/localtapiola.css" integrity="sha384-5JYmtSD7nykpUvSmTW1CHMoBDkBZUpUmG0vuh+NUVtZag3F75Kr7+/JU3J7JV6Wq" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdn.duetds.com/api/css/1.4.17/lib/duet.min.css" integrity="sha384-3js6/AaSATr7LHDXnuEbRHM7QK7Ez5G8MF6tnJxApK73tfF9hESRZn8GaQWA+CMk" crossorigin="anonymous" />
<link rel="stylesheet" href="https://cdn.duetds.com/api/tokens/2.1.1/lib/tokens.custom-properties.css" integrity="sha384-QNcOSzJTfVMWN/WqAtm5yev6PwVz+bBfSud0o8c/Dybn+c27Kb5bterSULzxCxKK" crossorigin="anonymous" />
<script type="module" src="https://cdn.duetds.com/api/components/4.11.2/lib/duet/duet.esm.js" integrity="sha384-edpA3e8air1atSZLk5pu88L3x4TZNkQMDCw0+tevpdBWnigPdglFQAd4ZV+myNfk" crossorigin="anonymous"></script>
<script nomodule src="https://cdn.duetds.com/api/components/4.11.2/lib/duet/duet.js" integrity="sha384-eDx+Y9oT+21RXSSspZKG1abKLBaDOFDQp2tnNwAFy5I/iI/x7OhSPsZWACS+Oxlt" crossorigin="anonymous"></script>
</head>
<body>
<style>
html {
scroll-behavior: smooth;
}
.price {
display: none;
}
.has-price .price {
display: block;
}
.has-price .price-placeholder {
display: none;
}
.link-list a {
border-bottom: 1px solid var(--color-gray-light);
font-weight: var(--font-weight-semi-bold);
padding: var(--space-x-small) 0;
justify-content: space-between;
text-decoration: none;
align-items: center;
display: flex;
width: 100%;
}
.link-list a:last-of-type {
border: 0;
}
</style>
<duet-header language="fi" skip-to-id="#content"></duet-header>
<duet-hero
heading="Eläinvakuutus. Vaivattomasti. Vain muutamassa minuutissa."
image="https://www.duetds.com/assets/img/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>
<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="medium" id="price">
<duet-heading level="h3" visual-level="h4">Vakuutuksen hinta valintasi perusteella</duet-heading>
<duet-label>Vuosimaksu</duet-label>
<duet-caption class="price-placeholder">Täytä perustiedot nähdäksesi hinta.</duet-caption>
<span class="price duet-font-size-x-large duet-font-weight-semi-bold">189,90 €</span>
<duet-spacer></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: "/?lang=fi" },
{ label: "På Svenska", country: "sv", href: "/?lang=sv" },
{ label: "In English", country: "en", href: "/?lang=en" }
]

// Set the contact menu items
header.contactItems = [
{ label: "Lähetä viesti", href: "/viestit/laheta" },
{ label: "Avaa chat", href: "/chat/" },
{ label: "Yhteystiedot", href: "/yhteystiedot/" }
]

// Set label and href for session link
header.session = {
label: "Kirjaudu ulos",
href: "/?logout",
type: "logout"
}

// Set label and href for user profile link
header.user = {
label: "Laura",
href: "/?userId=1234"
}

// Listen for change events inside the navigation component
header.addEventListener("duetChange", function(ev) {
var event = ev.detail.originalEvent
var data = ev.detail.data
if (data.href !== "#content") {
event.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

Tutorials

Building Layouts

Tutorials

Using CLI Tools

Tutorials

Creating Custom Patterns

Tutorials

Server Side Rendering

Tutorials

Sharing Prototypes

Tutorials

Usage With Markdown

Tutorials

VS Code

Tutorials

Zeplin


Troubleshooting

If you experience any issues while using a template, please head over to the Support page for more guidelines and help.