Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
288 changes: 144 additions & 144 deletions dist/css/bootstrap-grid.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/css/bootstrap-grid.css.map

Large diffs are not rendered by default.

940 changes: 468 additions & 472 deletions dist/css/bootstrap-reboot.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/css/bootstrap-reboot.css.map

Large diffs are not rendered by default.

1,756 changes: 875 additions & 881 deletions dist/css/bootstrap-utilities.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/css/bootstrap-utilities.css.map

Large diffs are not rendered by default.

6,888 changes: 3,452 additions & 3,436 deletions dist/css/bootstrap.css

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/css/bootstrap.css.map

Large diffs are not rendered by default.

140 changes: 70 additions & 70 deletions js/tests/visual/floating-label.html

Large diffs are not rendered by default.

46 changes: 22 additions & 24 deletions scss/forms/_floating-labels.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ $form-floating-tokens: () !default;
// stylelint-disable-next-line scss/dollar-variable-default
$form-floating-tokens: defaults(
(
--form-floating-height: calc(3.5rem + (var(--border-width) * 2)),
--form-floating-height: calc(3.75rem + (var(--border-width) * 2)),
--form-floating-line-height: 1.25,
--form-floating-padding-x: var(--btn-input-padding-x),
--form-floating-padding-x: calc(var(--btn-input-padding-x) * 1.25),
--form-floating-padding-y: 1rem,
--form-floating-input-padding-t: 1.625rem,
--form-floating-input-padding-b: .625rem,
Expand Down Expand Up @@ -54,13 +54,13 @@ $form-floating-tokens: defaults(
text-overflow: ellipsis;
white-space: nowrap;
pointer-events: none;
border: var(--input-btn-border-width) solid transparent; // Required for aligning label's text with the input as it affects inner box model
border: var(--border-width) solid transparent; // Required for aligning label's text with the input as it affects inner box model
transform-origin: 0 0;
@include transition(var(--form-floating-transition));
}

// Anchor the label to the top for textareas so it floats correctly at any height
> textarea ~ label {
> label:has(~ textarea) {
align-items: flex-start;
}

Expand All @@ -87,23 +87,23 @@ $form-floating-tokens: defaults(
}
}

> .form-control:focus,
> .form-control:not(:placeholder-shown),
> .form-control-plaintext {
~ label {
transform: var(--form-floating-label-transform);
}
// The label precedes the control in the DOM so screen readers announce it
// before the field's value, so we look forward with `:has()` to react to the
// control's state (focus, value, disabled, etc.).
> label:has(~ .form-control:focus),
> label:has(~ .form-control:not(:placeholder-shown)),
> label:has(~ .form-control-plaintext) {
transform: var(--form-floating-label-transform);
}

// Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
> .form-control:-webkit-autofill {
~ label {
transform: var(--form-floating-label-transform);
}
> label:has(~ .form-control:-webkit-autofill) {
transform: var(--form-floating-label-transform);
}
> textarea:focus,
> textarea:not(:placeholder-shown) {
~ label::after {

> label:has(~ textarea:focus),
> label:has(~ textarea:not(:placeholder-shown)) {
&::after {
position: absolute;
inset: var(--form-floating-padding-y) calc(var(--form-floating-padding-x) * .5);
z-index: -1;
Expand All @@ -113,18 +113,16 @@ $form-floating-tokens: defaults(
@include border-radius(var(--btn-input-border-radius));
}
}
> textarea:disabled ~ label::after {
> label:has(~ textarea:disabled)::after {
background-color: var(--form-floating-label-disabled-bg);
}

> .form-control-plaintext {
~ label {
border-width: var(--control-border-width) 0; // Required to properly position label text - as explained above
}
> label:has(~ .form-control-plaintext) {
border-width: var(--control-border-width) 0; // Required to properly position label text - as explained above
}

> :disabled ~ label,
> .form-control:disabled ~ label { // Required for `.form-control`s because of specificity
> label:has(~ :disabled),
> label:has(~ .form-control:disabled) { // Required for `.form-control`s because of specificity
color: var(--form-floating-label-disabled-color);
}
}
Expand Down
7 changes: 7 additions & 0 deletions scss/forms/_form-control.scss
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,13 @@ $form-control-sizes: defaults(
// text (without any border, background color, focus indicator)

.form-control-plaintext {
// Plaintext is a standalone class (not combined with `.form-control`), so it
// needs its own copy of the control tokens. Without them the `var(--control-*)`
// references below are invalid and fall back to their initial values (e.g.
// `border-width: medium`), which adds phantom inline borders and misaligns the
// text from a floating label.
@include tokens($form-control-tokens);

display: block;
width: 100%;
padding: var(--control-padding-y) 0;
Expand Down
4 changes: 2 additions & 2 deletions site/src/assets/examples/cheatsheet/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -505,12 +505,12 @@ export const body_class = 'bg-body-tertiary'
<Example showMarkup={false} code={`
<form>
<div class="form-floating mb-3">
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">
<label for="floatingInput">Email address</label>
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">
</div>
<div class="form-floating">
<input type="password" class="form-control" id="floatingPassword" placeholder="Password">
<label for="floatingPassword">Password</label>
<input type="password" class="form-control" id="floatingPassword" placeholder="Password">
</div>
</form>
`} />
Expand Down
4 changes: 2 additions & 2 deletions site/src/assets/examples/dialogs/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,12 @@ export const extra_css = ['dialogs.css']
<div class="dialog-body pt-0">
<form>
<div class="form-floating mb-3">
<input type="email" class="form-control rounded-3" id="floatingEmail" placeholder="name@example.com">
<label for="floatingEmail">Email address</label>
<input type="email" class="form-control rounded-3" id="floatingEmail" placeholder="name@example.com">
</div>
<div class="form-floating mb-3">
<input type="password" class="form-control rounded-3" id="floatingPassword" placeholder="Password">
<label for="floatingPassword">Password</label>
<input type="password" class="form-control rounded-3" id="floatingPassword" placeholder="Password">
</div>
<button class="btn-solid theme-primary w-100 py-2 mb-2" type="submit">Sign up</button>
<small class="fg-2">By clicking Sign up, you agree to the terms of use.</small>
Expand Down
4 changes: 2 additions & 2 deletions site/src/assets/examples/heroes/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ export const extra_css = ['heroes.css']
<div class="md:col-10 mx-auto lg:col-5">
<form class="p-4 md:p-5 border rounded-3 bg-body-tertiary">
<div class="form-floating mb-3">
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">
<label for="floatingInput">Email address</label>
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">
</div>
<div class="form-floating mb-3">
<input type="password" class="form-control" id="floatingPassword" placeholder="Password">
<label for="floatingPassword">Password</label>
<input type="password" class="form-control" id="floatingPassword" placeholder="Password">
</div>
<div class="form-field mb-3">
<input type="checkbox" value="remember-me" id="heroRememberMe" class="check">
Expand Down
4 changes: 2 additions & 2 deletions site/src/assets/examples/sign-in/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ export const body_class = 'd-flex align-items-center py-4 bg-body-tertiary'
<h1 class="h3 mb-3 fw-normal">Please sign in</h1>

<div class="form-floating">
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">
<label for="floatingInput">Email address</label>
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">
</div>
<div class="form-floating">
<input type="password" class="form-control" id="floatingPassword" placeholder="Password">
<label for="floatingPassword">Password</label>
<input type="password" class="form-control" id="floatingPassword" placeholder="Password">
</div>

<div class="form-field text-start my-3">
Expand Down
36 changes: 18 additions & 18 deletions site/src/content/docs/forms/floating-labels.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,98 +11,98 @@ Wrap a pair of `<input class="form-control">` and `<label>` elements in `.form-f

A non-empty `placeholder` attribute is required on each `<input>` as our CSS-only floating label implementation relies on the `:placeholder-shown` pseudo-element to detect when the input is empty. The placeholder text itself is not visible; only the `<label>` is shown to users.

Also note that the `<input>` must come first so we can utilize a sibling selector (i.e., `~`).
Also note that the `<label>` must come first so that screen readers announce it before the field’s value; our CSS reacts to the control’s state with the `:has()` selector.

<Example class="vstack gap-3" code={`<div class="form-floating">
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">
<label for="floatingInput">Email address</label>
<input type="email" class="form-control" id="floatingInput" placeholder="name@example.com">
</div>
<div class="form-floating">
<input type="password" class="form-control" id="floatingPassword" placeholder="Password">
<label for="floatingPassword">Password</label>
<input type="password" class="form-control" id="floatingPassword" placeholder="Password">
</div>`} />

When there’s a `value` already defined, `<label>`s will automatically adjust to their floated position.

<Example code={`<form class="form-floating">
<input type="email" class="form-control" id="floatingInputValue" placeholder="name@example.com" value="test@example.com">
<label for="floatingInputValue">Input with value</label>
<input type="email" class="form-control" id="floatingInputValue" placeholder="name@example.com" value="test@example.com">
</form>`} />

Form validation styles also work as expected.

<Example code={`<form class="form-floating">
<input type="email" class="form-control is-invalid" id="floatingInputInvalid" placeholder="name@example.com" value="test@example.com">
<label for="floatingInputInvalid">Invalid input</label>
<input type="email" class="form-control is-invalid" id="floatingInputInvalid" placeholder="name@example.com" value="test@example.com">
</form>`} />

## Textareas

By default, `<textarea>`s with `.form-control` will be the same height as `<input>`s.

<Example code={`<div class="form-floating">
<textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea"></textarea>
<label for="floatingTextarea">Comments</label>
<textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea"></textarea>
</div>`} />

To set a custom height on your `<textarea>`, do not use the `rows` attribute. Instead, override the `--bs-form-floating-height` CSS variable on the `.form-floating` wrapper (either inline or via custom CSS) so the label floats correctly at any height.

<Example code={`<div class="form-floating" style="--bs-form-floating-height: 100px">
<textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea2"></textarea>
<label for="floatingTextarea2">Comments</label>
<textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea2"></textarea>
</div>`} />

## Selects

Select elements work in the same way, but unlike `<input>`s, they’ll always show the `<label>` in its floated state. **Selects with `size` and `multiple` are not supported.**

<Example code={`<div class="form-floating">
<label for="floatingSelect">Works with selects</label>
<select class="form-control" id="floatingSelect" aria-label="Floating label select example">
<option selected>Open this select menu</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
<label for="floatingSelect">Works with selects</label>
</div>`} />

## Disabled

Add the `disabled` boolean attribute on an input, a textarea or a select to give it a grayed out appearance, remove pointer events, and prevent focusing.

<Example class="vstack gap-3" code={`<div class="form-floating">
<input type="email" class="form-control" id="floatingInputDisabled" placeholder="name@example.com" disabled>
<label for="floatingInputDisabled">Email address</label>
<input type="email" class="form-control" id="floatingInputDisabled" placeholder="name@example.com" disabled>
</div>
<div class="form-floating">
<textarea class="form-control" placeholder="Leave a comment here" id="floatingTextareaDisabled" disabled></textarea>
<label for="floatingTextareaDisabled">Comments</label>
<textarea class="form-control" placeholder="Leave a comment here" id="floatingTextareaDisabled" disabled></textarea>
</div>
<div class="form-floating" style="--bs-form-floating-height: 100px">
<textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea2Disabled" disabled>Disabled textarea with some text inside</textarea>
<label for="floatingTextarea2Disabled">Comments</label>
<textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea2Disabled" disabled>Disabled textarea with some text inside</textarea>
</div>
<div class="form-floating">
<label for="floatingSelectDisabled">Works with selects</label>
<select class="form-control" id="floatingSelectDisabled" aria-label="Floating label disabled select example" disabled>
<option selected>Open this select menu</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
<label for="floatingSelectDisabled">Works with selects</label>
</div>`} />

## Readonly plaintext

Floating labels also support `.form-control-plaintext`, which can be helpful for toggling from an editable `<input>` to a plaintext value without affecting the page layout.

<Example class="vstack gap-3" code={`<div class="form-floating">
<input type="email" readonly class="form-control-plaintext" id="floatingEmptyPlaintextInput" placeholder="name@example.com">
<label for="floatingEmptyPlaintextInput">Empty input</label>
<input type="email" readonly class="form-control-plaintext" id="floatingEmptyPlaintextInput" placeholder="name@example.com">
</div>
<div class="form-floating">
<input type="email" readonly class="form-control-plaintext" id="floatingPlaintextInput" placeholder="name@example.com" value="name@example.com">
<label for="floatingPlaintextInput">Input with value</label>
<input type="email" readonly class="form-control-plaintext" id="floatingPlaintextInput" placeholder="name@example.com" value="name@example.com">
</div>`} />

## Input groups
Expand All @@ -112,8 +112,8 @@ Floating labels also support `.input-group`.
<Example code={`<div class="input-group">
<span class="input-group-text">@</span>
<div class="form-floating">
<input type="text" class="form-control" id="floatingInputGroup1" placeholder="Username">
<label for="floatingInputGroup1">Username</label>
<input type="text" class="form-control" id="floatingInputGroup1" placeholder="Username">
</div>
</div>`} />

Expand All @@ -123,8 +123,8 @@ When using `.input-group` and `.form-floating` along with form validation, place
<div class="input-group">
<span class="input-group-text">@</span>
<div class="form-floating is-invalid">
<input type="text" class="form-control is-invalid" id="floatingInputGroup2" placeholder="Username" required>
<label for="floatingInputGroup2">Username</label>
<input type="text" class="form-control is-invalid" id="floatingInputGroup2" placeholder="Username" required>
</div>
</div>
<div class="invalid-feedback">
Expand All @@ -139,19 +139,19 @@ When working with the Bootstrap grid system, be sure to place form elements with
<Example code={`<div class="row g-2">
<div class="md:col">
<div class="form-floating">
<input type="email" class="form-control" id="floatingInputGrid" placeholder="name@example.com" value="mdo@example.com">
<label for="floatingInputGrid">Email address</label>
<input type="email" class="form-control" id="floatingInputGrid" placeholder="name@example.com" value="mdo@example.com">
</div>
</div>
<div class="md:col">
<div class="form-floating">
<label for="floatingSelectGrid">Works with selects</label>
<select class="form-control" id="floatingSelectGrid">
<option selected>Open this select menu</option>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
<label for="floatingSelectGrid">Works with selects</label>
</div>
</div>
</div>`} />
Expand Down
2 changes: 1 addition & 1 deletion site/src/content/docs/forms/validation.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -351,8 +351,8 @@ Validation styles are available for the following form controls and components:
<div class="form-field">
<div class="form-floating">
<input type="email" class="form-control is-invalid" id="validationFloating" placeholder="name@example.com" value="test@example.com" aria-describedby="validationFloatingFeedback">
<label for="validationFloating">Email address</label>
<input type="email" class="form-control is-invalid" id="validationFloating" placeholder="name@example.com" value="test@example.com" aria-describedby="validationFloatingFeedback">
</div>
<div id="validationFloatingFeedback" class="invalid-feedback d-block">Example invalid floating label feedback</div>
</div>
Expand Down