Put the verbs in brackets into the past tense.
Underline Focus
A field reduced to a single line: on click, an indigo-to-magenta stroke starts in the middle and runs out to both edges while the label rises above.
Updated
This effect is free — the Forms category contains 20 effects total, including 2 free. Effect.Labs has 840 vanilla effects. Explore the category →
Usage examples
- Brand guidelines14 items3 Nov
- Quotes 202632 itemsYesterday
- Workshop photos208 items28 Oct
- Invoices57 items12 Oct
Maison Ferbaline · Bistro
A table for tonight?
Market cooking, 28 seats. Dinner from 7 to 10 pm, Tuesday to Saturday.
More than 8 guests? Call us.
How it works
The .udl-input field has no fill and no frame, only a 2 px bottom rule in rgba(255, 255, 255, .2). Right after it inside the <label class="udl-field"> come the .udl-label text and an empty <span class="udl-line">, absolutely positioned on that rule: it starts at left: 50% with zero width.
When the field takes focus, .udl-input:focus ~ .udl-line moves the stroke to left: 0 and width: 100%. Both values change together over 0.4 s on a cubic-bezier(.4, 0, .2, 1) curve: the #6366f1 → #d946ef gradient seems to be born in the centre and open towards both sides. When focus leaves, the same transition closes it back to the middle.
The label follows a separate rule. It sits at text height (top: 30px) and rises to top: 2px, in indigo 0.75rem, as soon as :focus or :not(:placeholder-shown) applies; the invisible placeholder=" " is only there to tell whether the field holds anything. A filled field therefore keeps its label up after the coloured stroke has gone.
The padding-top: 18px on .udl-field reserves room for the raised label: stacked in a form, two fields never overlap. The .fx-0282-root root (dark background, 250 px minimum height) is only there for the demo.
Accessibility
- Real label: the
<label>wraps the field, so "Full name" is its accessible name, with noidto de-duplicate when the page holds several. - Form attributes:
name="name"andautocomplete="name"are supplied; the browser offers the saved name and the value goes out with the form. - Spotting the active field: the coloured stroke only exists during focus. A filled field the user has left gets the grey rule back, which sets it apart from the one being edited.
- Reduced motion: under
prefers-reduced-motion: reduce, neither the stroke nor the label slides; both appear directly in their final place. - Contrast: at rest,
#8b8b93onrgb(26, 26, 36)reaches 5.1:1; the raised label,#818cf8at 12 px, reaches 5.8:1. Measured in Chromium, Firefox and WebKit, at rest, focused and filled.
Browser compatibility
Uses :placeholder-shown (Chrome 47, Firefox 51, Safari 9), the ~ sibling selector, a linear gradient and CSS variables (Chrome 49, Firefox 31, Safari 9.1). Tested in Chromium, Firefox and WebKit: two fields side by side each animating on their own, Tab, touch, submission in a form, 390 px width, reduced motion.
Without transitions, stroke and label jump from one state to the other and the field stays usable. Without :placeholder-shown, the label drops back onto the typed text when the field is left.
The code
Copy the two blocks (HTML and CSS) into your page. No JavaScript, no dependencies.
<div class="fx-0282-root">
<label class="udl-field">
<input class="udl-input" type="text" name="name" autocomplete="name" placeholder=" ">
<span class="udl-label">Full name</span>
<span class="udl-line" aria-hidden="true"></span>
</label>
</div>
.fx-0282-root,
.fx-0282-root *,
.fx-0282-root *::before,
.fx-0282-root *::after {
box-sizing: border-box
}
.fx-0282-root {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 250px;
padding: 24px 16px;
position: relative;
background: rgb(26, 26, 36);
color: rgb(255, 255, 255);
font-family: sans-serif;
}
.udl-field {
position: relative;
display: block;
width: var(--udl-width, 280px);
max-width: 100%;
padding-top: 18px;
}
.udl-input {
width: 100%;
padding: 12px 0;
font-size: 1rem;
font-family: inherit;
background: transparent;
border: none;
border-bottom: 2px solid rgba(255, 255, 255, 0.2);
color: white;
outline: none;
}
.udl-line {
position: absolute;
bottom: 0;
left: 50%;
width: 0;
height: 2px;
background: linear-gradient(90deg, #6366f1, #d946ef);
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}
.udl-input:focus ~ .udl-line {
left: 0;
width: 100%;
}
.udl-label {
position: absolute;
left: 0;
top: 30px;
color: var(--udl-muted, #8b8b93);
pointer-events: none;
transition: all 0.3s ease;
}
.udl-input:focus + .udl-label,
.udl-input:not(:placeholder-shown) + .udl-label {
top: 2px;
font-size: 0.75rem;
color: #818cf8;
}
@media (prefers-reduced-motion: reduce) {
.udl-line,
.udl-label {
transition: none;
}
}
Pure CSS — no JavaScript needed.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Width (CSS — --udl-width) |
280 px | 100% to follow the column, a short value (100 to 140 px) for a field dropped into a sentence. The field never exceeds its container (max-width: 100%). |
Stroke gradient (CSS — background of .udl-line) |
linear-gradient(90deg, #6366f1, #d946ef) |
A plain colour works too. Keep a hue clearly brighter than the grey rule so the active field stands out. |
Thickness (CSS — height of .udl-line and border-bottom of .udl-input) |
2 px | Change both values together: the stroke covers the bottom rule exactly. |
Opening speed (CSS — transition of .udl-line) |
0.4 s | The label moves in 0.3 s. A stroke slightly slower than the label makes the line seem to follow the text going up. |
Resting label colour (CSS — --udl-muted) |
#8b8b93 |
The raised label keeps #818cf8, hard-coded in the :focus + .udl-label rule. |
Room above (CSS — padding-top of .udl-field) |
18 px | If you enlarge the raised label, increase this padding and the resting label's top (30 px) by the same amount. |
FAQ
Why does the stroke start from the centre rather than the left?
Because two properties change at once: left goes from 50% to 0 while width goes from 0 to 100%. For a stroke starting on the left, keep left: 0 at rest and animate only the width.
Does the field work on a light background?
Typed text is white and the rule is a transparent white: on a light background, make the color of .udl-input dark and the rule rgba(0, 0, 0, .2). The indigo-magenta gradient stays readable as is.
Can a field sit in the middle of a sentence?
Yes: give .udl-field display: inline-block and a short width through --udl-width. The text line grows to hold the room reserved for the label; plan for a line height around 1.9.