<article class="wrapper">
<h1>Accessible Floating <code>label</code>s</h1>
<form action="/" method="GET" class="form">
<label for="name" class="form__label">
<span class="form__label-text">Your Name</span>
<input type="text" name="name" id="name" placeholder="Your Name" autocomplete="name" class="form__text-input">
<!-- <span class="form__error-text">Your name cannot be empty…</span> -->
</label>
<label for="phone" class="form__label">
<span class="form__label-text">Phone</span>
<input type="tel" name="phone" id="phone" placeholder="Phone (555-555-5555)" autocomplete="tel" class="form__text-input">
<!-- <span class="form__error-text">Phone cannot be empty…</span> -->
</label>
<label for="message" class="form__label">
<span class="form__label-text">Message</span>
<textarea name="message" id="message" placeholder="Message, what's on your mind?" class="form__text-input form__textarea"></textarea>
<!-- <span class="form__error-text">Message cannot be empty…</span> -->
</label>
<button class="form__btn">Submit</button>
</form>
<aside class="note">
<h2>Note:</h2>
<p>This demo exists to help provide an <strong>accessible</strong> solution for "floating <code>label</code>s" if a design calls for such a requirement.</p>
<p>For the best usability results, it's recommended to <em>not</em> hide/float form <code>label</code>s. Only do so if you <em>absolutely must</em>. If possible, talk with your designer and come to an agreement on <code>label</code> styling.</p>
<p>See the article "<a href="https://medium.com/simple-human/floating-labels-are-a-bad-idea-82edb64220f6">Floating labels are problematic</a>" for more details on why this approach is not recommended.</p>
</aside>
</article>
.form {
margin: 0 auto;
max-width: 15rem;
}
.form__label-text {
display: inline-block;
padding: 0.5rem;
.js & {
opacity: 0;
transform: translateY(50%);
transition: all 0.2s ease-in-out;
&--floating {
opacity: 1;
transform: translateY(15%);
}
}
}
.form__text-input {
border: solid Silver 1px;
padding: 0.5rem;
width: 100%;
&::placeholder {
color: #767676;
}
}
.form__textarea {
min-height: 5rem;
width: 100%;
}
.form__btn {
background-color: Crimson;
border: 0;
border-radius: 0.15rem;
color: White;
margin: 1.5rem 0;
padding: 0.5rem 1rem;
}
label,
textarea {
margin: 0;
}
View Compiled
(() => {
const classes = {
textInput: ".form__text-input",
labelText: ".form__label-text",
labelTextFloating: "form__label-text--floating"
};
const events = {
blur: "blur",
keyUp: "keyup"
};
// Collect all text input controls
const textInputs = document.querySelectorAll(classes.textInput);
// Let's float the label when the checked conditions are met
// for each input event listener
const floatLabel = e => {
const eventType = e.type;
const textInput = e.target;
const labelText = textInput.parentNode.querySelector(classes.labelText);
// On `keyup`, if there's text in the input, show the label
if (eventType === events.keyUp && textInput.value.length !== 0) {
labelText.classList.add(classes.labelTextFloating);
}
// On `blur`, if there's no text in the input, hide the label
if (eventType === events.blur && textInput.value.length === 0) {
labelText.classList.remove(classes.labelTextFloating);
}
};
// Add `keyup` and `blur` events for each input
for (const textInput of textInputs) {
textInput.addEventListener(events.keyUp, floatLabel);
textInput.addEventListener(events.blur, floatLabel);
}
})();
View Compiled