From 2eb2597efe91233825103d432aa5250164ea263c Mon Sep 17 00:00:00 2001 From: Lea Verou Date: Thu, 16 Jan 2025 13:41:18 -0500 Subject: [PATCH] Floating labels for input --- src/components/input/input.ts | 12 +++++++++++- src/styles/themes/matter/overrides.css | 22 ++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/components/input/input.ts b/src/components/input/input.ts index b321a26ac..30d481c2a 100644 --- a/src/components/input/input.ts +++ b/src/components/input/input.ts @@ -1,4 +1,4 @@ -import { html, isServer } from 'lit'; +import { html, isServer, type PropertyValues } from 'lit'; import { customElement, property, query, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { ifDefined } from 'lit/directives/if-defined.js'; @@ -57,6 +57,8 @@ import styles from './input.css'; * @cssproperty --border-color - The color of the input's borders. * @cssproperty --border-width - The width of the input's borders. Expects a single value. * @cssproperty --box-shadow - The shadow effects around the edges of the input. + * + * @cssstate blank - The input is empty. */ @customElement('wa-input') export default class WaInput extends WebAwesomeFormAssociatedElement { @@ -308,6 +310,14 @@ export default class WaInput extends WebAwesomeFormAssociatedElement { this.passwordVisible = !this.passwordVisible; } + updated(changedProperties: PropertyValues) { + super.updated(changedProperties); + + if (changedProperties.has('value')) { + this.toggleCustomState('blank', !this.value); + } + } + @watch('step', { waitUntilFirstUpdate: true }) handleStepChange() { // If step changes, the value may become invalid so we need to recheck after the update. We set the new step diff --git a/src/styles/themes/matter/overrides.css b/src/styles/themes/matter/overrides.css index 7679bd607..deaf3d5a7 100644 --- a/src/styles/themes/matter/overrides.css +++ b/src/styles/themes/matter/overrides.css @@ -81,22 +81,36 @@ } } - /* Floating label */ + /** + * Floating labels + */ &::part(label) { transition: all var(--wa-transition-normal); position: absolute; - top: calc(var(--wa-form-control-height) / 2 - 0.5lh); left: calc(var(--wa-space) - 0.25em); z-index: 1; + /* State: out of the way by default */ + top: -0.5lh; + font-size: var(--wa-size-smaller); + background-color: var(--wa-form-control-background-color); padding-inline: 0.25em; } + &:focus::part(label) { - top: -0.5lh; color: var(--wa-color-focus); - font-size: var(--wa-size-smaller); + } + + /* State: placeholder-like when: + * - the input is empty + * - the input is not focused + * - there is no actual placeholder + */ + &:state(blank):not(:focus, [placeholder])::part(label) { + top: calc(var(--wa-form-control-height) / 2 - 0.5lh); + font-size: inherit; } /* Different positioning and appearance for filled */