Skip to main content

Form Validation

This template explains how to show and hide form validation errors in an accessible way when user tries to submit a form with required fields that are empty.

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">
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="stylesheet" href="" integrity="sha384-5JYmtSD7nykpUvSmTW1CHMoBDkBZUpUmG0vuh+NUVtZag3F75Kr7+/JU3J7JV6Wq" crossorigin="anonymous" />
<link rel="stylesheet" href="" integrity="sha384-+eUULRb2TsI9BMg6C3v7JKC8sC5Zrwtxt60Y6j/f6e1J4L/iINszZh1X/DDyz1Xz" crossorigin="anonymous" />
<link rel="stylesheet" href="" integrity="sha384-QNcOSzJTfVMWN/WqAtm5yev6PwVz+bBfSud0o8c/Dybn+c27Kb5bterSULzxCxKK" crossorigin="anonymous" />
<script type="module" src="" integrity="sha384-0wXJIcD/9zR943iDahCNkD5hmb60UqEERrG+P+AzWD0sRab9Hp8eF465ih9K7r4+" crossorigin="anonymous"></script>
<script nomodule src="" integrity="sha384-I+roClY+4BeY34jr982x3THYzrv+D2wyJ/cGT2mXqE/bzE1TIHD8nplbBChDYZ84" crossorigin="anonymous"></script>
<duet-header language="fi"></duet-header>
<duet-layout center>
<div slot="main">
<duet-card padding="large">
<duet-spacer breakpoint="x-small" size="medium"></duet-spacer>
<form id="form" action="#" novalidate>
<duet-heading level="h1" visual-level="h2">Ota yhteyttä</duet-heading>
Lähetä meille viesti kun haluat antaa palautetta tai pyytää yhteydenottoa.
Jos olet jo asiakkaamme, asiasi hoituu parhaiten, kun kirjaudut verkkopalveluun.
<duet-spacer size="medium"></duet-spacer>
<duet-input label="Nimi" name="name" placeholder="Matti Meikäläinen" expand required>
<duet-input label="Sähköposti" name="email" type="email" placeholder="" required expand>
<duet-select label="Kaupunki" name="city" placeholder="Valitse…" expand></duet-select>
label="Viesti asiakaspalveluun"
placeholder="Kirjoita tähän"
tooltip="Hello, I’m a tooltip! To close me, you can click outside of
the tooltip, hit ESC key or click the X button."


<duet-radio-group label="Yhteydenoton syy" direction="horizontal" name="group1">
<duet-radio label="Palaute" value="one"></duet-radio>
<duet-radio label="Yhteydenottopyyntö" value="two"></duet-radio>
<duet-spacer size="x-large"></duet-spacer>
<duet-button submit variation="primary">Lähetä viesti</duet-button>
<duet-footer logo-href="#" language="fi"></duet-footer>
// Show back link in the header component
var header = document.querySelector("duet-header")
header.back = {
label: "Takaisin",
href: "/"

// Show data in the footer component
var footer = document.querySelector("duet-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' }
] = [
{ label: 'Turvallisuus ja käyttöehdot', href: '#' },
{ label: 'Evästeet', href: '#' },
{ label: 'Henkilötietojen käsittely', href: '#' },

// Feed items into our select menu
var select = document.querySelector("duet-select")
select.items = [
{ label: "Helsinki", value: "1" },
{ label: "Tampere", value: "2" },
{ label: "Vantaa", value: "3" },
{ label: "Espoo", value: "4" }

// Prevent normal submission of the form
var form = document.querySelector("#form")
form.addEventListener("submit", function(event) {
}, false)

// When the submit button is clicked do fake validation for demo purposes
var submit = document.querySelector("duet-button")
submit.addEventListener("click", function(e) {

// Show error in the first input, announce it to the screen reader,
// and finally set focus on this first input so that user can fix the error.
var errorMsg = "Virhe: Tämä kenttä on pakollinen"
var input = document.querySelector("duet-input")
input.error = errorMsg

// Show additional errors in different type of components for demo
var email = document.querySelectorAll("duet-input")[1]
email.error = errorMsg
var select = document.querySelector("duet-select")
select.error = errorMsg
var textarea = document.querySelector("duet-textarea")
textarea.error = errorMsg
var radioGroup = document.querySelector("duet-radio-group")
radioGroup.error = errorMsg

// Finally, for demo purposes, let’s add change listeners for the
// form fields that remove the error when something is inputted
input.addEventListener("duetChange", function() {
input.error = ""
}, false)
email.addEventListener("duetChange", function() {
email.error = ""
}, false)
select.addEventListener("duetChange", function() {
select.error = ""
}, false)
textarea.addEventListener("duetChange", function() {
textarea.error = ""
}, false)
radioGroup.addEventListener("duetChange", function() {
radioGroup.error = ""
}, false)

}, false)


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.


Follow these practical tutorials to learn how to build simple page layouts using Duet’s CSS Framework, Web Components and other features:




Building Layouts


Using CLI Tools


Creating Custom Patterns


Server Side Rendering


Sharing Prototypes


Usage With Markdown


VS Code




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