@epa-wg/custom-element
Version:
Declarative Custom Element as W3C proposal PoC with native(XSLT) based templating
282 lines (261 loc) • 12.6 kB
HTML
<html lang="en" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xhtml="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>Forms - Declarative Custom Element implementation demo</title>
<link rel="icon" href="./wc-square.svg"/>
<script type="module" src="../local-storage.js"></script>
<script type="module" src="../custom-element.js"></script>
<style>
@import "./demo.css";
label {
display: flex;
}
label:has(input[type="text"],input[type="password"],input:not([type]) ) {
flex-direction: column;
}
nav {
max-width: 32em;
}
</style>
<!-- https://github.com/mdn/learning-area/blob/main/html/forms/form-validation/custom-error-message.html
todo: apply setCustomValidity( warningStr )
-->
</head>
<body>
<nav>
<a href="../index.html"><h3><code>custom-element</code> demo</h3></a>
<p> <b>formData</b><br/>
The values of named form fields are populated into the <b>slice</b> as <b>form-data</b> on <var>change</var>
or <var>submit</var> event. The field values can be used in form validation via <var>custom-validity</var>
attribute
and in condition to enabling the form parts
<a href="https://developer.mozilla.org/en-US/docs/Web/API/FormData">formData MDN</a>
</p>
<details>
<summary>slice to form-data mapping</summary>
<html-demo-element>
<template>
<datadom hidden>
<slice>
<signin-form>
<form-data>
<username>QWE</username>
<password>ASD</password>
</form-data>
</signin-form>
</slice>
</datadom>
</template>
</html-demo-element>
</details>
<p> <b> custom-validity attribute </b><br/>
applied on the form itself or on the form field.<br/>
The value is an XPath over DCE <var>datadom</var>. When evaluated as <u>boolean</u>, it would enable(true) or
disable(false)
the form submission, acting as form validation mechanism.<br>
Alternatively, the value can be evaluated as a <u>string</u> which would be treated as an error and can be used
as
validation error message set as <var>@validation-message</var> attribute on the form slice.
Look for <var>email-form/@validation-message</var> example on the page.<br/>
</p>
<p> When <var>custom-validity</var> attribute is set on the field, its XPath evaluated value is propagated to
<a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLObjectElement/validationMessage">
validationMessage property</a>. Which would be shown via browser system popup as the field validation error.
</p>
<p> <var>@validation-message</var> is set either by <var>custom-validity</var> attribute or by browser as system message.
By default, it is shown as popup on the field validation. But also is available for template as a string via
form field attribute. Like in <var>email-form/@validation-message</var>.
</p>
<a href="https://developer.mozilla.org/en-US/docs/Learn/Forms/Form_validation">Form Validation MDN</a>
</nav>
<html-demo-element legend="1. Simple validation"
description="custom-validity boolean value prevents submission, username length switches Next to 'Sign In' button ">
<ol>
<li> Click Next, observe the warning</li>
<li> Fill input with 10+ characters</li>
<li> Click Next, the password and "Sign In" button should appear</li>
</ol>
<template>
<custom-element>
<template>
<form slice="signin-form"
custom-validity="
string-length(/datadom/slice/signin-form/form-data/username) > 10
and string-length(//form-data/password) > 3 "
>
<label> Email
<input name="username" autocomplete="username" placeholder="Email, phone, or username"
required="">
</label>
<variable name="showpassword" select="string-length(//form-data/username) > 10 "></variable>
<if test="not($showpassword)">
<button slice="confirm" slice-event="click" slice-value="'password'">Next</button>
</if>
<if test="$showpassword">
<label>Enter password: <input name="password" type="password" required> </label>
<button>Sign In</button>
</if>
username {//username}
</form>
</template>
</custom-element>
</template>
</html-demo-element>
<html-demo-element legend="2. Form life cycle demo"
description="form-data in the form slice is the source of truth">
<template>
<custom-element>
<template>
<form slice="signin-form"
custom-validity="
string-length(/datadom/slice/signin-form/form-data/username) > 9
and ( ( //confirm-by = 'sms' )
or ( //confirm-by = 'email' )
or ( //confirm-by = 'password' and string-length(//form-data/password) > 3 )
)
"
>
<!-- form validity should be based on form-data -->
<variable name="warn">
<if test="string-length(//username-slice) < 9 ">
Should be 10 or more symbols.
<!-- updated by slice on input event -->
</if>
<if test="//form-data/confirm-by = 'sms'">
Message and Data Rates may apply.
<!-- updated by form change by radio select -->
</if>
</variable>
<label> Enter your email, phone, or user name
<input name="username" autocomplete="username"
placeholder="Email, phone, or username"
custom-validity="( string-length(//username-slice) > 9 ) ?? 'should be 10+ symbols'"
slice-event="input"
slice="username-slice"
required
/>
</label>
<var> {$warn} </var>
<fieldset>
<legend>Confirm by</legend>
<label><input type="radio" name="confirm-by" value="email"/> email </label>
<label><input type="radio" name="confirm-by" value="sms"/> text to phone </label>
<label><input type="radio" name="confirm-by" value="password"/> password </label>
<if test="/datadom/slice/signin-form/form-data/confirm-by = 'password'">
<label>Enter password: <input type="password" NAME="password"
custom-validity="( string-length(//form-data/password) > 3 ) ?? 'password is too short'"
/></label>
</if>
<if test="not(//confirm-by)">
Please select the auth method
</if>
</fieldset>
<section>
<button>Sign In</button>
</section>
</form>
//username-slice {//username-slice}<br/>
//username {//username}<br/>
//confirm-by {//confirm-by}<br/>
//password {//password}
</template>
</custom-element>
</template>
</html-demo-element>
<html-demo-element legend="3. read system validity message"
description="validationMessage propagated into slice as 'validation-message' attribute ">
<ol>
<li> type in input field</li>
<li> delete input field content</li>
<li> observe the warning in string after input</li>
<li> Click Next observe the system warning in dropdown over input</li>
</ol>
<template>
<custom-element>
<template>
<form slice="email-form">
<label> Email
<input slice="username" slice-event="input" placeholder="non-empty" required>
</label>
<if test="//username/@validation-message">
<var>{//username/@validation-message}</var>
</if>
<button>Next</button>
</form>
</template>
</custom-element>
</template>
</html-demo-element>
<html-demo-element legend="4. form validity message"
description="@validation-message propagated into form slice and ">
<ol>
<li> type up to 3 chars in input field</li>
<li> observe the slice value change</li>
<li> click next</li>
<li> observe the warning bellow the button</li>
</ol>
<template>
<custom-element>
<template>
<form slice="email-form"
custom-validity=" string-length(//slice/username) > 3 ??
concat('should be more than 3 characters, now is ',string-length(//slice/username) ) "
>
<label> Email
<input name="email" slice="username" slice-event="input" placeholder="non-empty" required/>
</label>
<if test="//username/@validation-message">
<var>{//username/@validation-message}</var>
</if>
<button>Next</button>
<p>//email-form/@validation-message: {//email-form/@validation-message} </p>
<p>//slice/username: {//slice/username} </p>
</form>
</template>
</custom-element>
</template>
</html-demo-element>
<html-demo-element legend="5. using custom-element as form input"
description="bypass value to container form "
id="sample-5"
>
<ol>
<li> select radio in top group</li>
<li> observe the fruit selected on the left</li>
<li> observe the warning message bellow button</li>
<li> next button does not submit the form</li>
<li> select radio in bottom group</li>
<li> observe the fruit selected on the right</li>
<li> same fruit selection would eliminate the warning and
allow the form submission</li>
<li> after submit, observe the URL parameters 'inp-1=🍏&inp-2=🍏' </li>
</ol>
<template>
<custom-element tag="sample-input">
<template>
<attribute name="name" ></attribute>
<attribute name="value" select="//val"></attribute>
{$name}
<label><input type="radio" name="{$name}" slice="val" value="🍏">Apple</label>
<label><input type="radio" name="{$name}" slice="val" value="🍌">Banana</label>
</template>
</custom-element>
<custom-element>
<template>
<form slice="cart-form" action="#sample-5"
custom-validity="(//inp1 = //inp2) ?? 'pick same fruit'"
>
<sample-input slice="inp1" name="inp-1"></sample-input>
<sample-input slice="inp2" name="inp-2"></sample-input>
<button>Next</button>
Picked :{//inp1} and {//inp2}
<p>{//cart-form/@validation-message}</p>
</form>
</template>
</custom-element>
</template>
</html-demo-element>
<script type="module" src="https://unpkg.com/html-demo-element@1/html-demo-element.js"></script>
</body>
</html>