]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
V6 more form fixes (#42523)
authorMark Otto <markd.otto@gmail.com>
Thu, 18 Jun 2026 03:54:48 +0000 (20:54 -0700)
committerGitHub <noreply@github.com>
Thu, 18 Jun 2026 03:54:48 +0000 (20:54 -0700)
* fix switch disabled checked

* fix selector for select bg

* fix radio disabled

* match disabled demos

* autocomplete off for date inputs

* fix floating label custom height

* fix disabled

scss/forms/_floating-labels.scss
scss/forms/_form-control.scss
scss/forms/_radio.scss
scss/forms/_switch.scss
site/src/content/docs/forms/checkbox.mdx
site/src/content/docs/forms/datepicker.mdx
site/src/content/docs/forms/floating-labels.mdx
site/src/content/docs/forms/radio.mdx
site/src/content/docs/forms/switch.mdx

index 8a751960b6a48ef59cc1735768f34e511b657dcb..1c15be2b3cd2a6f825e9301e062a708ffc038a2f 100644 (file)
@@ -16,6 +16,11 @@ $form-floating-tokens: defaults(
     --form-floating-input-padding-t: 1.625rem,
     --form-floating-input-padding-b: .625rem,
     --form-floating-label-height: 1.5em,
+    // Backgrounds for the textarea label's masking pseudo-element. Mirrors
+    // `.form-control` here because the label is a sibling of the control, so it
+    // can't inherit the control's own `--control-bg`/`--control-disabled-bg`.
+    --form-floating-label-bg: var(--btn-input-bg),
+    --form-floating-label-disabled-bg: var(--bg-2),
     --form-floating-label-opacity: .65,
     --form-floating-label-transform: scale(.85) translateY(-.5rem) translateX(.15rem),
     --form-floating-label-disabled-color: var(--fg-3),
@@ -54,6 +59,11 @@ $form-floating-tokens: defaults(
       @include transition(var(--form-floating-transition));
     }
 
+    // Anchor the label to the top for textareas so it floats correctly at any height
+    > textarea ~ label {
+      align-items: flex-start;
+    }
+
     > .form-control,
     > .form-control-plaintext {
       height: var(--form-floating-height);
@@ -99,12 +109,12 @@ $form-floating-tokens: defaults(
         z-index: -1;
         height: var(--form-floating-label-height);
         content: "";
-        background-color: var(--control-bg);
+        background-color: var(--form-floating-label-bg);
         @include border-radius(var(--btn-input-border-radius));
       }
     }
     > textarea:disabled ~ label::after {
-      background-color: var(--control-disabled-bg);
+      background-color: var(--form-floating-label-disabled-bg);
     }
 
     > .form-control-plaintext {
index 9ae6ab9bf8625ec64805732995db00d5af60ab47..cd01f82954d78fde68c2f9cdbcc5720f325ba15d 100644 (file)
@@ -204,7 +204,7 @@ $form-control-sizes: defaults(
     }
   }
 
-  @media (prefers-color-scheme: dark) {
+  [data-bs-theme="dark"] {
     select.form-control,
     .form-control-caret {
       background-image: var(--control-select-bg-dark);
index 82d4efe3e1bb149885cedad00eadd5891a9ca1fc..71dd811c8542ccf22572793a0ea5461e201b5a10 100644 (file)
@@ -61,6 +61,9 @@ $radio-tokens: defaults(
         cursor: default;
       }
     }
+    &:disabled:checked {
+      opacity: var(--radio-disabled-opacity);
+    }
 
     &:focus-visible {
       @include focus-ring(true);
index de992a25e822528933aeb6ff30a4dbea67fbc205..2357b74423b9c7bc35ab9ca1868db438bb43dc7c 100644 (file)
@@ -75,6 +75,18 @@ $switch-tokens: defaults(
       @include focus-ring(true);
     }
 
+    &:has(input:disabled:not(:checked)) {
+      --switch-bg: var(--switch-disabled-bg);
+      --switch-indicator-bg: var(--switch-disabled-indicator-bg);
+
+      &::before { opacity: .4; }
+
+      ~ label {
+        color: var(--fg-3);
+        cursor: default;
+      }
+    }
+
     &:has(input:checked) {
       background-color: var(--theme-bg, var(--switch-checked-bg));
       border-color: var(--theme-bg, var(--switch-checked-border-color));
@@ -84,14 +96,11 @@ $switch-tokens: defaults(
       }
     }
 
-    &:has(input:disabled) {
-      --switch-bg: var(--switch-disabled-bg);
-      --switch-indicator-bg: var(--switch-disabled-indicator-bg);
-
-      &::before { opacity: .4; }
+    &:has(input:checked:disabled) {
+      opacity: .65;
 
       ~ label {
-        color: var(--secondary-fg);
+        color: var(--fg-3);
         cursor: default;
       }
     }
index e9b3c7718de52cc1fe72fc7e8b290469f01567ff..85062ef4f47a058d2f0ee6eb3f8de390adb1d930 100644 (file)
@@ -61,14 +61,12 @@ Modify the appearance of checked checkboxes by adding the `.theme-{color}` class
 
 Add the `disabled` attribute and the associated `<label>`s are automatically styled to match with a lighter color to help indicate the input’s state.
 
-<Example code={`<div class="form-field">
+<Example class="vstack gap-2" code={`<div class="form-field">
     <input type="checkbox" id="checkDisabled" class="check" disabled />
     <label for="checkDisabled">Example new checkbox</label>
-  </div>`} />
-
-Applies to checked states, too.
+  </div>
 
-<Example code={`<div class="form-field">
+  <div class="form-field">
     <input type="checkbox" id="checkDisabledChecked" class="check" checked disabled />
     <label for="checkDisabledChecked">Example new checkbox</label>
   </div>`} />
index dca6eb9d0e7024c86ce13917c81d034366b123ec..5f20e4a3b6b65b1f5d4c9df5bca2155565d3f346 100644 (file)
@@ -14,7 +14,7 @@ deps:
 The Bootstrap Datepicker is a wrapper around [Vanilla Calendar Pro](https://vanilla-calendar.pro/) that provides a consistent, accessible date selection experience. It supports light/dark themes, input binding, and flexible configuration via data attributes or JavaScript.
 
 <Example code={`<label for="datepicker1" class="form-label">Datepicker</label>
-  <input type="text" class="form-control w-12" id="datepicker1" data-bs-toggle="datepicker" placeholder="Choose date…">`} />
+  <input type="text" class="form-control w-12" id="datepicker1" data-bs-toggle="datepicker" autocomplete="off" placeholder="Choose date…">`} />
 
 Note that we’re using a width utility of `.w-12` to ensure the input is wide enough to accommodate the date format and imply some affordance for the expected type of input.
 
@@ -35,7 +35,7 @@ Use the [form field]([[docsref:/forms/field]]) component to layout and wrap your
 
 <Example code={`<div class="form-field">
     <label for="datepicker2" class="form-label">Datepicker field</label>
-    <input type="text" class="form-control w-12" id="datepicker2" data-bs-toggle="datepicker" placeholder="Choose date…">
+    <input type="text" class="form-control w-12" id="datepicker2" data-bs-toggle="datepicker" autocomplete="off" placeholder="Choose date…">
     <div class="form-text">
       We’ll never share your email with anyone else.
     </div>
@@ -50,7 +50,7 @@ Use the [form adorn component]([[docsref:/forms/form-adorn]]) to add a calendar
     <div class="form-adorn-icon">
       <svg class="bi" width="16" height="16"><use href="#calendar-week" /></svg>
     </div>
-    <input type="text" class="form-ghost" id="datepickerIconStart" data-bs-toggle="datepicker" placeholder="Choose date…">
+      <input type="text" class="form-ghost" id="datepickerIconStart" data-bs-toggle="datepicker" autocomplete="off" placeholder="Choose date…">
   </div>`} />
 
 ### Min & Max dates
@@ -58,35 +58,35 @@ Use the [form adorn component]([[docsref:/forms/form-adorn]]) to add a calendar
 Restrict the selectable date range using `data-bs-date-min` and `data-bs-date-max`.
 
 <Example code={`<label for="datepickerMinMax" class="form-label">Event date (2026 only)</label>
-  <input type="text" class="form-control w-12" id="datepickerMinMax" data-bs-toggle="datepicker" data-bs-date-min="2026-01-01" data-bs-date-max="2026-12-31" placeholder="Select a date in 2026">`} />
+  <input type="text" class="form-control w-12" id="datepickerMinMax" data-bs-toggle="datepicker" autocomplete="off" data-bs-date-min="2026-01-01" data-bs-date-max="2026-12-31" placeholder="Select a date in 2026">`} />
 
 ### Multiple dates
 
 Enable multiple date selection with `data-bs-selection-mode="multiple"`.
 
 <Example code={`<label for="datepicker3" class="form-label">Select multiple dates</label>
-  <input type="text" class="form-control" id="datepicker3" data-bs-toggle="datepicker" data-bs-selection-mode="multiple" placeholder="Select date range…">`} />
+  <input type="text" class="form-control" id="datepicker3" data-bs-toggle="datepicker" autocomplete="off" data-bs-selection-mode="multiple" placeholder="Select date range…">`} />
 
 ### Multiple months
 
 Display multiple months side-by-side with the `displayMonthsCount` option. This is useful for date range selection where users need to see more context.
 
 <Example code={`<label for="datepickerMultiMonth" class="form-label">Select date range</label>
-  <input type="text" class="form-control" id="datepickerMultiMonth" data-bs-toggle="datepicker" data-bs-selection-mode="multiple-ranged" data-bs-display-months-count="2" placeholder="Select start and end dates">`} />
+  <input type="text" class="form-control" id="datepickerMultiMonth" data-bs-toggle="datepicker" autocomplete="off" data-bs-selection-mode="multiple-ranged" data-bs-display-months-count="2" placeholder="Select start and end dates">`} />
 
 ### Date range
 
 Select a range of dates with `data-bs-selection-mode="multiple-ranged"`. Use `data-bs-selected-dates` to preselect a date range.
 
 <Example code={`<label for="datepicker4" class="form-label">Select date range</label>
-  <input type="text" class="form-control" id="datepicker4" data-bs-toggle="datepicker" data-bs-selection-mode="multiple-ranged" data-bs-selected-dates='["2026-06-10", "2026-06-18"]' placeholder="Select start and end dates…">`} />
+  <input type="text" class="form-control" id="datepicker4" data-bs-toggle="datepicker" autocomplete="off" data-bs-selection-mode="multiple-ranged" data-bs-selected-dates='["2026-06-10", "2026-06-18"]' placeholder="Select start and end dates…">`} />
 
 ### Multi-month date range
 
 For selecting date ranges that span multiple months, combine `data-bs-selection-mode="multiple-ranged"` with `data-bs-display-months-count="2"` to show two months side-by-side, making it easier for users to select across month boundaries.
 
 <Example code={`<label for="datepickerRangeTwoMonths" class="form-label">Select date range</label>
-  <input type="text" class="form-control" id="datepickerRangeTwoMonths" data-bs-toggle="datepicker" data-bs-selection-mode="multiple-ranged" data-bs-display-months-count="2" data-bs-selected-dates='["2026-06-25", "2026-07-08"]' placeholder="Select start and end dates…">`} />
+  <input type="text" class="form-control" id="datepickerRangeTwoMonths" data-bs-toggle="datepicker" autocomplete="off" data-bs-selection-mode="multiple-ranged" data-bs-display-months-count="2" data-bs-selected-dates='["2026-06-25", "2026-07-08"]' placeholder="Select start and end dates…">`} />
 
 ## Options
 
@@ -95,7 +95,7 @@ For selecting date ranges that span multiple months, combine `data-bs-selection-
 Set the first day of the week (0 = Sunday, 1 = Monday, etc.) with `data-bs-first-weekday`.
 
 <Example code={`<label for="datepicker6" class="form-label">Week starts on Sunday</label>
-  <input type="text" class="form-control w-12" id="datepicker6" data-bs-toggle="datepicker" data-bs-first-weekday="0" placeholder="Select a date">`} />
+  <input type="text" class="form-control w-12" id="datepicker6" data-bs-toggle="datepicker" autocomplete="off" data-bs-first-weekday="0" placeholder="Select a date">`} />
 
 ### Placement
 
@@ -104,15 +104,15 @@ Control where the calendar appears relative to the input with `data-bs-placement
 <Example code={`<div class="d-flex gap-3">
     <div>
       <label for="datepickerLeft" class="form-label">Left aligned</label>
-      <input type="text" class="form-control" id="datepickerLeft" data-bs-toggle="datepicker" data-bs-placement="left" placeholder="Left">
+      <input type="text" class="form-control" id="datepickerLeft" data-bs-toggle="datepicker" autocomplete="off" data-bs-placement="left" placeholder="Left">
     </div>
     <div>
       <label for="datepickerCenter" class="form-label">Center aligned</label>
-      <input type="text" class="form-control" id="datepickerCenter" data-bs-toggle="datepicker" data-bs-placement="center" placeholder="Center">
+      <input type="text" class="form-control" id="datepickerCenter" data-bs-toggle="datepicker" autocomplete="off" data-bs-placement="center" placeholder="Center">
     </div>
     <div>
       <label for="datepickerRight" class="form-label">Right aligned</label>
-      <input type="text" class="form-control" id="datepickerRight" data-bs-toggle="datepicker" data-bs-placement="right" placeholder="Right">
+      <input type="text" class="form-control" id="datepickerRight" data-bs-toggle="datepicker" autocomplete="off" data-bs-placement="right" placeholder="Right">
     </div>
   </div>`} />
 
@@ -194,7 +194,7 @@ When a parent element has a theme, both the input and calendar popup inherit it:
 
 <Example code={`<div data-bs-theme="dark" class="p-3 bg-body fg-body rounded">
   <label for="datepickerDark" class="form-label">Dark mode datepicker</label>
-  <input type="text" class="form-control" id="datepickerDark" data-bs-toggle="datepicker" placeholder="Select a date">
+  <input type="text" class="form-control" id="datepickerDark" data-bs-toggle="datepicker" autocomplete="off" placeholder="Select a date">
 </div>`} />
 
 ### Datepicker-only theme
@@ -202,7 +202,7 @@ When a parent element has a theme, both the input and calendar popup inherit it:
 Use `data-bs-datepicker-theme` to set the datepicker popup’s theme independently of the input. This is useful when you want a light input with a dark datepicker, or vice versa:
 
 <Example code={`<label for="datepickerTheme" class="form-label">Light input, dark datepicker</label>
-<input type="text" class="form-control w-12" id="datepickerTheme" data-bs-toggle="datepicker" data-bs-datepicker-theme="dark" placeholder="Select a date">`} />
+<input type="text" class="form-control w-12" id="datepickerTheme" data-bs-toggle="datepicker" autocomplete="off" data-bs-datepicker-theme="dark" placeholder="Select a date">`} />
 
 ## CSS
 
index 5cf8615a11702d0197ae7d117baadc065b560427..36d780d281e1e7f1f5db75aca287322e24c79fc5 100644 (file)
@@ -45,10 +45,10 @@ By default, `<textarea>`s with `.form-control` will be the same height as `<inpu
     <label for="floatingTextarea">Comments</label>
   </div>`} />
 
-To set a custom height on your `<textarea>`, do not use the `rows` attribute. Instead, set an explicit `height` (either inline or via custom CSS).
+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">
-    <textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea2" style="height: 100px"></textarea>
+<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>
   </div>`} />
 
@@ -78,8 +78,8 @@ Add the `disabled` boolean attribute on an input, a textarea or a select to give
     <textarea class="form-control" placeholder="Leave a comment here" id="floatingTextareaDisabled" disabled></textarea>
     <label for="floatingTextareaDisabled">Comments</label>
   </div>
-  <div class="form-floating">
-    <textarea class="form-control" placeholder="Leave a comment here" id="floatingTextarea2Disabled" style="height: 100px" disabled>Disabled textarea with some text inside</textarea>
+  <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>
   </div>
   <div class="form-floating">
index d476186d82cbec2b906a15c490734bc00689e25a..375f74d1593d5dab4224d3b60107179d0c804e09 100644 (file)
@@ -48,11 +48,15 @@ Modify the appearance of checked radios by adding the `.theme-{color}` class to
 
 Add the `disabled` attribute and the associated `<label>`s are automatically styled to match with a lighter color to help indicate the input’s state.
 
-<Example code={`<div class="form-field">
+<Example class="vstack gap-2" code={`<div class="form-field">
     <input type="radio" id="radioDisabled" class="radio" disabled />
     <label for="radioDisabled">Example new radio</label>
   </div>
-  `} />
+
+  <div class="form-field">
+    <input type="radio" id="radioCheckedDisabled" class="radio" disabled checked />
+    <label for="radioCheckedDisabled">Example checked disabled radio</label>
+  </div>`} />
 
 ## Sizes
 
index 17f41e83500e38c59e635ba8837eea984d6a61ca..7ab2306d1d3af52554115a27213d0da4027f6d74 100644 (file)
@@ -41,11 +41,18 @@ Modify the appearance of switches by adding the `.theme-{color}` class to the `.
 
 Add the `disabled` attribute and the associated `<label>`s are automatically styled to match with a lighter color to help indicate the input’s state.
 
-<Example class="d-flex flex-column gap-3" code={`<div class="form-field">
+<Example class="vstack gap-2" code={`<div class="form-field">
     <div class="switch">
       <input type="checkbox" value="" id="switchDisabledLabel" role="switch" switch disabled>
     </div>
     <label for="switchDisabledLabel">Disabled switch</label>
+  </div>
+
+  <div class="form-field">
+    <div class="switch">
+      <input type="checkbox" value="" id="switchCheckedDisabledLabel" role="switch" switch disabled checked>
+    </div>
+    <label for="switchCheckedDisabledLabel">Disabled checked switch</label>
   </div>`} />
 
 ## Sizes