From: Mark Otto Date: Wed, 3 Sep 2025 03:59:19 +0000 (-0700) Subject: New form controls X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ac67589d418785b99b63e78f8062b64257a779fb;p=thirdparty%2Fbootstrap.git New form controls --- diff --git a/.bundlewatch.config.json b/.bundlewatch.config.json index 0177b5f615..7d0f30525e 100644 --- a/.bundlewatch.config.json +++ b/.bundlewatch.config.json @@ -26,11 +26,11 @@ }, { "path": "./dist/css/bootstrap.css", - "maxSize": "35.75 kB" + "maxSize": "36.0 kB" }, { "path": "./dist/css/bootstrap.min.css", - "maxSize": "31.5 kB" + "maxSize": "32.0 kB" }, { "path": "./dist/js/bootstrap.bundle.js", diff --git a/.cspell.json b/.cspell.json index 191c9bc05c..872c34b23c 100644 --- a/.cspell.json +++ b/.cspell.json @@ -21,6 +21,7 @@ "callout", "callouts", "camelCase", + "checkgroup", "clearfix", "Codesniffer", "combinator", diff --git a/scss/_root.scss b/scss/_root.scss index 241147aa65..478114f95a 100644 --- a/scss/_root.scss +++ b/scss/_root.scss @@ -91,6 +91,11 @@ --#{$prefix}root-font-size: #{$font-size-root}; } --#{$prefix}body-font-family: #{meta.inspect($font-family-base)}; + + --#{$prefix}font-size-base: #{$font-size-base}; // 14px + --#{$prefix}font-size-sm: calc(#{$font-size-base} * .9285); + --#{$prefix}font-size-lg: calc(#{$font-size-base} * 1.285); + @include rfs($font-size-base, --#{$prefix}body-font-size); --#{$prefix}body-font-weight: #{$font-weight-base}; --#{$prefix}body-line-height: #{$line-height-base}; @@ -237,7 +242,7 @@ --#{$prefix}link-color-rgb: #{to-rgb($link-color-dark)}; --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color-dark)}; - --#{$prefix}code-color: #{$code-color-dark}; + // --#{$prefix}code-color: #{$code-color-dark}; // removed in v6 --#{$prefix}highlight-color: #{$mark-color-dark}; --#{$prefix}highlight-bg: #{$mark-bg-dark}; diff --git a/scss/_variables.scss b/scss/_variables.scss index a0ed0d40a2..ea27464499 100644 --- a/scss/_variables.scss +++ b/scss/_variables.scss @@ -10,7 +10,7 @@ // consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. // scss-docs-start theme-color-variables -$primary: $purple-500 !default; +$primary: $blue-500 !default; $secondary: $gray-600 !default; $success: $green-500 !default; $info: $cyan-500 !default; @@ -167,6 +167,7 @@ $body-emphasis-color: $black !default; $link-color: $primary !default; $link-decoration: underline !default; +$link-underline-offset: .2em !default; $link-shade-percentage: 20% !default; $link-hover-color: shift-color($link-color, $link-shade-percentage) !default; $link-hover-decoration: null !default; @@ -204,7 +205,7 @@ $border-widths: ( 5: 5px ) !default; $border-style: solid !default; -$border-color: $gray-300 !default; +$border-color: color.mix($gray-300, $gray-400) !default; $border-color-translucent: rgba($black, .175) !default; // scss-docs-end border-variables @@ -266,8 +267,8 @@ $font-family-code: var(--#{$prefix}font-monospace) !default; // $font-size-root affects the value of `rem`, which is used for as well font sizes, paddings, and margins // $font-size-base affects the font size of the body text -$font-size-root: null !default; -$font-size-base: 1rem !default; // Assumes the browser default, typically `16px` +$font-size-root: 16px !default; +$font-size-base: 14px !default; // Assumes the browser default, typically `16px` $font-size-sm: $font-size-base * .875 !default; $font-size-lg: $font-size-base * 1.25 !default; @@ -546,8 +547,8 @@ $offcanvas-backdrop-opacity: $modal-backdrop-opacity !default; // Code -$code-font-size: $small-font-size !default; -$code-color: $pink !default; +$code-font-size: 95% !default; +$code-color: var(--#{$prefix}secondary-text) !default; $kbd-padding-y: .1875rem !default; $kbd-padding-x: .375rem !default; @@ -578,7 +579,7 @@ $border-color-translucent-dark: rgba($white, .15) !default; $headings-color-dark: inherit !default; $link-color-dark: tint-color($primary, 40%) !default; $link-hover-color-dark: shift-color($link-color-dark, -$link-shade-percentage) !default; -$code-color-dark: tint-color($code-color, 40%) !default; +// $code-color-dark: tint-color($code-color, 40%) !default; $mark-color-dark: $body-color-dark !default; $mark-bg-dark: $yellow-800 !default; @@ -587,8 +588,8 @@ $mark-bg-dark: $yellow-800 !default; // Forms // -$form-select-indicator-color-dark: $body-color-dark !default; -$form-select-indicator-dark: url("data:image/svg+xml,") !default; +// $form-select-indicator-color-dark: $body-color-dark !default; +// $form-select-indicator-dark: url("data:image/svg+xml,") !default; $form-switch-color-dark: rgba($white, .25) !default; $form-switch-bg-image-dark: url("data:image/svg+xml,") !default; diff --git a/scss/content/_reboot.scss b/scss/content/_reboot.scss index 47bd8321fe..313837b3d5 100644 --- a/scss/content/_reboot.scss +++ b/scss/content/_reboot.scss @@ -33,7 +33,8 @@ :root { @if $font-size-root != null { - @include font-size(var(--#{$prefix}root-font-size)); + font-size: var(--#{$prefix}root-font-size); + // @include font-size(var(--#{$prefix}root-font-size)); } @if $enable-smooth-scroll { @@ -256,12 +257,13 @@ // Links a { - color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, 1)); - text-decoration: $link-decoration; + color: var(--#{$prefix}link-color); + text-decoration: var(--#{$prefix}link-decoration); + text-underline-offset: $link-underline-offset; &:hover { - --#{$prefix}link-color-rgb: var(--#{$prefix}link-hover-color-rgb); - text-decoration: $link-hover-decoration; + color: var(--#{$prefix}link-hover-color); + text-decoration: var(--#{$prefix}link-hover-decoration); } } diff --git a/scss/forms/_form-check.scss b/scss/forms/_form-check.scss index bdb223f1e2..eed5ad3cd2 100644 --- a/scss/forms/_form-check.scss +++ b/scss/forms/_form-check.scss @@ -62,7 +62,237 @@ $form-switch-checked-bg-image: url("data:image/svg+xml,") !default; - -$form-select-feedback-icon-padding-end: $form-select-padding-x * 2.5 + $form-select-indicator-padding !default; -$form-select-feedback-icon-position: center right $form-select-indicator-padding !default; -$form-select-feedback-icon-size: $input-height-inner-half $input-height-inner-half !default; - -$form-select-border-width: $input-border-width !default; -$form-select-border-color: $input-border-color !default; -$form-select-border-radius: $input-border-radius !default; -$form-select-box-shadow: var(--#{$prefix}box-shadow-inset) !default; - -$form-select-focus-border-color: $input-focus-border-color !default; -$form-select-focus-width: $input-focus-width !default; -// $form-select-focus-box-shadow: 0 0 0 $form-select-focus-width $input-btn-focus-color !default; - -$form-select-padding-y-sm: $input-padding-y-sm !default; -$form-select-padding-x-sm: $input-padding-x-sm !default; -$form-select-font-size-sm: $input-font-size-sm !default; -$form-select-border-radius-sm: $input-border-radius-sm !default; - -$form-select-padding-y-lg: $input-padding-y-lg !default; -$form-select-padding-x-lg: $input-padding-x-lg !default; -$form-select-font-size-lg: $input-font-size-lg !default; -$form-select-border-radius-lg: $input-border-radius-lg !default; - -$form-select-transition: $input-transition !default; -// scss-docs-end form-select-variables - -@layer forms { - .form-select { - --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator)}; - - display: block; - width: 100%; - padding: $form-select-padding-y $form-select-indicator-padding $form-select-padding-y $form-select-padding-x; - font-family: $form-select-font-family; - @include font-size($form-select-font-size); - font-weight: $form-select-font-weight; - line-height: $form-select-line-height; - color: $form-select-color; - appearance: none; - background-color: $form-select-bg; - background-image: var(--#{$prefix}form-select-bg-img), var(--#{$prefix}form-select-bg-icon, none); - background-repeat: no-repeat; - background-position: $form-select-bg-position; - background-size: $form-select-bg-size; - border: $form-select-border-width solid $form-select-border-color; - @include border-radius($form-select-border-radius, 0); - @include box-shadow($form-select-box-shadow); - @include transition($form-select-transition); - - &:focus-visible { - border-color: $form-select-focus-border-color; - @include focus-ring(true); - } - - &[multiple], - &[size]:not([size="1"]) { - padding-right: $form-select-padding-x; - background-image: none; - } - - &:disabled { - color: $form-select-disabled-color; - background-color: $form-select-disabled-bg; - border-color: $form-select-disabled-border-color; - } - - // Remove outline from select box in FF - &:-moz-focusring { - color: transparent; - text-shadow: 0 0 0 $form-select-color; - } - } - - .form-select-sm { - padding-top: $form-select-padding-y-sm; - padding-bottom: $form-select-padding-y-sm; - padding-left: $form-select-padding-x-sm; - @include font-size($form-select-font-size-sm); - @include border-radius($form-select-border-radius-sm); - } - - .form-select-lg { - padding-top: $form-select-padding-y-lg; - padding-bottom: $form-select-padding-y-lg; - padding-left: $form-select-padding-x-lg; - @include font-size($form-select-font-size-lg); - @include border-radius($form-select-border-radius-lg); - } - - @if $enable-dark-mode { - @include color-mode(dark) { - .form-select { - --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator-dark)}; - } - } - } -} diff --git a/scss/forms/_form-variables.scss b/scss/forms/_form-variables.scss index bde73334ae..f7a002ddeb 100644 --- a/scss/forms/_form-variables.scss +++ b/scss/forms/_form-variables.scss @@ -1,18 +1,53 @@ @use "../config" as *; +@use "../colors" as *; @use "../variables" as *; +$control-min-height: 2.5rem !default; +$control-min-height-sm: 2rem !default; +$control-min-height-lg: 3rem !default; +$control-padding-y: .375rem !default; +$control-padding-x: .75rem !default; +$control-font-size: $font-size-base !default; +$control-line-height: $line-height-base !default; +$control-color: var(--#{$prefix}body-color) !default; +$control-bg: var(--#{$prefix}body-bg) !default; +$control-border-width: var(--#{$prefix}border-width) !default; +$control-border-color: var(--#{$prefix}border-color) !default; +$control-border-radius: var(--#{$prefix}border-radius) !default; + +$control-padding-y-sm: .25rem !default; +$control-padding-x-sm: .5rem !default; +$control-font-size-sm: $font-size-sm !default; +$control-line-height-sm: $line-height-sm !default; +$control-border-radius-sm: var(--#{$prefix}border-radius-sm) !default; + +$control-padding-y-lg: .5rem !default; +$control-padding-x-lg: 1rem !default; +$control-font-size-lg: $font-size-lg !default; +$control-line-height-lg: $line-height-lg !default; +$control-border-radius-lg: var(--#{$prefix}border-radius-lg) !default; + +$control-select-indicator-color: $gray-600 !default; +$control-select-indicator: url("data:image/svg+xml,") !default; +$control-select-bg-position: right $control-padding-x center !default; +$control-select-bg-size: 16px 12px !default; + +$control-select-indicator-color-dark: $body-color-dark !default; +$control-select-indicator-dark: url("data:image/svg+xml,") !default; + + // scss-docs-start input-btn-variables $input-btn-padding-y: .375rem !default; $input-btn-padding-x: .75rem !default; -$input-btn-font-family: null !default; +// $input-btn-font-family: null !default; $input-btn-font-size: $font-size-base !default; $input-btn-line-height: $line-height-base !default; -$input-btn-focus-width: $focus-ring-width !default; -$input-btn-focus-color-opacity: $focus-ring-opacity !default; -$input-btn-focus-color: $focus-ring-color !default; -$input-btn-focus-blur: $focus-ring-blur !default; -$input-btn-focus-box-shadow: $focus-ring-box-shadow !default; +// $input-btn-focus-width: $focus-ring-width !default; +// $input-btn-focus-color-opacity: $focus-ring-opacity !default; +// $input-btn-focus-color: $focus-ring-color !default; +// $input-btn-focus-blur: $focus-ring-blur !default; +// $input-btn-focus-box-shadow: $focus-ring-box-shadow !default; $input-btn-padding-y-sm: .25rem !default; $input-btn-padding-x-sm: .5rem !default; @@ -22,15 +57,15 @@ $input-btn-padding-y-lg: .5rem !default; $input-btn-padding-x-lg: 1rem !default; $input-btn-font-size-lg: $font-size-lg !default; -$input-btn-border-width: var(--#{$prefix}border-width) !default; +// $input-btn-border-width: var(--#{$prefix}border-width) !default; // scss-docs-end input-btn-variables // scss-docs-start form-input-variables $input-padding-y: $input-btn-padding-y !default; $input-padding-x: $input-btn-padding-x !default; -$input-font-family: $input-btn-font-family !default; +// $input-font-family: $input-btn-font-family !default; $input-font-size: $input-btn-font-size !default; -$input-font-weight: $font-weight-base !default; +// $input-font-weight: $font-weight-base !default; $input-line-height: $input-btn-line-height !default; $input-padding-y-sm: $input-btn-padding-y-sm !default; @@ -48,7 +83,7 @@ $input-disabled-border-color: null !default; $input-color: var(--#{$prefix}body-color) !default; $input-border-color: var(--#{$prefix}border-color) !default; -$input-border-width: $input-btn-border-width !default; +$input-border-width: var(--#{$prefix}border-width) !default; $input-box-shadow: var(--#{$prefix}box-shadow-inset) !default; $input-border-radius: var(--#{$prefix}border-radius) !default; @@ -70,9 +105,12 @@ $input-height-inner: add($input-line-height * 1em, $input-pad $input-height-inner-half: add($input-line-height * .5em, $input-padding-y) !default; $input-height-inner-quarter: add($input-line-height * .25em, $input-padding-y * .5) !default; -$input-height: add($input-line-height * 1em, add($input-padding-y * 2, $input-height-border, false)) !default; -$input-height-sm: add($input-line-height * 1em, add($input-padding-y-sm * 2, $input-height-border, false)) !default; -$input-height-lg: add($input-line-height * 1em, add($input-padding-y-lg * 2, $input-height-border, false)) !default; +// $input-height: add($input-line-height * 1em, add($input-padding-y * 2, $input-height-border, false)) !default; +// $input-height-sm: add($input-line-height * 1em, add($input-padding-y-sm * 2, $input-height-border, false)) !default; +// $input-height-lg: add($input-line-height * 1em, add($input-padding-y-lg * 2, $input-height-border, false)) !default; +$input-height: 2.5rem !default; +$input-height-sm: 2rem !default; +$input-height-lg: 3rem !default; $input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; diff --git a/scss/forms/_input-group.scss b/scss/forms/_input-group.scss index 8d6de5be18..99db177f5f 100644 --- a/scss/forms/_input-group.scss +++ b/scss/forms/_input-group.scss @@ -10,7 +10,7 @@ // scss-docs-start input-group-variables $input-group-addon-padding-y: $input-padding-y !default; $input-group-addon-padding-x: $input-padding-x !default; -$input-group-addon-font-weight: $input-font-weight !default; +// $input-group-addon-font-weight: $input-font-weight !default; $input-group-addon-color: $input-color !default; $input-group-addon-bg: var(--#{$prefix}tertiary-bg) !default; $input-group-addon-border-color: $input-border-color !default; @@ -64,7 +64,7 @@ $input-group-addon-border-color: $input-border-color !default; align-items: center; padding: $input-group-addon-padding-y $input-group-addon-padding-x; @include font-size($input-font-size); // Match inputs - font-weight: $input-group-addon-font-weight; + // font-weight: $input-group-addon-font-weight; line-height: $input-line-height; color: $input-group-addon-color; text-align: center; diff --git a/scss/forms/_switch.scss b/scss/forms/_switch.scss new file mode 100644 index 0000000000..67baf23c25 --- /dev/null +++ b/scss/forms/_switch.scss @@ -0,0 +1,11 @@ +@use "../config" as *; +@use "../colors" as *; +@use "../variables" as *; +@use "../functions" as *; +@use "../vendor/rfs" as *; +@use "../mixins/border-radius" as *; +@use "../mixins/box-shadow" as *; +@use "../mixins/color-mode" as *; +@use "../mixins/focus-ring" as *; +@use "../mixins/transition" as *; +@use "form-variables" as *; diff --git a/scss/forms/index.scss b/scss/forms/index.scss index 57e6cd25ee..a08cde8b39 100644 --- a/scss/forms/index.scss +++ b/scss/forms/index.scss @@ -1,7 +1,6 @@ @forward "labels"; @forward "form-text"; @forward "form-control"; -@forward "form-select"; @forward "form-check"; @forward "form-range"; @forward "floating-labels"; diff --git a/scss/helpers/_stacks.scss b/scss/helpers/_stacks.scss index 36c4ccad70..67c83c3eb6 100644 --- a/scss/helpers/_stacks.scss +++ b/scss/helpers/_stacks.scss @@ -1,13 +1,24 @@ +// stylelint-disable selector-no-qualifying-type + @layer helpers { // scss-docs-start stacks - .hstack { + .hstack, + b-hstack { display: flex; flex-direction: row; align-items: center; align-self: stretch; } + .hstack-start, + b-hstack[align="start"] { + display: flex; + flex-direction: row; + align-items: flex-start; + align-self: stretch; + } - .vstack { + .vstack, + b-vstack { display: flex; flex: 1 1 auto; flex-direction: column; diff --git a/site/data/sidebar.yml b/site/data/sidebar.yml index d8e732f5a4..a930467e19 100644 --- a/site/data/sidebar.yml +++ b/site/data/sidebar.yml @@ -60,8 +60,10 @@ pages: - title: Overview - title: Form control - - title: Select - title: Checks & radios + - title: Checkbox + - title: Radio + - title: Switch - title: Range - title: Input group - title: Floating labels diff --git a/site/src/content/docs/components/buttons.mdx b/site/src/content/docs/components/buttons.mdx index 4f864f7101..56f4abffa9 100644 --- a/site/src/content/docs/components/buttons.mdx +++ b/site/src/content/docs/components/buttons.mdx @@ -15,7 +15,7 @@ Bootstrap has a base `.btn` class that sets up basic styles such as padding and The `.btn` class is intended to be used in conjunction with our button variants, or to serve as a basis for your own custom styles. -If you are using the `.btn` class on its own, remember to at least define some explicit `:focus` and/or `:focus-visible` styles. +When using `.btn` without a modifier, be sure to add some explicit `:focus-visible` styles. ## Variants diff --git a/site/src/content/docs/customize/overview.mdx b/site/src/content/docs/customize/overview.mdx index 7acb624ea6..323e6546b4 100644 --- a/site/src/content/docs/customize/overview.mdx +++ b/site/src/content/docs/customize/overview.mdx @@ -46,6 +46,6 @@ Several Bootstrap components include embedded SVGs in our CSS to style component - [Form switches]([[docsref:/forms/checks-radios#switches]]) - [Form validation icons]([[docsref:/forms/validation#server-side]]) - [Navbar toggle buttons]([[docsref:/components/navbar#responsive-behaviors]]) -- [Select menus]([[docsref:/forms/select]]) +{/* - [Select menus]([[docsref:/forms/select]]) */} Based on [community conversation](https://github.com/twbs/bootstrap/issues/25394), some options for addressing this in your own codebase include [replacing the URLs with locally hosted assets]([[docsref:/getting-started/webpack#extracting-svg-files]]), removing the images and using inline images (not possible in all components), and modifying your CSP. Our recommendation is to carefully review your own security policies and decide on the best path forward, if necessary. diff --git a/site/src/content/docs/forms/checkbox.mdx b/site/src/content/docs/forms/checkbox.mdx new file mode 100644 index 0000000000..cd3aac1de8 --- /dev/null +++ b/site/src/content/docs/forms/checkbox.mdx @@ -0,0 +1,105 @@ +--- +title: Checkbox +description: Highly customizable, native checkbox `` elements for presenting toggleable options. +toc: true +--- + +**Trialing new components with the following rules:** + +- New components are purely components, they don't assume layout of any kind. +- New options for form layout: + - Use new form groups to lay out your forms: `.control-group`, `.check-group`, `.radio-group`. + - Use helpers to lay out your forms—`.hstack` and `.vstack`—with utilities. + +## Basic checkbox + +All checkbox styling is contained to a wrapper class, `.check`. This does the following: + +- Adds a stacking grid layout for the checkbox and custom SVG icon. +- Overrides the default `` appearance with themed colors. +- Handles the toggling of separate paths in our custom SVG for the `:checked` and indeterminate states. Two ``s are included in the SVG, one for each state, and the appropriate `` is shown based on the ``’s state. + +For folks looking to replace our provided icons, you'll need to add the `.checked` and `.indeterminate` classes to the ``s and use them in a single `` element. + +Checkbox layout and labels are handled with additional HTML and CSS. + + + + + + + + `} /> + +## Indeterminate + +Checkboxes can utilize the indeterminate pseudo class when manually set via JavaScript. There is no available HTML attribute for specifying it. + + + + + + + + `} /> + +## Label + +Wrap the `.check` in a `` layout component and add your label. We use a custom element for layout here that sets some basic flexbox styling. + +Consider margin utilities for additional spacing, and flex utilities for alignment. + + +
+ + + + + +
+ + `} /> + +## Description + +With this layout approach, you can easily add a description or other content after the label. Here we use another custom element, ``, to stack the label and description. + + +
+ + + + + +
+ + + Supporting description for the above label. + + `} /> + +## Disabled + +Add the `disabled` attribute and the associated `