Move .form-control and .form-select to --tblr-control-* tokens (#3163)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
Paweł Kunaandcopilot-swe-agent[bot] authored and Bartek committed 2026-10-02 11:32:45 +02:00
1 parent 6cd45d012e
commit 8f00eab8e3
32 files changed
+791 -288

No files matched your search

+6
View File
@@ -0,0 +1,6 @@
---
"@tabler/core": minor
"@tabler/docs": patch
---
Added `--tblr-form-check-*` and `--tblr-form-switch-*` variables, with shared `--tblr-control-checked-bg` and disabled tokens on `:root`.
+6
View File
@@ -0,0 +1,6 @@
---
"@tabler/core": minor
"@tabler/docs": patch
---
Added `--tblr-control-*` variables to `.form-control` and `.form-select`; sizes and the file button now follow them.
+5
View File
@@ -0,0 +1,5 @@
---
"@tabler/core": minor
---
Updated icon addons, select groups, `.col-form-label`, validation icons, OTP and Tom Select to read the `--tblr-control-*` and `--tblr-btn-input-*` variables.
+5
View File
@@ -0,0 +1,5 @@
---
"@tabler/core": minor
---
Fixed `.form-select-sm` and `.form-select-lg` height to match `.form-control-sm` and `.form-control-lg`. Small buttons, inputs and selects are now 32px tall instead of 28px. Fixed the font size of a small Tom Select to match a small native select.
+5
View File
@@ -0,0 +1,5 @@
---
"@tabler/docs": patch
---
Added the Forms → CSS variables page: the control scale, state colors and every `--tblr-control-*`, add-on, floating, range, check and switch token.
@@ -0,0 +1,6 @@
---
"@tabler/core": minor
"@tabler/docs": patch
---
Added `--tblr-input-group-addon-*`, `--tblr-form-floating-*` and `--tblr-range-*` variables to input groups, floating labels and range inputs.
+2 -2
View File
@@ -148,7 +148,7 @@
},
{
"path": "./dist/css/tabler-props.css",
"maxSize": "4.2 kB"
"maxSize": "4.3 kB"
},
{
"path": "./dist/css/tabler-props.min.css",
@@ -156,7 +156,7 @@
},
{
"path": "./dist/css/tabler-props.rtl.css",
"maxSize": "4.2 kB"
"maxSize": "4.3 kB"
},
{
"path": "./dist/css/tabler-props.rtl.min.css",
+7
View File
@@ -52,6 +52,13 @@
}
}
// deprecated(2.0): `--form-select-bg-img` is the old name of `--control-select-bg`
// (from `bootstrap/forms/_form-select.scss`). Still read by `.form-select`,
// so a project that set it keeps its arrow.
.form-select {
--form-select-bg-img: var(--control-select-bg);
}
// `.form-hint` is deprecated, use `.form-text` instead
// (from `bootstrap/forms/_form-text.scss`).
.form-hint {
+8
View File
@@ -125,6 +125,14 @@
--btn-input-xl-min-height: calc(var(--btn-input-xl-line-height) + var(--btn-input-xl-padding-y) * 2 + #{$input-btn-border-width} * 2);
// scss-docs-end btn-input-css-vars
/** Checks, radios and switches: shared state colors, in the names Bootstrap 6 uses */
// scss-docs-start control-state-css-vars
--control-checked-bg: #{$form-check-input-checked-bg-color};
--control-checked-border-color: #{$form-check-input-checked-border-color};
--control-disabled-bg: #{$input-disabled-bg};
--control-disabled-opacity: #{$form-check-input-disabled-opacity};
// scss-docs-end control-state-css-vars
/** Backdrops */
--backdrop-opacity: #{$backdrop-opacity};
--backdrop-bg: #{$backdrop-bg};
+1 -1
View File
@@ -1063,7 +1063,7 @@ $badge-padding-x-lg: 0.5rem !default;
$input-btn-border-width: var(--border-width) !default;
$input-btn-font-family: var(--body-font-family) !default;
$input-btn-padding-y-sm: 0.3125rem !default;
$input-btn-padding-y-sm: 0.4375rem !default;
$input-btn-padding-x-sm: 0.5rem !default;
$input-btn-font-size-sm: $h5-font-size !default;
$input-btn-line-height-sm: 1rem !default;
+41 -22
View File
@@ -1,14 +1,33 @@
@use '../../config' as *;
.form-floating {
// scss-docs-start form-floating-css-vars
--form-floating-height: #{$form-floating-height};
--form-floating-line-height: #{$form-floating-line-height};
--form-floating-padding-x: #{var-if-default($form-floating-padding-x, $input-btn-padding-x, '--btn-input-padding-x')};
--form-floating-padding-y: #{$form-floating-padding-y};
--form-floating-input-padding-t: #{$form-floating-input-padding-t};
--form-floating-input-padding-b: #{$form-floating-input-padding-b};
--form-floating-label-height: #{$form-floating-label-height};
// The textarea label masks the text under it. It is a sibling of the control,
// so it cannot read the control's `--control-bg` and mirrors the scale instead.
--form-floating-label-bg: #{var-if-default($input-bg, var(--bg-forms), '--btn-input-bg')};
--form-floating-label-disabled-bg: #{$input-disabled-bg};
--form-floating-label-border-radius: #{var-if-default($input-border-radius, var(--border-radius), '--btn-input-border-radius')};
--form-floating-label-opacity: #{$form-floating-label-opacity};
--form-floating-label-transform: #{$form-floating-label-transform};
--form-floating-label-disabled-color: #{$form-floating-label-disabled-color};
--form-floating-transition: #{$form-floating-transition};
// scss-docs-end form-floating-css-vars
position: relative;
> .form-control,
> .form-control-plaintext,
> .form-select {
height: $form-floating-height;
min-height: $form-floating-height;
line-height: $form-floating-line-height;
height: var(--form-floating-height);
min-height: var(--form-floating-height);
line-height: var(--form-floating-line-height);
}
> label {
@@ -18,21 +37,21 @@
z-index: 2;
max-width: 100%;
height: 100%; // allow textareas
padding: $form-floating-padding-y $form-floating-padding-x;
padding: var(--form-floating-padding-y) var(--form-floating-padding-x);
overflow: hidden;
color: color-transparent(var(--body-color), $form-floating-label-opacity);
color: color-transparent(var(--body-color), calc(var(--form-floating-label-opacity) * 100%));
text-align: start;
text-overflow: ellipsis;
white-space: nowrap;
pointer-events: none;
border: $input-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($form-floating-transition);
@include transition(var(--form-floating-transition));
}
> .form-control,
> .form-control-plaintext {
padding: $form-floating-padding-y $form-floating-padding-x;
padding: var(--form-floating-padding-y) var(--form-floating-padding-x);
&::placeholder {
color: transparent;
@@ -40,20 +59,20 @@
&:focus,
&:not(:placeholder-shown) {
padding-top: $form-floating-input-padding-t;
padding-bottom: $form-floating-input-padding-b;
padding-top: var(--form-floating-input-padding-t);
padding-bottom: var(--form-floating-input-padding-b);
}
// Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
&:-webkit-autofill {
padding-top: $form-floating-input-padding-t;
padding-bottom: $form-floating-input-padding-b;
padding-top: var(--form-floating-input-padding-t);
padding-bottom: var(--form-floating-input-padding-b);
}
}
> .form-select {
padding-top: $form-floating-input-padding-t;
padding-bottom: $form-floating-input-padding-b;
padding-inline-start: $form-floating-padding-x;
padding-top: var(--form-floating-input-padding-t);
padding-bottom: var(--form-floating-input-padding-b);
padding-inline-start: var(--form-floating-padding-x);
}
> .form-control:focus,
@@ -61,29 +80,29 @@
> .form-control-plaintext,
> .form-select {
~ label {
transform: $form-floating-label-transform;
transform: var(--form-floating-label-transform);
}
}
// Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
> .form-control:-webkit-autofill {
~ label {
transform: $form-floating-label-transform;
transform: var(--form-floating-label-transform);
}
}
> textarea:focus,
> textarea:not(:placeholder-shown) {
~ label::after {
position: absolute;
inset: $form-floating-padding-y ($form-floating-padding-x * 0.5);
inset: var(--form-floating-padding-y) calc(var(--form-floating-padding-x) * 0.5);
z-index: -1;
height: $form-floating-label-height;
height: var(--form-floating-label-height);
content: '';
background-color: $input-bg;
@include border-radius($input-border-radius);
background-color: var(--form-floating-label-bg);
@include border-radius(var(--form-floating-label-border-radius));
}
}
> textarea:disabled ~ label::after {
background-color: $input-disabled-bg;
background-color: var(--form-floating-label-disabled-bg);
}
> .form-control-plaintext {
@@ -95,6 +114,6 @@
> :disabled ~ label,
> .form-control:disabled ~ label {
// Required for `.form-control`s because of specificity
color: $form-floating-label-disabled-color;
color: var(--form-floating-label-disabled-color);
}
}
+62 -28
View File
@@ -5,44 +5,67 @@
@use '../../config' as *;
.form-check {
// scss-docs-start form-check-css-vars
--form-check-min-height: #{$form-check-min-height};
--form-check-padding-start: #{$form-check-padding-start};
--form-check-margin-bottom: #{$form-check-margin-bottom};
// scss-docs-end form-check-css-vars
display: block;
min-height: $form-check-min-height;
padding-inline-start: $form-check-padding-start;
margin-bottom: $form-check-margin-bottom;
min-height: var(--form-check-min-height);
padding-inline-start: var(--form-check-padding-start);
margin-bottom: var(--form-check-margin-bottom);
.form-check-input {
float: inline-start;
margin-inline-start: $form-check-padding-start * -1;
margin-inline-start: calc(var(--form-check-padding-start) * -1);
}
}
.form-check-reverse {
padding-inline-end: $form-check-padding-start;
padding-inline-end: var(--form-check-padding-start);
padding-inline-start: 0;
text-align: end;
.form-check-input {
float: inline-end;
margin-inline-end: $form-check-padding-start * -1;
margin-inline-end: calc(var(--form-check-padding-start) * -1);
margin-inline-start: 0;
}
}
// The checked, indeterminate and disabled tokens read the shared state colors
// on `:root` (`--control-checked-bg` and friends) until the Sass variable is
// configured, so one override retunes checks, radios and switches together.
.form-check-input {
// scss-docs-start form-check-input-css-vars
--form-check-input-width: #{$form-check-input-width};
--form-check-bg: #{$form-check-input-bg};
--form-check-border: #{$form-check-input-border};
--form-check-border-radius: #{$form-check-input-border-radius};
--form-check-box-shadow: #{$form-check-input-box-shadow};
--form-check-icon-color: #{$form-check-input-checked-color};
--form-check-focus-border-color: #{$form-check-input-focus-border};
--form-check-active-filter: #{$form-check-input-active-filter};
--form-check-checked-bg: #{var-if-default($form-check-input-checked-bg-color, var(--primary), '--control-checked-bg')};
--form-check-checked-border-color: #{var-if-default($form-check-input-checked-border-color, var(--border-color-translucent), '--control-checked-border-color')};
--form-check-indeterminate-bg: #{var-if-default($form-check-input-indeterminate-bg-color, var(--primary), '--control-checked-bg')};
--form-check-indeterminate-border-color: #{var-if-default($form-check-input-indeterminate-border-color, var(--primary), '--form-check-indeterminate-bg')};
--form-check-disabled-opacity: #{var-if-default($form-check-input-disabled-opacity, 0.5, '--control-disabled-opacity')};
--form-check-transition: #{$form-check-transition};
// scss-docs-end form-check-input-css-vars
position: relative;
flex-shrink: 0;
width: $form-check-input-width;
height: $form-check-input-width;
width: var(--form-check-input-width);
height: var(--form-check-input-width);
margin-top: ($line-height-base - $form-check-input-width) * 0.5; // line-height minus check height
vertical-align: top;
appearance: none;
background-color: var(--form-check-bg);
border: $form-check-input-border;
border: var(--form-check-border);
print-color-adjust: exact; // Keep themed appearance for print
@include transition($form-check-transition);
@include transition(var(--form-check-transition));
// Start the focus ring's `outline-color` transition from transparent, not `currentcolor`.
outline-color: transparent;
@@ -62,7 +85,7 @@
&[type='checkbox'] {
--form-check-icon: #{escape-svg($form-check-input-checked-bg-image)};
@include border-radius($form-check-input-border-radius);
@include border-radius(var(--form-check-border-radius));
}
&[type='radio'] {
@@ -73,17 +96,17 @@
}
&:active {
filter: $form-check-input-active-filter;
filter: var(--form-check-active-filter);
}
&:focus-visible {
border-color: $form-check-input-focus-border;
border-color: var(--form-check-focus-border-color);
@include focus-ring(true);
}
&:checked {
background-color: $form-check-input-checked-bg-color;
border-color: $form-check-input-checked-border-color;
background-color: var(--form-check-checked-bg);
border-color: var(--form-check-checked-border-color);
&::before {
opacity: 1;
@@ -94,8 +117,8 @@
--form-check-icon: #{escape-svg($form-check-input-indeterminate-bg-image)};
--form-check-icon-color: #{$form-check-input-indeterminate-color};
background-color: $form-check-input-indeterminate-bg-color;
border-color: $form-check-input-indeterminate-border-color;
background-color: var(--form-check-indeterminate-bg);
border-color: var(--form-check-indeterminate-border-color);
&::before {
opacity: 1;
@@ -105,7 +128,7 @@
&:disabled {
pointer-events: none;
filter: none;
opacity: $form-check-input-disabled-opacity;
opacity: var(--form-check-disabled-opacity);
}
// Use disabled attribute in addition of :disabled pseudo-class
@@ -129,18 +152,29 @@
//
.form-switch {
padding-inline-start: $form-switch-padding-start;
// scss-docs-start form-switch-css-vars
--form-switch-width: #{$form-switch-width};
--form-switch-height: #{$form-switch-height};
--form-switch-padding-start: #{if(sass($form-switch-padding-start == $form-switch-width + 0.5rem): calc(var(--form-switch-width) + 0.5rem); else: $form-switch-padding-start)};
--form-switch-border-radius: #{if(sass($form-switch-border-radius == $form-switch-width): var(--form-switch-width); else: $form-switch-border-radius)};
--form-switch-focus-color: #{$form-switch-focus-color};
--form-switch-checked-color: #{$form-switch-checked-color};
--form-switch-disabled-bg: #{var-if-default($form-switch-disabled-bg, var(--bg-forms-disabled), '--control-disabled-bg')};
--form-switch-disabled-color: #{$form-switch-disabled-color};
// scss-docs-end form-switch-css-vars
padding-inline-start: var(--form-switch-padding-start);
.form-check-input {
--form-switch-color: #{$form-switch-color};
// The knob is a circle three quarters of the track height, inset by an eighth
// — the same geometry the old `viewBox='-4 -4 8 8'` svg had.
--form-switch-knob-size: calc(#{$form-switch-height} * 0.75);
--form-switch-knob-offset: calc(#{$form-switch-height} * 0.125);
--form-switch-knob-size: calc(var(--form-switch-height) * 0.75);
--form-switch-knob-offset: calc(var(--form-switch-height) * 0.125);
width: $form-switch-width;
margin-inline-start: $form-switch-padding-start * -1;
@include border-radius($form-switch-border-radius, 0);
width: var(--form-switch-width);
margin-inline-start: calc(var(--form-switch-padding-start) * -1);
@include border-radius(var(--form-switch-border-radius), 0);
@include transition($form-switch-transition);
// The knob replaces the masked check icon: a plain circle that slides.
@@ -159,11 +193,11 @@
}
&:focus {
--form-switch-color: #{$form-switch-focus-color};
--form-switch-color: var(--form-switch-focus-color);
}
&:checked {
--form-switch-color: #{$form-switch-checked-color};
--form-switch-color: var(--form-switch-checked-color);
&::before {
inset-inline-start: calc(100% - var(--form-switch-knob-size) - var(--form-switch-knob-offset));
@@ -172,11 +206,11 @@
}
&.form-check-reverse {
padding-inline-end: $form-switch-padding-start;
padding-inline-end: var(--form-switch-padding-start);
padding-inline-start: 0;
.form-check-input {
margin-inline-end: $form-switch-padding-start * -1;
margin-inline-end: calc(var(--form-switch-padding-start) * -1);
margin-inline-start: 0;
}
}
+79 -70
View File
@@ -6,25 +6,57 @@
@use '../../config' as *;
// The control tokens, in the names Bootstrap 6 uses. One block serves every
// text-like control: `.form-select` and `.form-control-plaintext` stand alone
// (no `.form-control`), so they need the same declarations. A token seeded from
// a size variable reads the `:root` scale until the Sass variable is configured.
.form-select,
.form-control-plaintext,
.form-control {
// scss-docs-start control-css-vars
--control-min-height: calc(var(--control-line-height) + var(--control-padding-y) * 2 + var(--control-border-width) * 2);
--control-padding-y: #{var-if-default($input-padding-y, $input-btn-padding-y, '--btn-input-padding-y')};
--control-padding-x: #{var-if-default($input-padding-x, $input-btn-padding-x, '--btn-input-padding-x')};
@include rfs(var-if-default($input-font-size, $input-btn-font-size, '--btn-input-font-size'), --control-font-size);
--control-line-height: #{var-if-default($input-line-height, $input-btn-line-height, '--btn-input-line-height')};
--control-fg: #{var-if-default($input-color, var(--body-color), '--btn-input-fg')};
--control-bg: #{var-if-default($input-bg, var(--bg-forms), '--btn-input-bg')};
--control-border-width: #{$input-border-width};
--control-border-color: #{$input-border-color};
--control-border-radius: #{var-if-default($input-border-radius, var(--border-radius), '--btn-input-border-radius')};
--control-box-shadow: #{$input-box-shadow};
--control-focus-fg: #{var-if-default($input-focus-color, $input-color, '--control-fg')};
--control-focus-bg: #{var-if-default($input-focus-bg, $input-bg, '--control-bg')};
--control-focus-border-color: #{$input-focus-border-color};
--control-placeholder-color: #{$input-placeholder-color};
--control-disabled-color: #{if(sass($input-disabled-color): $input-disabled-color; else: $form-secondary-color)};
--control-disabled-bg: #{$input-disabled-bg};
--control-disabled-border-color: #{if(sass($input-disabled-border-color): $input-disabled-border-color; else: var(--control-border-color))};
--control-action-bg: #{$form-file-button-bg};
--control-action-hover-bg: #{$form-file-button-hover-bg};
--control-transition: #{$input-transition};
// scss-docs-end control-css-vars
}
.form-control {
display: block;
width: 100%;
padding: $input-padding-y $input-padding-x;
padding: var(--control-padding-y) var(--control-padding-x);
font-family: $input-font-family;
@include font-size($input-font-size);
@include font-size(var(--control-font-size));
font-weight: $input-font-weight;
line-height: $input-line-height;
color: $input-color;
line-height: var(--control-line-height);
color: var(--control-fg);
appearance: none; // Fix appearance for date inputs in Safari
background-color: $input-bg;
background-color: var(--control-bg);
background-clip: padding-box;
border: $input-border-width solid $input-border-color;
border: var(--control-border-width) solid var(--control-border-color);
// Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS.
@include border-radius($input-border-radius, 0);
@include border-radius(var(--control-border-radius), 0);
@include box-shadow($input-box-shadow);
@include transition($input-transition);
@include box-shadow(var(--control-box-shadow));
@include transition(var(--control-transition));
// Start the focus ring's `outline-color` transition from transparent, not `currentcolor`.
outline-color: transparent;
@@ -38,9 +70,9 @@
// Customize the `:focus` state to imitate native WebKit styles.
&:focus {
color: $input-focus-color;
background-color: $input-focus-bg;
border-color: $input-focus-border-color;
color: var(--control-focus-fg);
background-color: var(--control-focus-bg);
border-color: var(--control-focus-border-color);
--focus-ring-offset: -1px;
@include focus-ring(true);
}
@@ -74,7 +106,7 @@
// Placeholder
&::placeholder {
color: $input-placeholder-color;
color: var(--control-placeholder-color);
// Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526.
opacity: 1;
}
@@ -85,31 +117,31 @@
// disabled if the fieldset is disabled. Due to implementation difficulty, we
// don't honor that edge case; we style them as disabled anyway.
&:disabled {
color: $input-disabled-color;
background-color: $input-disabled-bg;
border-color: $input-disabled-border-color;
color: var(--control-disabled-color);
background-color: var(--control-disabled-bg);
border-color: var(--control-disabled-border-color);
// iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655.
opacity: 1;
}
// File input buttons theming
&::file-selector-button {
padding: $input-padding-y $input-padding-x;
margin: (-$input-padding-y) (-$input-padding-x);
margin-inline-end: $input-padding-x;
padding: var(--control-padding-y) var(--control-padding-x);
margin: calc(var(--control-padding-y) * -1) calc(var(--control-padding-x) * -1);
margin-inline-end: var(--control-padding-x);
color: $form-file-button-color;
@include gradient-bg($form-file-button-bg);
@include gradient-bg(var(--control-action-bg));
pointer-events: none;
border-color: inherit;
border-style: solid;
border-width: 0;
border-inline-end-width: $input-border-width;
border-inline-end-width: var(--control-border-width);
border-radius: 0; // stylelint-disable-line property-disallowed-list
@include transition($btn-transition);
}
&:hover:not(:disabled):not([readonly])::file-selector-button {
background-color: $form-file-button-hover-bg;
background-color: var(--control-action-hover-bg);
}
}
@@ -121,13 +153,13 @@
.form-control-plaintext {
display: block;
width: 100%;
padding: $input-padding-y 0;
padding: var(--control-padding-y) 0;
margin-bottom: 0; // match inputs if this class comes on inputs with default margins
line-height: $input-line-height;
color: $input-plaintext-color;
line-height: var(--control-line-height);
color: #{var-if-default($input-plaintext-color, $input-color, '--control-fg')};
background-color: transparent;
border: solid transparent;
border-width: $input-border-width 0;
border-width: var(--control-border-width) 0;
&:focus {
outline: 0;
@@ -143,36 +175,29 @@
// Form control sizing
//
// Build on `.form-control` with modifier classes to decrease or increase the
// height and font-size of form controls.
// height and font-size of form controls. A size only moves the tokens; the
// height, the file button and the color swatch follow.
//
// Repeated in `_input_group.scss` to avoid Sass extend issues.
.form-control-sm {
line-height: $input-line-height-sm;
min-height: $input-height-sm;
padding: $input-padding-y-sm $input-padding-x-sm;
@include font-size($input-font-size-sm);
@include border-radius($input-border-radius-sm);
&::file-selector-button {
padding: $input-padding-y-sm $input-padding-x-sm;
margin: (-$input-padding-y-sm) (-$input-padding-x-sm);
margin-inline-end: $input-padding-x-sm;
}
min-height: var(--control-min-height);
@include font-size(var(--control-font-size));
--control-padding-y: #{var-if-default($input-padding-y-sm, $input-btn-padding-y-sm, '--btn-input-sm-padding-y')};
--control-padding-x: #{var-if-default($input-padding-x-sm, $input-btn-padding-x-sm, '--btn-input-sm-padding-x')};
@include rfs(var-if-default($input-font-size-sm, $input-btn-font-size-sm, '--btn-input-sm-font-size'), --control-font-size);
--control-line-height: #{var-if-default($input-line-height-sm, $input-btn-line-height-sm, '--btn-input-sm-line-height')};
--control-border-radius: #{var-if-default($input-border-radius-sm, var(--border-radius-sm), '--btn-input-sm-border-radius')};
}
.form-control-lg {
line-height: $input-line-height-lg;
min-height: $input-height-lg;
padding: $input-padding-y-lg $input-padding-x-lg;
@include font-size($input-font-size-lg);
@include border-radius($input-border-radius-lg);
&::file-selector-button {
padding: $input-padding-y-lg $input-padding-x-lg;
margin: (-$input-padding-y-lg) (-$input-padding-x-lg);
margin-inline-end: $input-padding-x-lg;
}
min-height: var(--control-min-height);
@include font-size(var(--control-font-size));
--control-padding-y: #{var-if-default($input-padding-y-lg, $input-btn-padding-y-lg, '--btn-input-lg-padding-y')};
--control-padding-x: #{var-if-default($input-padding-x-lg, $input-btn-padding-x-lg, '--btn-input-lg-padding-x')};
@include rfs(var-if-default($input-font-size-lg, $input-btn-font-size-lg, '--btn-input-lg-font-size'), --control-font-size);
--control-line-height: #{var-if-default($input-line-height-lg, $input-btn-line-height-lg, '--btn-input-lg-line-height')};
--control-border-radius: #{var-if-default($input-border-radius-lg, var(--border-radius-lg), '--btn-input-lg-border-radius')};
}
// Make sure textareas don't shrink too much when resized
@@ -180,15 +205,7 @@
// stylelint-disable selector-no-qualifying-type
textarea {
&.form-control {
min-height: $input-height;
}
&.form-control-sm {
min-height: $input-height-sm;
}
&.form-control-lg {
min-height: $input-height-lg;
min-height: var(--control-min-height);
}
}
@@ -196,8 +213,8 @@ textarea {
.form-control-color {
width: $form-color-width;
height: $input-height;
padding: $input-padding-y;
height: var(--control-min-height);
padding: var(--control-padding-y);
&:not(:disabled):not([readonly]) {
cursor: pointer;
@@ -205,19 +222,11 @@ textarea {
&::-moz-color-swatch {
border: 0 !important; // stylelint-disable-line declaration-no-important
@include border-radius($input-border-radius);
@include border-radius(var(--control-border-radius));
}
&::-webkit-color-swatch {
border: 0 !important; // stylelint-disable-line declaration-no-important
@include border-radius($input-border-radius);
}
&.form-control-sm {
height: $input-height-sm;
}
&.form-control-lg {
height: $input-height-lg;
@include border-radius(var(--control-border-radius));
}
}
+50 -32
View File
@@ -7,8 +7,26 @@
@use '../../config' as *;
.form-range {
// scss-docs-start range-css-vars
--range-track-width: #{$form-range-track-width};
--range-track-height: #{$form-range-track-height};
--range-track-cursor: #{$form-range-track-cursor};
--range-track-bg: #{$form-range-track-bg};
--range-track-border-radius: #{$form-range-track-border-radius};
--range-track-box-shadow: #{$form-range-track-box-shadow};
--range-thumb-width: #{$form-range-thumb-width};
--range-thumb-height: #{$form-range-thumb-height};
--range-thumb-bg: #{$form-range-thumb-bg};
--range-thumb-border: #{$form-range-thumb-border};
--range-thumb-border-radius: #{$form-range-thumb-border-radius};
--range-thumb-box-shadow: #{$form-range-thumb-box-shadow};
--range-thumb-active-bg: #{$form-range-thumb-active-bg};
--range-thumb-disabled-bg: #{$form-range-thumb-disabled-bg};
--range-thumb-transition: #{$form-range-thumb-transition};
// scss-docs-end range-css-vars
width: 100%;
height: add($form-range-thumb-height, $form-range-thumb-focus-box-shadow-width * 2);
height: calc(var(--range-thumb-height) + #{$form-range-thumb-focus-box-shadow-width * 2});
padding: 0; // Need to reset padding
appearance: none;
background-color: transparent;
@@ -31,69 +49,69 @@
}
&::-webkit-slider-thumb {
width: $form-range-thumb-width;
height: $form-range-thumb-height;
margin-top: ($form-range-track-height - $form-range-thumb-height) * 0.5; // Webkit specific
width: var(--range-thumb-width);
height: var(--range-thumb-height);
margin-top: calc((var(--range-track-height) - var(--range-thumb-height)) / 2); // Webkit specific
appearance: none;
@include gradient-bg($form-range-thumb-bg);
border: $form-range-thumb-border;
@include border-radius($form-range-thumb-border-radius);
@include box-shadow($form-range-thumb-box-shadow);
@include transition($form-range-thumb-transition);
@include gradient-bg(var(--range-thumb-bg));
border: var(--range-thumb-border);
@include border-radius(var(--range-thumb-border-radius));
@include box-shadow(var(--range-thumb-box-shadow));
@include transition(var(--range-thumb-transition));
outline-color: transparent;
&:active {
@include gradient-bg($form-range-thumb-active-bg);
@include gradient-bg(var(--range-thumb-active-bg));
}
}
&::-webkit-slider-runnable-track {
width: $form-range-track-width;
height: $form-range-track-height;
width: var(--range-track-width);
height: var(--range-track-height);
color: transparent; // Why?
cursor: $form-range-track-cursor;
background-color: $form-range-track-bg;
cursor: var(--range-track-cursor);
background-color: var(--range-track-bg);
border-color: transparent;
@include border-radius($form-range-track-border-radius);
@include box-shadow($form-range-track-box-shadow);
@include border-radius(var(--range-track-border-radius));
@include box-shadow(var(--range-track-box-shadow));
}
&::-moz-range-thumb {
width: $form-range-thumb-width;
height: $form-range-thumb-height;
width: var(--range-thumb-width);
height: var(--range-thumb-height);
appearance: none;
@include gradient-bg($form-range-thumb-bg);
border: $form-range-thumb-border;
@include border-radius($form-range-thumb-border-radius);
@include box-shadow($form-range-thumb-box-shadow);
@include transition($form-range-thumb-transition);
@include gradient-bg(var(--range-thumb-bg));
border: var(--range-thumb-border);
@include border-radius(var(--range-thumb-border-radius));
@include box-shadow(var(--range-thumb-box-shadow));
@include transition(var(--range-thumb-transition));
outline-color: transparent;
&:active {
@include gradient-bg($form-range-thumb-active-bg);
@include gradient-bg(var(--range-thumb-active-bg));
}
}
&::-moz-range-track {
width: $form-range-track-width;
height: $form-range-track-height;
width: var(--range-track-width);
height: var(--range-track-height);
color: transparent;
cursor: $form-range-track-cursor;
background-color: $form-range-track-bg;
cursor: var(--range-track-cursor);
background-color: var(--range-track-bg);
border-color: transparent; // Firefox specific?
@include border-radius($form-range-track-border-radius);
@include box-shadow($form-range-track-box-shadow);
@include border-radius(var(--range-track-border-radius));
@include box-shadow(var(--range-track-box-shadow));
}
&:disabled {
pointer-events: none;
&::-webkit-slider-thumb {
background-color: $form-range-thumb-disabled-bg;
background-color: var(--range-thumb-disabled-bg);
}
&::-moz-range-thumb {
background-color: $form-range-thumb-disabled-bg;
background-color: var(--range-thumb-disabled-bg);
}
}
}
+66 -30
View File
@@ -5,75 +5,111 @@
@use '../../config' as *;
// The `--control-*` tokens come from the shared block in `_form-control.scss`.
// A `$form-select-*` variable defaults to its `$input-*` twin; only a value a
// project changed on its own has to be written again here.
@mixin -select-token($token, $value, $default) {
@if $value != $default {
#{$token}: #{$value};
}
}
.form-select {
--form-select-bg-img: #{escape-svg($form-select-indicator)};
// scss-docs-start form-select-css-vars
--control-select-bg: #{escape-svg($form-select-indicator)};
--control-select-bg-dark: #{escape-svg($form-select-indicator-dark)};
--control-select-bg-position: #{$form-select-bg-position};
--control-select-bg-size: #{$form-select-bg-size};
// Room for the arrow. Reads the root scale, not `--control-padding-x`, so the
// size modifiers keep the same 3rem they always had.
--control-select-indicator-padding: #{if(sass($form-select-indicator-padding == $form-select-padding-x * 3 and $form-select-padding-x == $input-btn-padding-x): calc(var(--btn-input-padding-x) * 3); else: $form-select-indicator-padding)};
// scss-docs-end form-select-css-vars
@include -select-token(--control-padding-y, $form-select-padding-y, $input-padding-y);
@include -select-token(--control-padding-x, $form-select-padding-x, $input-padding-x);
@include -select-token(--control-font-size, $form-select-font-size, $input-font-size);
@include -select-token(--control-line-height, $form-select-line-height, $input-line-height);
@include -select-token(--control-fg, $form-select-color, $input-color);
@include -select-token(--control-bg, $form-select-bg, $input-bg);
@include -select-token(--control-border-width, $form-select-border-width, $input-border-width);
@include -select-token(--control-border-color, $form-select-border-color, $input-border-color);
@include -select-token(--control-border-radius, $form-select-border-radius, $input-border-radius);
@include -select-token(--control-box-shadow, $form-select-box-shadow, $input-box-shadow);
@include -select-token(--control-focus-border-color, $form-select-focus-border-color, $input-focus-border-color);
@include -select-token(--control-disabled-color, $form-select-disabled-color, $input-disabled-color);
@include -select-token(--control-disabled-bg, $form-select-disabled-bg, $input-disabled-bg);
@include -select-token(--control-disabled-border-color, $form-select-disabled-border-color, $input-disabled-border-color);
@include -select-token(--control-transition, $form-select-transition, $input-transition);
display: block;
width: 100%;
padding: $form-select-padding-y $form-select-indicator-padding $form-select-padding-y $form-select-padding-x;
padding: var(--control-padding-y) var(--control-padding-x);
padding-inline-end: var(--control-select-indicator-padding);
font-family: $form-select-font-family;
@include font-size($form-select-font-size);
@include font-size(var(--control-font-size));
font-weight: $form-select-font-weight;
line-height: $form-select-line-height;
color: $form-select-color;
line-height: var(--control-line-height);
color: var(--control-fg);
appearance: none;
background-color: $form-select-bg;
background-image: var(--form-select-bg-img), var(--form-select-bg-icon, none);
background-color: var(--control-bg);
// deprecated(2.0): `--form-select-bg-img` is the old name of `--control-select-bg`
background-image: var(--form-select-bg-img, var(--control-select-bg)), var(--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);
background-position: var(--control-select-bg-position);
background-size: var(--control-select-bg-size);
border: var(--control-border-width) solid var(--control-border-color);
@include border-radius(var(--control-border-radius), 0);
@include box-shadow(var(--control-box-shadow));
@include transition(var(--control-transition));
// Start the focus ring's `outline-color` transition from transparent, not `currentcolor`.
outline-color: transparent;
&:focus {
border-color: $form-select-focus-border-color;
border-color: var(--control-focus-border-color);
--focus-ring-offset: -1px;
@include focus-ring(true);
}
&[multiple],
&[size]:not([size='1']) {
padding-inline-end: $form-select-padding-x;
padding-inline-end: var(--control-padding-x);
background-image: none;
}
&:disabled {
color: $form-select-disabled-color;
background-color: $form-select-disabled-bg;
border-color: $form-select-disabled-border-color;
color: var(--control-disabled-color);
background-color: var(--control-disabled-bg);
border-color: var(--control-disabled-border-color);
}
// Remove outline from select box in FF
&:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 $form-select-color;
text-shadow: 0 0 0 var(--control-fg);
}
}
// A size moves the same tokens as `.form-control-sm/-lg`, line height
// included, so a select and an input of one size are equally tall.
.form-select-sm {
padding-top: $form-select-padding-y-sm;
padding-bottom: $form-select-padding-y-sm;
padding-inline-start: $form-select-padding-x-sm;
@include font-size($form-select-font-size-sm);
@include border-radius($form-select-border-radius-sm);
--control-padding-y: #{var-if-default($form-select-padding-y-sm, $input-btn-padding-y-sm, '--btn-input-sm-padding-y')};
--control-padding-x: #{var-if-default($form-select-padding-x-sm, $input-btn-padding-x-sm, '--btn-input-sm-padding-x')};
@include rfs(var-if-default($form-select-font-size-sm, $input-btn-font-size-sm, '--btn-input-sm-font-size'), --control-font-size);
--control-line-height: #{var-if-default($input-line-height-sm, $input-btn-line-height-sm, '--btn-input-sm-line-height')};
--control-border-radius: #{var-if-default($form-select-border-radius-sm, var(--border-radius-sm), '--btn-input-sm-border-radius')};
}
.form-select-lg {
padding-top: $form-select-padding-y-lg;
padding-bottom: $form-select-padding-y-lg;
padding-inline-start: $form-select-padding-x-lg;
@include font-size($form-select-font-size-lg);
@include border-radius($form-select-border-radius-lg);
--control-padding-y: #{var-if-default($form-select-padding-y-lg, $input-btn-padding-y-lg, '--btn-input-lg-padding-y')};
--control-padding-x: #{var-if-default($form-select-padding-x-lg, $input-btn-padding-x-lg, '--btn-input-lg-padding-x')};
@include rfs(var-if-default($form-select-font-size-lg, $input-btn-font-size-lg, '--btn-input-lg-font-size'), --control-font-size);
--control-line-height: #{var-if-default($input-line-height-lg, $input-btn-line-height-lg, '--btn-input-lg-line-height')};
--control-border-radius: #{var-if-default($form-select-border-radius-lg, var(--border-radius-lg), '--btn-input-lg-border-radius')};
}
@if $enable-dark-mode {
@include color-mode(dark) {
.form-select {
--form-select-bg-img: #{escape-svg($form-select-indicator-dark)};
--control-select-bg: var(--control-select-bg-dark);
}
}
}
+84 -30
View File
@@ -7,7 +7,21 @@
@use '../../config' as *;
// Addon tokens, in the names Bootstrap 6 uses. The addon sits next to the
// control, not inside it, so it reads the `:root` scale rather than the
// control's own `--control-*` tokens.
.input-group {
// scss-docs-start input-group-css-vars
--input-group-addon-padding-y: #{var-if-default($input-group-addon-padding-y, $input-btn-padding-y, '--btn-input-padding-y')};
--input-group-addon-padding-x: #{var-if-default($input-group-addon-padding-x, $input-btn-padding-x, '--btn-input-padding-x')};
@include rfs(var-if-default($input-font-size, $input-btn-font-size, '--btn-input-font-size'), --input-group-addon-font-size);
--input-group-addon-line-height: #{var-if-default($input-line-height, $input-btn-line-height, '--btn-input-line-height')};
--input-group-addon-color: #{$input-group-addon-color};
--input-group-addon-bg: #{$input-group-addon-bg};
--input-group-addon-border-color: #{$input-group-addon-border-color};
--input-group-addon-border-radius: #{var-if-default($input-border-radius, var(--border-radius), '--btn-input-border-radius')};
// scss-docs-end input-group-css-vars
position: relative;
display: flex;
flex-wrap: wrap; // For form validation feedback
@@ -51,48 +65,88 @@
.input-group-text {
display: flex;
align-items: center;
padding: $input-group-addon-padding-y $input-group-addon-padding-x;
@include font-size($input-font-size); // Match inputs
padding: var(--input-group-addon-padding-y) var(--input-group-addon-padding-x);
@include font-size(var(--input-group-addon-font-size)); // Match inputs
font-weight: $input-group-addon-font-weight;
line-height: $input-line-height;
color: $input-group-addon-color;
line-height: var(--input-group-addon-line-height);
color: var(--input-group-addon-color);
text-align: center;
white-space: nowrap;
background-color: $input-group-addon-bg;
border: $input-border-width solid $input-group-addon-border-color;
@include border-radius($input-border-radius);
background-color: var(--input-group-addon-bg);
border: $input-border-width solid var(--input-group-addon-border-color);
@include border-radius(var(--input-group-addon-border-radius));
}
// Sizing
//
// Remix the default form control sizing classes into new ones for easier
// manipulation.
// A size moves the addon and control tokens; the button keeps its own rules
// until `.btn` reads the scale too.
.input-group-lg > .form-control,
.input-group-lg > .form-select,
.input-group-lg > .input-group-text,
.input-group-lg > .btn {
line-height: $input-line-height-lg;
min-height: $input-height-lg;
padding: $input-padding-y-lg $input-padding-x-lg;
@include font-size($input-font-size-lg);
@include border-radius($input-border-radius-lg);
@mixin -input-group-size($size) {
--input-group-addon-padding-y: #{var-if-default(map.get($-input-group-sizes, $size, 'padding-y'), map.get($-input-group-sizes, $size, 'scale-padding-y'), '--btn-input-#{$size}-padding-y')};
--input-group-addon-padding-x: #{var-if-default(map.get($-input-group-sizes, $size, 'padding-x'), map.get($-input-group-sizes, $size, 'scale-padding-x'), '--btn-input-#{$size}-padding-x')};
@include rfs(var-if-default(map.get($-input-group-sizes, $size, 'font-size'), map.get($-input-group-sizes, $size, 'scale-font-size'), '--btn-input-#{$size}-font-size'), --input-group-addon-font-size);
--input-group-addon-line-height: #{var-if-default(map.get($-input-group-sizes, $size, 'line-height'), map.get($-input-group-sizes, $size, 'scale-line-height'), '--btn-input-#{$size}-line-height')};
--input-group-addon-border-radius: #{var-if-default(map.get($-input-group-sizes, $size, 'border-radius'), map.get($-input-group-sizes, $size, 'scale-border-radius'), '--btn-input-#{$size}-border-radius')};
> .form-control,
> .form-select {
--control-padding-y: var(--input-group-addon-padding-y);
--control-padding-x: var(--input-group-addon-padding-x);
--control-font-size: var(--input-group-addon-font-size);
--control-line-height: var(--input-group-addon-line-height);
--control-border-radius: var(--input-group-addon-border-radius);
min-height: var(--control-min-height);
}
> .form-select {
padding-inline-end: calc(#{var-if-default($form-select-padding-x, $input-btn-padding-x, '--btn-input-padding-x')} + var(--control-select-indicator-padding));
}
> .btn {
line-height: map.get($-input-group-sizes, $size, 'line-height');
min-height: map.get($-input-group-sizes, $size, 'height');
padding: map.get($-input-group-sizes, $size, 'padding-y') map.get($-input-group-sizes, $size, 'padding-x');
@include font-size(map.get($-input-group-sizes, $size, 'font-size'));
@include border-radius(map.get($-input-group-sizes, $size, 'border-radius'));
}
}
.input-group-sm > .form-control,
.input-group-sm > .form-select,
.input-group-sm > .input-group-text,
.input-group-sm > .btn {
line-height: $input-line-height-sm;
min-height: $input-height-sm;
padding: $input-padding-y-sm $input-padding-x-sm;
@include font-size($input-font-size-sm);
@include border-radius($input-border-radius-sm);
$-input-group-sizes: (
'sm': (
'padding-y': $input-padding-y-sm,
'padding-x': $input-padding-x-sm,
'font-size': $input-font-size-sm,
'line-height': $input-line-height-sm,
'border-radius': $input-border-radius-sm,
'height': $input-height-sm,
'scale-padding-y': $input-btn-padding-y-sm,
'scale-padding-x': $input-btn-padding-x-sm,
'scale-font-size': $input-btn-font-size-sm,
'scale-line-height': $input-btn-line-height-sm,
'scale-border-radius': var(--border-radius-sm),
),
'lg': (
'padding-y': $input-padding-y-lg,
'padding-x': $input-padding-x-lg,
'font-size': $input-font-size-lg,
'line-height': $input-line-height-lg,
'border-radius': $input-border-radius-lg,
'height': $input-height-lg,
'scale-padding-y': $input-btn-padding-y-lg,
'scale-padding-x': $input-btn-padding-x-lg,
'scale-font-size': $input-btn-font-size-lg,
'scale-line-height': $input-btn-line-height-lg,
'scale-border-radius': var(--border-radius-lg),
),
);
.input-group-lg {
@include -input-group-size('lg');
}
.input-group-lg > .form-select,
.input-group-sm > .form-select {
padding-inline-end: $form-select-padding-x + $form-select-indicator-padding;
.input-group-sm {
@include -input-group-size('sm');
}
// Rounded corners
+9 -9
View File
@@ -15,24 +15,24 @@
// For use with horizontal and inline forms, when you need the label (or legend)
// text to align with the form controls.
.col-form-label {
padding-top: add($input-padding-y, $input-border-width);
padding-bottom: add($input-padding-y, $input-border-width);
padding-top: calc(#{var-if-default($input-padding-y, $input-btn-padding-y, '--btn-input-padding-y')} + #{$input-border-width});
padding-bottom: calc(#{var-if-default($input-padding-y, $input-btn-padding-y, '--btn-input-padding-y')} + #{$input-border-width});
margin-bottom: 0; // Override the `<legend>` default
@include font-size(inherit); // Override the `<legend>` default
font-style: $form-label-font-style;
font-weight: $form-label-font-weight;
line-height: $input-line-height;
line-height: #{var-if-default($input-line-height, $input-btn-line-height, '--btn-input-line-height')};
color: $form-label-color;
}
.col-form-label-lg {
padding-top: add($input-padding-y-lg, $input-border-width);
padding-bottom: add($input-padding-y-lg, $input-border-width);
@include font-size($input-font-size-lg);
padding-top: calc(#{var-if-default($input-padding-y-lg, $input-btn-padding-y-lg, '--btn-input-lg-padding-y')} + #{$input-border-width});
padding-bottom: calc(#{var-if-default($input-padding-y-lg, $input-btn-padding-y-lg, '--btn-input-lg-padding-y')} + #{$input-border-width});
@include font-size(var-if-default($input-font-size-lg, $input-btn-font-size-lg, '--btn-input-lg-font-size'));
}
.col-form-label-sm {
padding-top: add($input-padding-y-sm, $input-border-width);
padding-bottom: add($input-padding-y-sm, $input-border-width);
@include font-size($input-font-size-sm);
padding-top: calc(#{var-if-default($input-padding-y-sm, $input-btn-padding-y-sm, '--btn-input-sm-padding-y')} + #{$input-border-width});
padding-bottom: calc(#{var-if-default($input-padding-y-sm, $input-btn-padding-y-sm, '--btn-input-sm-padding-y')} + #{$input-border-width});
@include font-size(var-if-default($input-font-size-sm, $input-btn-font-size-sm, '--btn-input-sm-font-size'));
}
+17
View File
@@ -117,3 +117,20 @@
@content;
}
}
// `$input-height` and its sizes as a token: the `:root` scale's min height
// (`--btn-input-min-height`) while the input metrics keep their defaults, the
// configured Sass value otherwise. Elements that sit next to a control (an icon
// addon, a select-group tile, an otp slot) match its height through it.
@function input-height-token($size: null) {
@if $size == 'sm' {
$default: add($input-btn-line-height-sm, add(calc($input-btn-padding-y-sm * 2), calc(#{$input-btn-border-width} * 2), false));
@return if(sass($input-height-sm == $default): var(--btn-input-sm-min-height); else: $input-height-sm);
}
@if $size == 'lg' {
$default: add($input-btn-line-height-lg, add(calc($input-btn-padding-y-lg * 2), calc(#{$input-btn-border-width} * 2), false));
@return if(sass($input-height-lg == $default): var(--btn-input-lg-min-height); else: $input-height-lg);
}
$default: add($input-btn-line-height, add(calc($input-btn-padding-y * 2), calc(#{$input-btn-border-width} * 2), false));
@return if(sass($input-height == $default): var(--btn-input-min-height); else: $input-height);
}
@@ -56,6 +56,11 @@ exports[`css custom-property prefixing > leaves vendor-owned names alone and pre
"--tblr-chart-3",
"--tblr-chart-4",
"--tblr-chart-5",
"--tblr-control-font-size",
"--tblr-control-line-height",
"--tblr-control-padding-x",
"--tblr-control-padding-y",
"--tblr-control-placeholder-color",
"--tblr-danger",
"--tblr-focus-ring",
"--tblr-focus-ring-color",
@@ -0,0 +1,14 @@
// Tests for `input-height-token()` in scss/mixins/_mixins.scss: the height of
// a control as a token that reads the `:root` scale while the input metrics
// keep their defaults.
@use 'sass:meta';
@use '../config' as *;
@include describe('input-height-token') {
@include it('reads the root scale for the default metrics') {
@include assert-equal(meta.inspect(input-height-token()), 'var(--btn-input-min-height)');
@include assert-equal(meta.inspect(input-height-token('sm')), 'var(--btn-input-sm-min-height)');
@include assert-equal(meta.inspect(input-height-token('lg')), 'var(--btn-input-lg-min-height)');
}
}
@@ -13,6 +13,10 @@
@include assert-equal(var-if-default(1rem, 0.5625rem, --btn-input-padding-y), 1rem);
}
@include it('takes the token name as a string too') {
@include assert-equal(meta.inspect(var-if-default(1rem, 1rem, '--btn-input-padding-x')), 'var(--btn-input-padding-x)');
}
@include it('compares var() defaults by value') {
@include assert-equal(meta.inspect(var-if-default(var(--border-radius), var(--border-radius), --btn-input-border-radius)), 'var(--btn-input-border-radius)');
@include assert-equal(meta.inspect(var-if-default(0, var(--border-radius), --btn-input-border-radius)), '0');
+5 -5
View File
@@ -53,7 +53,7 @@ Form control
&:disabled,
&.disabled {
color: $form-secondary-color;
color: var(--control-disabled-color);
user-select: none;
}
@@ -155,7 +155,7 @@ Input group
*/
.input-group {
box-shadow: $input-box-shadow;
@include border-radius($input-border-radius);
@include border-radius(var(--input-group-addon-border-radius));
.form-control,
.form-select,
@@ -173,7 +173,7 @@ Input group
&:focus-within {
--focus-ring-offset: -1px;
@include focus-ring(true);
@include border-radius($input-border-radius);
@include border-radius(var(--input-group-addon-border-radius));
.form-control,
.input-group-text {
@@ -183,7 +183,7 @@ Input group
.form-control {
&:focus {
border-color: $input-border-color;
border-color: var(--control-border-color);
outline: 0;
box-shadow: none;
}
@@ -199,7 +199,7 @@ Input group
.input-group-text {
z-index: 10;
background: $form-check-input-bg;
background: #{var-if-default($form-check-input-bg, var(--bg-forms), '--btn-input-bg')};
@include transition($input-transition);
&:first-child {
+6 -8
View File
@@ -24,11 +24,9 @@ Form check
}
.form-check-input {
--form-check-input-width: #{$form-check-input-width};
margin-top: ($form-check-min-height - $form-check-input-width) * 0.5;
margin-top: calc((#{$form-check-min-height} - var(--form-check-input-width)) / 2);
background-size: var(--form-check-input-width);
box-shadow: $form-check-input-box-shadow;
box-shadow: var(--form-check-box-shadow);
}
.form-check-label {
@@ -67,15 +65,15 @@ Form switch
*/
.form-switch {
.form-check-input {
height: $form-switch-height;
margin-top: ($form-check-min-height - $form-switch-height) * 0.5;
height: var(--form-switch-height);
margin-top: calc((#{$form-check-min-height} - var(--form-switch-height)) / 2);
@include transition(background-color $transition-time, background-position $transition-time, $focus-ring-transition);
// An off switch that is disabled fills its track like a disabled input,
// so it no longer looks like an off switch that can still be toggled.
&:disabled:not(:checked) {
--form-switch-color: #{$form-switch-disabled-color};
background-color: $form-switch-disabled-bg;
--form-switch-color: var(--form-switch-disabled-color);
background-color: var(--form-switch-disabled-bg);
}
}
}
+1 -1
View File
@@ -30,7 +30,7 @@ Icon input
align-items: center;
justify-content: center;
min-width: var(--input-icon-addon-width);
height: $input-height;
height: input-height-token();
font-size: 1.2em;
color: var(--icon-color);
pointer-events: none;
+3 -3
View File
@@ -114,7 +114,7 @@
.otp-input:disabled ~ .otp-slots .otp-slot {
color: var(--disabled-color);
background-color: $input-disabled-bg;
background-color: #{var-if-default($input-disabled-bg, var(--bg-forms-disabled), '--control-disabled-bg')};
}
// Zero gap with shared, merged borders; only the first and last slot keep a
@@ -149,12 +149,12 @@
}
.otp-sm {
--otp-size: #{$input-height-sm};
--otp-size: #{input-height-token('sm')};
--otp-font-size: #{$input-font-size-sm};
}
.otp-lg {
--otp-size: #{$input-height-lg};
--otp-size: #{input-height-token('lg')};
--otp-font-size: #{$input-font-size-lg};
}
+6 -6
View File
@@ -36,11 +36,11 @@ Select group
.form-selectgroup-label {
position: relative;
display: block;
min-width: $input-height;
padding: $input-btn-padding-y $input-btn-padding-x;
min-width: input-height-token();
padding: var(--btn-input-padding-y) var(--btn-input-padding-x);
margin: 0;
font-size: $input-btn-font-size;
line-height: $input-line-height;
font-size: var(--btn-input-font-size);
line-height: #{var-if-default($input-line-height, $input-btn-line-height, '--btn-input-line-height')};
color: var(--secondary);
text-align: center;
cursor: pointer;
@@ -95,8 +95,8 @@ Select group
.form-selectgroup-check-floated {
position: absolute;
inset-inline-end: $input-btn-padding-y;
top: $input-btn-padding-y;
inset-inline-end: var(--btn-input-padding-y);
top: var(--btn-input-padding-y);
}
.form-selectgroup-input:checked + .form-selectgroup-label {
+3 -3
View File
@@ -11,7 +11,7 @@
// `.btn`/`.btn-sm`/`.btn-lg` use for their own icons (see ui/_buttons.scss).
%validation-icon-size {
--form-feedback-icon-size: #{$input-btn-icon-size};
--form-feedback-icon-inset: #{$input-padding-x};
--form-feedback-icon-inset: #{var-if-default($input-padding-x, $input-btn-padding-x, '--btn-input-padding-x')};
padding-inline-end: calc(var(--form-feedback-icon-size) + var(--form-feedback-icon-inset) * 2) !important;
background-position: right var(--form-feedback-icon-inset) center !important;
background-size: var(--form-feedback-icon-size) var(--form-feedback-icon-size) !important;
@@ -19,12 +19,12 @@
%validation-icon-size-sm {
--form-feedback-icon-size: #{$input-btn-icon-size-sm};
--form-feedback-icon-inset: #{$input-padding-x-sm};
--form-feedback-icon-inset: #{var-if-default($input-padding-x-sm, $input-btn-padding-x-sm, '--btn-input-sm-padding-x')};
}
%validation-icon-size-lg {
--form-feedback-icon-size: #{$input-btn-icon-size-lg};
--form-feedback-icon-inset: #{$input-padding-x-lg};
--form-feedback-icon-inset: #{var-if-default($input-padding-x-lg, $input-btn-padding-x-lg, '--btn-input-lg-padding-x')};
}
%validation-icon-size-textarea {
+14 -38
View File
@@ -72,49 +72,25 @@
// The bootstrap5 preset hardcodes Bootstrap's own input metrics on
// `.ts-control` (0.375rem 0.75rem padding, 1.5 line-height), so a Tom Select
// came out 5px shorter than a `.form-control` next to it (#2567). Use Tabler's
// input tokens instead, in every size. The multi-value control follows the
// preset's formula: take the item's 1px padding, 1px border and 3px bottom
// margin out of the control's padding so the chips fill the same height.
// came out 5px shorter than a `.form-control` next to it (#2567). The wrapper
// carries the `.form-control` / `.form-select` class, so it holds the
// `--control-*` tokens: read them and every size follows on its own. The
// multi-value control follows the preset's formula: take the item's 1px
// padding, 1px border and 3px bottom margin out of the control's padding so
// the chips fill the same height. The font size is `!important` because the
// preset sets its own on `.form-select-sm.has-items .ts-control`, which
// outranks this selector.
.ts-wrapper.form-control,
.ts-wrapper.form-select {
.ts-control {
padding: $input-padding-y $input-padding-x;
font-size: $input-font-size;
line-height: $input-line-height;
padding: var(--control-padding-y) var(--control-padding-x);
font-size: var(--control-font-size) !important;
line-height: var(--control-line-height);
}
&.multi.has-items .ts-control {
padding-top: calc(#{$input-padding-y} - 2px) !important;
padding-bottom: calc(#{$input-padding-y} - 5px);
}
&.form-control-sm,
&.form-select-sm {
.ts-control {
padding: $input-padding-y-sm $input-padding-x-sm;
font-size: $input-font-size-sm;
line-height: $input-line-height-sm;
}
&.multi.has-items .ts-control {
padding-top: calc(#{$input-padding-y-sm} - 2px) !important;
padding-bottom: calc(#{$input-padding-y-sm} - 5px);
}
}
&.form-control-lg,
&.form-select-lg {
.ts-control {
padding: $input-padding-y-lg $input-padding-x-lg;
font-size: $input-font-size-lg;
line-height: $input-line-height-lg;
}
&.multi.has-items .ts-control {
padding-top: calc(#{$input-padding-y-lg} - 2px) !important;
padding-bottom: calc(#{$input-padding-y-lg} - 5px);
}
padding-top: calc(var(--control-padding-y) - 2px) !important;
padding-bottom: calc(var(--control-padding-y) - 5px);
}
}
@@ -172,7 +148,7 @@
.ts-control input {
&::placeholder {
color: $input-placeholder-color;
color: var(--control-placeholder-color, #{$input-placeholder-color});
}
}
+259
View File
@@ -0,0 +1,259 @@
---
title: CSS variables
seoTitle: Form CSS variables
order: 11
summary: Every form control reads its size, colors and states from CSS variables, so you can restyle inputs, selects, checks and switches at runtime without recompiling Sass.
description: Reference of the CSS variables that size and color Tabler form controls, with examples of runtime overrides.
related: [/ui/forms/elements, /ui/forms/floating-labels, /ui/getting-started/customize]
---
import Example from '@components/Example.astro';
## Overview
Form controls are built on three layers of custom properties. Each layer reads the one above it, so you can change a single value or a single control.
1. **The control scale on `:root`.** `--tblr-btn-input-*` holds the padding, font size, line height, radius and minimum height of a control, with a `-sm-*`, `-lg-*` and `-xl-*` set for each size. `--tblr-control-checked-bg` and its siblings hold the state colors that checks, radios and switches share.
2. **Component tokens on the control.** `.form-control` and `.form-select` carry `--tblr-control-*`, `.input-group` carries `--tblr-input-group-addon-*`, `.form-floating` carries `--tblr-form-floating-*`, and so on. By default each token points at the scale.
3. **The declarations.** Every `padding`, `color` or `border` in the stylesheet reads a token, never a fixed value.
The names follow Bootstrap 6, so a project that moves to a future major keeps its overrides.
Sass still works. A `$input-*`, `$form-select-*` or `$form-check-*` variable that you set in Sass is compiled into the token as a fixed value. That control then ignores the scale on `:root`, as it did before the tokens existed.
## Usage
### Change every control at once
Override the scale on `:root`. Inputs, selects, add-ons, floating labels, select-group tiles and column labels all follow.
```css
:root {
--tblr-btn-input-padding-y: 0.75rem;
--tblr-btn-input-padding-x: 1.25rem;
--tblr-btn-input-border-radius: 0;
}
```
The scale inherits, so the same variables on a container change only the controls inside it.
<Example column>
<div style="--tblr-btn-input-padding-y: 0.75rem; --tblr-btn-input-border-radius: 0">
<div class="mb-3">
<label class="form-label">Taller, square controls</label>
<input type="text" class="form-control" placeholder="Input" />
</div>
<div class="input-group">
<span class="input-group-text">@</span>
<input type="text" class="form-control" placeholder="Username" />
</div>
</div>
</Example>
### Change one control
Set a component token on the element. Tokens on the element win over the scale.
<Example column>
<input type="text" class="form-control mb-3" placeholder="Pill input" style="--tblr-control-border-radius: 2rem; --tblr-control-padding-x: 1.5rem" />
<select class="form-select" style="--tblr-control-bg: var(--tblr-bg-surface-secondary); --tblr-control-border-color: transparent">
<option>Flat select</option>
</select>
</Example>
### Make a custom size
The size classes only move the size tokens, so a custom size is a few tokens on a class of your own.
```css
.form-control-xs {
--tblr-control-padding-y: 0.125rem;
--tblr-control-padding-x: 0.5rem;
--tblr-control-font-size: 0.75rem;
--tblr-control-line-height: 1rem;
}
```
The minimum height, the file selector button and the color swatch follow the tokens on their own.
### Recolor checks, radios and switches
The checked and disabled colors of every check control come from `:root`.
<Example column>
<div style="--tblr-control-checked-bg: var(--tblr-green)">
<label class="form-check"><input class="form-check-input" type="checkbox" checked /><span class="form-check-label">Checkbox</span></label>
<label class="form-check"><input class="form-check-input" type="radio" checked /><span class="form-check-label">Radio</span></label>
<label class="form-check form-switch"><input class="form-check-input" type="checkbox" checked /><span class="form-check-label">Switch</span></label>
</div>
</Example>
## Reference
### Control scale on `:root`
| Variable | Default |
| --- | --- |
| `--tblr-btn-input-fg` | `var(--tblr-body-color)` |
| `--tblr-btn-input-bg` | `var(--tblr-bg-forms)` |
| `--tblr-btn-input-padding-y` | `0.5625rem` |
| `--tblr-btn-input-padding-x` | `1rem` |
| `--tblr-btn-input-font-size` | `0.875rem` |
| `--tblr-btn-input-line-height` | `1.25rem` |
| `--tblr-btn-input-border-radius` | `var(--tblr-border-radius)` |
| `--tblr-btn-input-min-height` | line height + 2 × padding + 2 × border |
The same set exists per size as `--tblr-btn-input-sm-*`, `--tblr-btn-input-lg-*` and `--tblr-btn-input-xl-*`.
| Size | Padding | Font size | Line height | Radius |
| --- | --- | --- | --- | --- |
| `sm` | `0.4375rem 0.5rem` | `0.75rem` | `1rem` | `var(--tblr-border-radius-sm)` |
| `lg` | `0.6875rem 1.5rem` | `1rem` | `1.5rem` | `var(--tblr-border-radius-lg)` |
| `xl` | `0.6875rem 1.75rem` | `1.5rem` | `2rem` | `var(--tblr-border-radius)` |
### State colors on `:root`
| Variable | Default | Read by |
| --- | --- | --- |
| `--tblr-control-checked-bg` | `var(--tblr-primary)` | checked and indeterminate checks, radios, switches |
| `--tblr-control-checked-border-color` | `var(--tblr-border-color-translucent)` | checked checks and radios |
| `--tblr-control-disabled-bg` | `var(--tblr-bg-forms-disabled)` | disabled switches and OTP slots |
| `--tblr-control-disabled-opacity` | `0.5` | disabled checks, radios, switches |
### Inputs and selects
Set on `.form-control`, `.form-control-plaintext` and `.form-select`. `.form-control-sm/-lg` and `.form-select-sm/-lg` override the first five with the matching size of the scale.
| Variable | Default |
| --- | --- |
| `--tblr-control-padding-y` | `var(--tblr-btn-input-padding-y)` |
| `--tblr-control-padding-x` | `var(--tblr-btn-input-padding-x)` |
| `--tblr-control-font-size` | `var(--tblr-btn-input-font-size)` |
| `--tblr-control-line-height` | `var(--tblr-btn-input-line-height)` |
| `--tblr-control-border-radius` | `var(--tblr-btn-input-border-radius)` |
| `--tblr-control-min-height` | line height + 2 × padding + 2 × border |
| `--tblr-control-fg` | `var(--tblr-btn-input-fg)` |
| `--tblr-control-bg` | `var(--tblr-btn-input-bg)` |
| `--tblr-control-border-width` | `var(--tblr-border-width)` |
| `--tblr-control-border-color` | `var(--tblr-border-color)` |
| `--tblr-control-box-shadow` | `var(--tblr-shadow-input)` |
| `--tblr-control-focus-fg` | `var(--tblr-control-fg)` |
| `--tblr-control-focus-bg` | `var(--tblr-control-bg)` |
| `--tblr-control-focus-border-color` | primary mixed with white |
| `--tblr-control-placeholder-color` | `var(--tblr-tertiary)` |
| `--tblr-control-disabled-color` | `var(--tblr-secondary)` |
| `--tblr-control-disabled-bg` | `var(--tblr-bg-forms-disabled)` |
| `--tblr-control-disabled-border-color` | `var(--tblr-control-border-color)` |
| `--tblr-control-action-bg` | `var(--tblr-tertiary-bg)` (file selector button) |
| `--tblr-control-action-hover-bg` | `var(--tblr-secondary-bg)` |
| `--tblr-control-transition` | border color, outline color and shadow, `0.15s` |
`.form-select` adds the arrow: `--tblr-control-select-bg`, `--tblr-control-select-bg-dark`, `--tblr-control-select-bg-position`, `--tblr-control-select-bg-size` and `--tblr-control-select-indicator-padding` (the room kept for the arrow, `3 ×` the scale's horizontal padding).
Tom Select copies the `.form-control` or `.form-select` class onto its wrapper, so its control reads the same tokens.
### Input groups
Set on `.input-group`. `.input-group-sm/-lg` override the size tokens and pass them to the controls in the group.
| Variable | Default |
| --- | --- |
| `--tblr-input-group-addon-padding-y` | `var(--tblr-btn-input-padding-y)` |
| `--tblr-input-group-addon-padding-x` | `var(--tblr-btn-input-padding-x)` |
| `--tblr-input-group-addon-font-size` | `var(--tblr-btn-input-font-size)` |
| `--tblr-input-group-addon-line-height` | `var(--tblr-btn-input-line-height)` |
| `--tblr-input-group-addon-color` | `var(--tblr-gray-500)` |
| `--tblr-input-group-addon-bg` | `var(--tblr-bg-surface-secondary)` |
| `--tblr-input-group-addon-border-color` | `var(--tblr-border-color)` |
| `--tblr-input-group-addon-border-radius` | `var(--tblr-btn-input-border-radius)` |
### Floating labels
Set on `.form-floating`.
| Variable | Default |
| --- | --- |
| `--tblr-form-floating-height` | `3.5rem` + 2 × border |
| `--tblr-form-floating-line-height` | `1.25` |
| `--tblr-form-floating-padding-x` | `var(--tblr-btn-input-padding-x)` |
| `--tblr-form-floating-padding-y` | `1rem` |
| `--tblr-form-floating-input-padding-t` | `1.625rem` |
| `--tblr-form-floating-input-padding-b` | `0.625rem` |
| `--tblr-form-floating-label-height` | `1.5em` |
| `--tblr-form-floating-label-bg` | `var(--tblr-btn-input-bg)` (masks the text under a textarea label) |
| `--tblr-form-floating-label-disabled-bg` | `var(--tblr-bg-forms-disabled)` |
| `--tblr-form-floating-label-border-radius` | `var(--tblr-btn-input-border-radius)` |
| `--tblr-form-floating-label-opacity` | `0.65` |
| `--tblr-form-floating-label-transform` | `scale(0.85) translateY(-0.5rem) translateX(0.15rem)` |
| `--tblr-form-floating-label-disabled-color` | gray `600` in light mode, `400` in dark |
| `--tblr-form-floating-transition` | opacity and transform, `0.1s` |
### Range inputs
Set on `.form-range`.
| Variable | Default |
| --- | --- |
| `--tblr-range-track-width` | `100%` |
| `--tblr-range-track-height` | `0.25rem` |
| `--tblr-range-track-cursor` | `pointer` |
| `--tblr-range-track-bg` | `var(--tblr-border-color)` |
| `--tblr-range-track-border-radius` | `1rem` |
| `--tblr-range-track-box-shadow` | `var(--tblr-box-shadow-inset)` |
| `--tblr-range-thumb-width` | `1rem` |
| `--tblr-range-thumb-height` | `1rem` |
| `--tblr-range-thumb-bg` | `var(--tblr-primary)` |
| `--tblr-range-thumb-border` | `2px` white |
| `--tblr-range-thumb-border-radius` | `1rem` |
| `--tblr-range-thumb-box-shadow` | soft black shadow |
| `--tblr-range-thumb-active-bg` | primary mixed with white |
| `--tblr-range-thumb-disabled-bg` | `var(--tblr-secondary-color)` |
| `--tblr-range-thumb-transition` | background, border, outline and shadow, `0.15s` |
### Checks and radios
`.form-check` carries the layout: `--tblr-form-check-min-height` (`1.25rem`), `--tblr-form-check-padding-start` (`2rem`) and `--tblr-form-check-margin-bottom` (`0.75rem`). The input itself carries the look.
| Variable on `.form-check-input` | Default |
| --- | --- |
| `--tblr-form-check-input-width` | `1.25rem` |
| `--tblr-form-check-bg` | `var(--tblr-bg-forms)` |
| `--tblr-form-check-border` | `var(--tblr-border-width) var(--tblr-border-style) var(--tblr-border-color)` |
| `--tblr-form-check-border-radius` | `var(--tblr-border-radius)` |
| `--tblr-form-check-box-shadow` | `var(--tblr-shadow-input)` |
| `--tblr-form-check-icon-color` | `#fff` |
| `--tblr-form-check-focus-border-color` | primary mixed with white |
| `--tblr-form-check-active-filter` | `brightness(90%)` |
| `--tblr-form-check-checked-bg` | `var(--tblr-control-checked-bg)` |
| `--tblr-form-check-checked-border-color` | `var(--tblr-control-checked-border-color)` |
| `--tblr-form-check-indeterminate-bg` | `var(--tblr-control-checked-bg)` |
| `--tblr-form-check-indeterminate-border-color` | `var(--tblr-form-check-indeterminate-bg)` |
| `--tblr-form-check-disabled-opacity` | `var(--tblr-control-disabled-opacity)` |
| `--tblr-form-check-transition` | outline color, `0.15s` |
### Switches
Set on `.form-switch`. The knob is three quarters of the height and slides by the width, so both follow these two tokens.
| Variable | Default |
| --- | --- |
| `--tblr-form-switch-width` | `2rem` |
| `--tblr-form-switch-height` | `1.25rem` |
| `--tblr-form-switch-padding-start` | width + `0.5rem` |
| `--tblr-form-switch-border-radius` | `var(--tblr-form-switch-width)` |
| `--tblr-form-switch-focus-color` | primary mixed with white |
| `--tblr-form-switch-checked-color` | `var(--tblr-white)` (the knob) |
| `--tblr-form-switch-disabled-bg` | `var(--tblr-control-disabled-bg)` |
| `--tblr-form-switch-disabled-color` | gray `400` in light mode, `600` in dark |
`.form-switch-lg` keeps its own `--tblr-form-switch-lg-*` set.
## Sass variables
The tokens are seeded from the Sass variables of the same component: `$input-*` for inputs, `$form-select-*` for selects, `$input-group-addon-*`, `$form-floating-*`, `$form-range-*`, `$form-check-*` and `$form-switch-*`. Configure them through `@use` as before. A configured variable becomes a fixed token value, so it no longer follows `--tblr-btn-input-*` at runtime; leave it at its default to keep the runtime link.
```scss
@use '@tabler/core/scss/tabler' with (
$input-padding-y: 0.75rem,
$input-border-radius: 0
);
```
+7
View File
@@ -6,6 +6,7 @@ docs-libs: [nouislider]
description: Styled inputs, selects, checkboxes and radios, with states, sizes and layout options.
order: 1
related: [/ui/forms/validation, /ui/forms/helpers, /ui/forms/fieldset, /ui/plugins/date-picker, /ui/plugins/advanced-select]
css-vars: control
sass-vars: input
---
import Example from '@components/Example.astro';
@@ -287,6 +288,8 @@ Use radio buttons for the parts of your form which require users to choose one o
Use checkboxes if you want to allow users to select more than one option from a set of predefined options or to turn an option on or off.
Checks, radios and switches share their state colors through `--tblr-control-checked-bg`, `--tblr-control-checked-border-color`, `--tblr-control-disabled-bg` and `--tblr-control-disabled-opacity` on `:root`. Each control also has its own tokens: `--tblr-form-check-*` on `.form-check-input` and `--tblr-form-switch-*` on `.form-switch`.
<Example column>
<div class="mb-3">
<div class="form-label">Checkboxes</div>
@@ -328,6 +331,8 @@ Use checkboxes if you want to allow users to select more than one option from a
Add a [range slider](/ui/plugins/range-slider) to make it possible for users to set a value or range, such as a price range or a time frame.
The track and the thumb read `--tblr-range-*` custom properties on `.form-range`: `--tblr-range-track-height`, `--tblr-range-track-bg`, `--tblr-range-thumb-width`, `--tblr-range-thumb-bg`, `--tblr-range-thumb-border` and the rest of the `track-*` and `thumb-*` set.
<Example column>
<div class="mb-3"> <label class="form-label">Range input</label> <input type="range" class="form-range mb-2" value="40" min="0" max="100" step="10" /> <div class="form-range mb-2 text-green" id="range-color"></div> </div> <script>{`document.addEventListener("DOMContentLoaded", function () { window.noUiSlider && noUiSlider.create(document.getElementById("range-color"), { start: 40, connect: [true, false], step: 10, range: { min: 0, max: 100, }, }); });`}</script>
</Example>
@@ -336,6 +341,8 @@ Add a [range slider](/ui/plugins/range-slider) to make it possible for users to
Create a group of input controls and place add-ons on either side of an input.
The add-on reads `--tblr-input-group-addon-*` custom properties on `.input-group` (`padding-y`, `padding-x`, `font-size`, `line-height`, `color`, `bg`, `border-color`, `border-radius`). `.input-group-sm` and `.input-group-lg` only change these tokens and pass them on to the controls in the group.
<Example column>
<div class="mb-3">
<label class="form-label">Input group</label>
@@ -3,6 +3,7 @@ title: Floating labels
order: 3
summary: Floating labels put the label inside the field. The label sits over the empty control and moves up when the user types or selects a value.
description: Show labels inside form controls.
css-vars: form-floating
---
import Example from '@components/Example.astro';
+4
View File
@@ -383,6 +383,10 @@
{
"title": "OTP input",
"url": "/ui/forms/otp-input"
},
{
"title": "CSS variables",
"url": "/ui/forms/css-variables"
}
]
},