---
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.
@
### Change one control
Set a component token on the element. Tokens on the element win over the scale.
### 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`.
## 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 fills the height minus a `0.125rem` gap on every side 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-bg` | gray `300` in light mode, translucent white in dark (the off track) |
| `--tblr-form-switch-focus-color` | `var(--tblr-white)` (the knob) |
| `--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
);
```