1. このページの目的
サインインフォームのベストプラクティスを試す。
Use cross-platform browser features to build a sign-in form をその通り実装してみる。
2. デモ
<form action="#" method="post">
<h1>Sign in</h1>
<section>
<label for="email">Email</label>
<input id="email" name="email" type="email" autocomplete="username" required autofocus>
</section>
<section>
<label for="password">Password</label>
<button id="toggle-password" type="button" aria-label="Show password as plain text. Warning: this will display your password on the screhow password</button>
<input id="password" name="password" type="password" autocomplete="current-password" minlength="8" aria-describedby="password-constrainquired>
<div id="password-constraints">Eight or more characters, with at least one lowercase and one uppercase letter.</div>
</section>
<button id="sign-in">Sign in</button>
</form>
:root {
--desktop-font-size: 16px;
--mobile-font-size: 22px;
}
body {
font-family: sans-serif;
font-weight: 500;
margin: 10px 20px;
}
button {
background-color: #eee;
border: 1px solid #ccc;
border-radius: 2px;
color: #444;
cursor: pointer;
display: block;
font-size: 22px; /* fallback */
font-size: var(--mobile-font-size);
font-weight: 500;
margin: 3px 0 0 0;
padding: 10px;
}
button:hover {
background-color: #ccc;
color: black;
}
button#toggle-password {
background: none;
border: none;
cursor: pointer;
font-weight: 300;
padding: 0;
position: absolute;
top: -4px;
right: -2px;
}
form {
margin: 0 auto;
max-width: 500px;
}
h1 {
border-bottom: 1px solid #ccc;
font-size: 28px;
font-weight: 600;
margin: 0 0 20px 0;
padding: 0 0 5px 0;
}
input {
border: 1px solid #ccc;
font-size: 22px; /* fallback */
font-size: var(--mobile-font-size);
padding: 15px;
width: 90%; /* fallback */
width: calc(100% - 30px); /* full width minus padding */
}
input[type=email]:not(:focus):invalid,
input[type=password]:not(:focus):invalid {
color: red;
outline-color: red;
}
label {
display: block;
font-size: 20px;
font-size: var(--mobile-font-size);
font-weight: 500;
margin: 0 0 3px 0;
}
form section {
margin: 0 0 20px 0;
position: relative; /* for password toggle positioning */
}
@media (min-width: 450px) {
body {
margin: 50px;
}
button {
font-size: 14px; /* fallback */
font-size: var(--desktop-font-size);
}
h1 {
font-size: 28px;
font-size: calc(2 * var(--desktop-font-size));
font-weight: 500;
margin: 0 0 80px 0;
}
input {
font-size: 14px; /* fallback */
font-size: var(--desktop-font-size);
}
label {
font-size: 14px; /* fallback */
font-size: var(--desktop-font-size);
}
}
div#password-constraints {
margin: 5px 0 0 0;
font-size: 16px;
}
const passwordInput = document.getElementById('password');
const togglePasswordButton = document.getElementById('toggle-password');
togglePasswordButton.addEventListener('click', togglePassword);
function togglePassword() {
if (passwordInput.type === 'password') {
passwordInput.type = 'text';
togglePasswordButton.textContent = 'Hide password';
togglePasswordButton.setAttribute('aria-label',
'Hide password.');
} else {
passwordInput.type = 'password';
togglePasswordButton.textContent = 'Show password';
togglePasswordButton.setAttribute('aria-label',
'Show password as plain text. ' +
'Warning: this will display your password on the screen.');
}
}
passwordInput.addEventListener('input', resetCustomValidity);
function resetCustomValidity() {
passwordInput.setCustomValidity('');
}
// A production site would use more stringent password testing.
function validatePassword() {
let message= '';
if (!/.{8,}/.test(passwordInput.value)) {
message = 'At least eight characters. ';
}
if (!/.*[A-Z].*/.test(passwordInput.value)) {
message += 'At least one uppercase letter. ';
}
if (!/.*[a-z].*/.test(passwordInput.value)) {
message += 'At least one lowercase letter.';
}
passwordInput.setCustomValidity(message);
}
const form = document.querySelector('form');
const signinButton = document.querySelector('button#sign-in');
form.addEventListener('submit', handleFormSubmission);
function handleFormSubmission(event) {
event.preventDefault();
validatePassword();
form.reportValidity();
if (form.checkValidity() === false) {
} else {
// On a production site do form submission.
alert('Logging in!')
signinButton.disabled = 'true';
}
}