# Upgrade to 1.6

> Move a project from Tabler 1.5 to 1.6. Nothing breaks. The page lists what is deprecated, with a before and after example for CSS, JavaScript and Sass.

Upgrade guide from Tabler 1.5 to 1.6 with every deprecated class, color variable, Sass variable and JavaScript helper, and what to use instead.

Source: https://docs.tabler.io/ui/getting-started/upgrade/1-6

---

Tabler 1.6 is a drop-in update. A project that works on 1.5 works on 1.6 without a change: every class, custom property, Sass variable, function and file that 1.5 had is still there.

Some of them are **deprecated**. They keep working in every 1.x release and go away in 2.0. This page lists them with the replacement, so you can move over when it suits you. Sass warns about a deprecated function when you compile; set `$enable-deprecation-messages: false` to silence it.

There is one thing to check if you compile Tabler from the Sass sources and run Sass color functions on Tabler's variables: see [Variables that turned into color-mix()](#variables-that-turned-into-color-mix).

If you're coming from 1.4 or older, do the [1.5 upgrade](/ui/getting-started/upgrade/1-5) first.

## Overview

Nothing in this table is required. Use it to find what you can modernize.

If you…|You can…
---|---
Use `--tblr-primary-rgb` or any `--tblr-*-rgb` variable|Switch to `color-mix()`, see [RGB color variables](#rgb-color-variables-are-deprecated)
Load `dist/libs/autosize` or `dist/libs/countup.js`|Remove the script tags, both are part of `tabler.js` now
Call `autosize(el)` or `new countUp.CountUp(...)` yourself|Switch to `tabler.Autosize` and `tabler.CountUp`
Load `dist/libs/clipboard` or call `new ClipboardJS(...)`|Switch to the `Clipboard` component, see [Clipboard](#clipboard-is-built-in)
Load `dist/libs/litepicker` or call `new Litepicker(...)`|Switch to the `Datepicker` plugin, see [Datepicker replaces Litepicker](#datepicker-replaces-litepicker)
Use `<span class="legend">` as a colored dot|Rename to `.legend-dot`, see [Legend is a component now](#legend-is-a-component-now)
Use `.form-hint`|Rename to `.form-text`, see [Form hint is form text](#form-hint-is-form-text)
Call `tabler.tabler.getColor()` or `tabler.tabler.hexToRgba()`|Read the variable yourself, see [Deprecated JavaScript helpers](#deprecated-javascript-helpers)
Override `$form-switch-bg-image` or the toggler icon variables|See [Masked icons](#masked-icons)
Override `$input-btn-focus-*`, a `$*-focus-box-shadow` variable or `--tblr-btn-focus-box-shadow`|Use the focus ring tokens, see [The focus ring is an outline](#the-focus-ring-is-an-outline)
Use `theme-color-lighter()` or another function from the [list below](#deprecated-functions)|Switch to the replacement
Call `darken()`, `rgba()` or another Sass color function on `$primary-bg-subtle` or another derived color|Build from the base color instead, see [Variables that turned into color-mix()](#variables-that-turned-into-color-mix)
Create components from TypeScript with a hand-written options object|Check the value types, see [Stricter TypeScript types](#stricter-typescript-types)
Ship your own build and want the smallest CSS|Set `$enable-deprecated: false`, see [Dropping the deprecated layer](#dropping-the-deprecated-layer)

## Update the package

Install the new version:

```sh
npm install --save @tabler/core@1.6.0
```

Or update the CDN links:

```html
<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/@tabler/core@1.6.0/dist/css/tabler.min.css"
/>
<script src="https://cdn.jsdelivr.net/npm/@tabler/core@1.6.0/dist/js/tabler.min.js"></script>
```

## RGB color variables are deprecated

Tabler emits an RGB triplet next to every color, so you can build a transparent version with `rgba()`:

```css
/* works in 1.5 and 1.6 */
.my-highlight {
  background-color: rgba(var(--tblr-primary-rgb), 0.2);
}
```

Tabler itself no longer reads the `--tblr-*-rgb` and `--tblr-*-lt-rgb` variables. It mixes its tints, shades and translucent surfaces at runtime with `color-mix()`, and your CSS can do the same:

```css
/* 1.6 and later */
.my-highlight {
  background-color: color-mix(in oklab, var(--tblr-primary) 20%, transparent);
}
```

The triplets are still emitted, with the same values, and are removed in 2.0. To find every place to move over, grep your project for `-rgb)`.

There's a good reason to switch. The triplets are static: overriding `--tblr-primary` does not change `--tblr-primary-rgb`, so in 1.5 you had to set both. Everything Tabler derives from `--tblr-primary` now follows it, so one variable recolors the whole theme:

```diff
  :root {
    --tblr-primary: #f11d46;
-   --tblr-primary-rgb: 241, 29, 70;
  }
```

`--tblr-primary-lt`, `--tblr-primary-darken` and the other derived variables still exist, they're computed with `color-mix()` now.

The same goes for the one component token that was a triplet: `.status` used to set `--tblr-status-color-rgb`, and it is deprecated in favor of `--tblr-status-color`, which holds the color itself:

```diff
  .status-custom {
-   --tblr-status-color-rgb: 241, 29, 70;
+   --tblr-status-color: #f11d46;
  }
```

### The palette is defined in oklch

The color values themselves moved from hex to `oklch()`. `--tblr-primary` used to resolve to `#066fd1`, now it resolves to `oklch(54.6% 0.1724 254.2deg)`. The colors look the same. It only matters if you read a variable from JavaScript and expect a hex string, see [Deprecated JavaScript helpers](#deprecated-javascript-helpers) below.

Every browser that could run Tabler 1.5 supports `oklch()`, so the [minimum versions](/ui/getting-started/browser-support) don't change.

## Plugins are components now

In 1.5, a few plugins were small scripts that ran once on page load and reached for a global library. In 1.6 each of them is a proper component with the same API as the Bootstrap ones: `getInstance()`, `getOrCreateInstance()`, `dispose()`, and events with a `.bs.` suffix.

Component|Attribute|Docs
---|---|---
`tabler.Autosize`|`data-bs-toggle="autosize"`|[Autosize](/ui/plugins/autosize)
`tabler.CountUp`|`data-countup`|[Countup](/ui/plugins/countup)
`tabler.InputMask`|`data-mask`|[Input mask](/ui/plugins/input-mask)
`tabler.Sortable`|`data-sortable`|[Sortable](/ui/plugins/sortable)
`tabler.SwitchIcon`|`data-bs-toggle="switch-icon"`|[Switch icon](/ui/components/switch-icon)

Markup with data attributes keeps working as it did. Tabler still finds every element on page load and creates the component for it.

### Autosize and countUp.js are built in

Both were rewritten inside `tabler.js`, so they don't need a separate script. The old files stay in `dist/libs` until 2.0, so a page that loads them keeps working, but you can remove them:

```diff
- <script src="/dist/libs/autosize/dist/autosize.min.js"></script>
- <script src="/dist/libs/countup.js/dist/countUp.umd.js"></script>
  <script src="/dist/js/tabler.min.js"></script>
```

And from your dependencies, if you installed them for Tabler:

```sh
npm uninstall autosize countup.js
```

If you called the libraries directly for elements added later, the components do the same:

```diff
- autosize(document.getElementById('message'));
+ new tabler.Autosize(document.getElementById('message'));

- autosize.update(document.getElementById('message'));
+ tabler.Autosize.getInstance(document.getElementById('message')).update();

- new countUp.CountUp('total', 1500, { duration: 4 }).start();
+ new tabler.CountUp(document.getElementById('total'), { duration: 4 });
```

The `CountUp` component reads the target number from the element's text, like the `data-countup` attribute always did. It respects `prefers-reduced-motion` on its own, so you can drop the workaround from the 1.5 docs that removed `data-countup` for those users.

Options you passed to countUp.js in `data-countup` keep their names: `startVal`, `duration`, `decimalPlaces`, `useEasing`, `useGrouping`, `separator`, `decimal`, `prefix` and `suffix`. A number or a boolean written as a string, such as `"duration":"3"`, is still read. Anything outside that list is ignored.

### IMask and SortableJS stay external

`InputMask` and `Sortable` are thin wrappers, so you still install [IMask](/ui/plugins/input-mask) and [SortableJS](/ui/plugins/sortable) yourself and load them before `tabler.js`. Nothing changes there. What's new is that the component keeps a reference to the library instance, so you can reach it from `getInstance()` instead of keeping your own.

### Clipboard is built in

Tabler has its own [Clipboard](/ui/plugins/clipboard) component, written on top of the browser's `navigator.clipboard` API. `dist/libs/clipboard` stays in the package until 2.0, so code that uses ClipboardJS keeps working. To move over, drop the script:

```diff
- <script src="/dist/libs/clipboard/dist/clipboard.min.js"></script>
  <script src="/dist/js/tabler.min.js"></script>
```

```sh
npm uninstall clipboard
```

A copy button carries `data-bs-toggle="clipboard"` and points at its source with `data-bs-target` or `data-bs-text`, and the two states live in the button:

```diff
- <button type="button" class="btn" data-clipboard-target="#api-key">Copy</button>
+ <button type="button" class="btn" data-bs-toggle="clipboard" data-bs-target="#api-key">
+   <span class="clipboard-label">Copy</span>
+   <span class="clipboard-feedback">Copied</span>
+ </button>
```

If you created the library yourself, switch to the component and its events:

```diff
- const clipboard = new ClipboardJS('.btn-copy');
- clipboard.on('success', () => showToast('Copied'));
+ document.querySelectorAll('.btn-copy').forEach((button) => {
+   new tabler.Clipboard(button);
+   button.addEventListener('copied.bs.clipboard', () => showToast('Copied'));
+ });
```

The browser API works in secure contexts only, so on plain `http` the copy fails and `error.bs.clipboard` fires. `localhost` counts as secure.

### Datepicker replaces Litepicker

[Litepicker](https://github.com/wakirin/Litepicker) has been archived since 2023, so Tabler's own pages moved to the new [Datepicker](/ui/plugins/date-picker) plugin. Litepicker is deprecated: `dist/libs/litepicker` and its styles in `tabler-vendors.css` stay until 2.0, so a page that uses it keeps working.

Datepicker is part of `tabler.js`. It renders its calendar with [Vanilla Calendar Pro](https://vanilla-calendar.pro), which you load in place of Litepicker:

```diff
- <script src="/dist/libs/litepicker/dist/litepicker.js"></script>
+ <script src="/dist/libs/vanilla-calendar-pro/index.js"></script>
  <script src="/dist/js/tabler.min.js"></script>
```

```sh
npm uninstall litepicker
npm install vanilla-calendar-pro
```

Then replace the script that created the picker with a data attribute:

```diff
- <input class="form-control" id="date" />
- <script>
-   new Litepicker({ element: document.getElementById('date') });
- </script>
+ <input type="text" class="form-control" id="date" data-bs-toggle="datepicker" autocomplete="off" />
```

The Datepicker page has a [table that maps every Litepicker option](/ui/plugins/date-picker#migration-from-litepicker) to its new name.

### New events

Every component fires events on its element. If you used to poll or wrap the library callbacks, these are the ones to listen for:

Component|Events
---|---
`Autosize`|`resized.bs.autosize`
`Clipboard`|`copied.bs.clipboard`, `error.bs.clipboard`
`CountUp`|`start.bs.countup`, `complete.bs.countup`
`SwitchIcon`|`toggle.bs.switch-icon` before the state changes, cancelable with `event.preventDefault()`, then `change.bs.switch-icon`. Both carry the new state in `event.active`.

## Deprecated JavaScript helpers

`tabler.js` exposes a small `tabler` namespace next to the components, with `prefix`, `getColor()` and `hexToRgba()`. It was never documented, but it was easy to find in the source, so some projects picked it up for chart colors:

```js
/* works in 1.5 and 1.6 */
const color = tabler.tabler.getColor('primary', 0.5);
```

With a bundler the namespace is a named export, `import { tabler } from '@tabler/core'`, and the same applies to it.

The namespace is deprecated and goes away in 2.0. `hexToRgba()` only understands hex strings, and the palette is `oklch()` now, so `getColor()` with an opacity returns a `color-mix()` expression instead of `rgba()`. Read the variable yourself, and use `color-mix()` when you need transparency:

```js
/* 1.6 and later */
const primary = getComputedStyle(document.body).getPropertyValue('--tblr-primary').trim();
const primaryHalf = `color-mix(in oklab, ${primary} 50%, transparent)`;
```

Every place that accepts a CSS color, including canvas and most chart libraries that render to SVG, takes the `oklch()` string as it is. A library that parses colors itself and only understands hex or `rgb()` needs the value converted first. For ApexCharts you don't have to do anything, its theme reads the `--tblr-chart-*` variables since 1.5.

## Legend is a component now

In 1.5 `.legend` was a small colored dot. In 1.6 `.legend` is a whole legend item with a dot, a label and an optional value, and the dot is `.legend-dot`:

```diff
- <span class="legend bg-primary"></span>
+ <span class="legend-dot bg-primary"></span>
```

An empty `.legend` still renders as a dot, so the old markup still works. It is deprecated, so rename it when you touch that markup. See [Legend](/ui/components/legend) for the new item, the list and the interactive states, and for `.legend-lg`, `.legend-unit` and `.legend-list-divided`, which show a big value with a unit.

## Form hint is form text

Tabler had its own `.form-hint` class for the helper text under a field, while Bootstrap calls the same thing `.form-text`. 1.6 uses the Bootstrap class and keeps `.form-hint` as a deprecated alias with the same spacing as before, so the old name still works. Rename when you touch the markup anyway:

```diff
- <small class="form-hint">We'll never share your email.</small>
+ <div class="form-text">We'll never share your email.</div>
```

The three `$form-hint-*` Sass variables and `--tblr-form-hint-*` properties only apply to `.form-hint`. `.form-text` uses Bootstrap's `$form-text-margin-top`, `$form-text-font-size` and `$form-text-color`.

## Masked icons

The check mark in a checkbox, the dot in a radio, the knob of a switch, the navbar toggler and the carousel arrows used to be SVG background images with the color baked into the SVG. They are CSS masks now, painted with `background-color`. That's what lets them follow the color variables at runtime, and it's why the same checkbox looks right in every theme without a dark variant of the image.

For most projects this is invisible. It matters if you customized those icons:

- `$form-switch-bg-image`, `$form-switch-bg-image-dark`, `$form-switch-checked-bg-image`, `$form-switch-checked-bg-position` and `$form-switch-focus-bg-image` are deprecated and no longer change the switch. The knob is a plain circle drawn with CSS. Its color comes from `$form-switch-color`, its size from `--tblr-form-switch-knob-size`.
- `$form-check-input-checked-bg-image-dark` is deprecated, because one image now works for both modes. The icon color is `$form-check-input-checked-color`, or `--tblr-form-check-icon-color` at runtime.
- `$navbar-light-toggler-icon-bg` and `$navbar-dark-toggler-icon-bg` are deprecated in favor of `$navbar-toggler-icon-bg`. The color comes from `--tblr-navbar-toggler-icon-color`.
- An image set at runtime through `--tblr-form-check-bg-image` or `--tblr-form-switch-bg` is still painted, under the new icon. Both can show, so move to the color variables when you can.

If you replaced one of the SVGs with your own, keep the shape but drop the `fill` and `stroke` colors from it. The mask only looks at the alpha channel, so any color inside the SVG is ignored.

## The focus ring is an outline

In 1.5 the focus indicator was a `box-shadow`, a solid 2px ring with a soft `0.25rem` halo around it. In 1.6 it's an `outline`, the way Bootstrap 6 draws it. Every component uses the same three variables:

```css
:root {
  --tblr-focus-ring-width: 2px;
  --tblr-focus-ring-offset: 2px;
  --tblr-focus-ring-color: /* primary mixed with the page background */;
}
```

The color is `--tblr-primary` mixed with `--tblr-body-bg`, at `--tblr-focus-ring-opacity` (`0.5`) in light mode and `--tblr-focus-ring-opacity-dark` (`0.75`) in dark mode. It follows `--tblr-primary`, so a recolored theme gets a matching ring for free.

The per-component shadow variables are deprecated. A shadow you set through one of them is still drawn, next to the outline. To restyle the ring itself, set the ring variables on the component:

```diff
  .btn {
-   --tblr-btn-focus-box-shadow: 0 0 0 3px #f11d46;
+   --tblr-focus-ring-width: 3px;
+   --tblr-focus-ring-color: #f11d46;
  }
```

The same goes for `--tblr-pagination-focus-box-shadow`, `--tblr-accordion-btn-focus-box-shadow`, `--tblr-btn-close-focus-shadow`, and for `--tblr-focus-ring-x`, `--tblr-focus-ring-y` and `--tblr-focus-ring-blur` on the `.focus-ring` helper.

Form controls draw the ring over their border with `--tblr-focus-ring-offset: -1px`. Buttons and everything else draw it `2px` outside.

If you write your own components, the `focus-ring()` mixin gives them the same ring. Pass `true` to draw it over the border, and a color as the second argument to override it:

```scss
.my-control:focus-visible {
  @include focus-ring(true);
}
```

`focus-ring($show-border: true)` from 1.5 still compiles and means the same thing.

The `.focus-ring` helper is fixed along the way. It now shows on `:focus-visible` instead of `:focus`, so a mouse click no longer draws it.

## Stricter TypeScript types

The Bootstrap component port is compiled with strict TypeScript, and every component's options are a typed `ComponentConfig` instead of a bag of `unknown`. The constructor takes `Partial<ComponentConfig>`, so you can still pass a subset of the options, and unknown keys are still accepted. What the compiler rejects now is a wrong value type:

```ts
import { Modal } from '@tabler/core';

// 1.5: compiles. 1.6: `backdrop` is `boolean | 'static'`.
new Modal(element, { backdrop: 'yes' });

// 1.6
new Modal(element, { backdrop: 'static' });
```

`Modal.Default` and `Modal.DefaultType` are typed the same way, and `getInstance()` returns `null` when there is no instance yet, so narrow it before calling a method:

```ts
Modal.getInstance(element)?.hide();
```

Nothing changes at runtime. JavaScript projects and projects that use the data attributes are not affected.

## Sass changes

Only relevant if you compile `scss/tabler.scss` yourself.

### Deprecated variables

These still exist, so `@use … with (…)` and your own code that reads them keep compiling. They live in `scss/_variables-deprecated.scss` and are removed in 2.0.

Variable|What to use instead
---|---
`$theme-colors-rgb`|Nothing. Use `color-mix()` on the color itself.
`$form-hint-margin-top`, `$form-hint-label-offset`, `$form-hint-control-margin-top`|`$form-text-margin-top` and friends. The old ones still style `.form-hint`.
`$form-switch-bg-image`, `$form-switch-bg-image-dark`, `$form-switch-checked-bg-image`, `$form-switch-checked-bg-position`, `$form-switch-focus-bg-image`, `$form-switch-color-dark`|See [Masked icons](#masked-icons). No effect any more.
`$form-check-input-checked-bg-image-dark`|See [Masked icons](#masked-icons). No effect any more.
`$navbar-light-toggler-icon-bg`, `$navbar-dark-toggler-icon-bg`|`$navbar-toggler-icon-bg`. No effect any more.
`$lighten-dark`|`$active-bg`, which is a `light-dark()` value and carries its own dark color, so `--tblr-active-bg` no longer reads it. Hover backgrounds use the new `$hover-bg` and `--tblr-hover-bg`. No effect any more.
`$input-btn-focus-width`|`$focus-ring-width`. A changed value still sets the ring width.
`$input-btn-focus-color`|`$focus-ring-color`. A changed value still sets the ring color.
`$btn-focus-box-shadow`, `$btn-close-focus-shadow`, `$pagination-focus-box-shadow`, `$accordion-btn-focus-box-shadow`|The ring variables. A changed value is still drawn as a shadow, next to the outline.
`$focus-ring-blur`, `$focus-ring-box-shadow`, `$input-btn-focus-color-opacity`, `$input-btn-focus-blur`, `$input-btn-focus-box-shadow`, `$input-focus-width`, `$input-focus-box-shadow`, `$form-select-focus-width`, `$form-select-focus-box-shadow`, `$form-check-input-focus-box-shadow`, `$form-range-thumb-focus-box-shadow`, `$nav-link-focus-box-shadow`, `$pagination-focus-outline`|`$focus-ring-width`, `$focus-ring-offset` and `$focus-ring-color`. See [The focus ring is an outline](#the-focus-ring-is-an-outline). No effect any more.

In `$form-validation-states` the new key is `focus-ring-color`, and it takes a color. A `focus-box-shadow` key from 1.5 is still drawn:

```diff
  'invalid': (
    'color': var(--form-invalid-color),
-   'focus-box-shadow': 0 0 0 0.25rem rgba(214, 57, 57, 0.25),
+   'focus-ring-color': focus-ring-color(var(--danger)),
  ),
```

Two defaults changed with the outline: `$focus-ring-width` went from `0.25rem` to `2px`, and `$focus-ring-opacity` from `0.25` to `0.5`.

### Deprecated functions

These still work and warn when you compile. They live in `scss/mixins/_deprecated.scss` and are removed in 2.0.

Function or mixin|What to use instead
---|---
`theme-color-lighter($color)`|`mix-color($color, #fff, 10%)`, or `mix-color-css()` for a value that follows `--tblr-*` overrides
`theme-color-darker($color)`|`shade-color($color, 10%)`, or `adjust-lightness-css(var(--primary), -6%)`
`url-svg($svg)`|`escape-svg(url("data:image/svg+xml,…"))`
`varify($list)`|Write the `var()` values by hand
`map-get-multiple()`, `map-merge-multiple()`|`map.get()` and `map.merge()` from `sass:map`
`breakpoint-prev()`, `media-breakpoint-down-than()`|`media-breakpoint-down()` with the breakpoint one step down

Two pairs of functions are new:

- `mix-color($a, $b, $weight)` and `adjust-lightness($color, $amount)` work at compile time on Sass colors and return an sRGB color, so the result can still feed `color-contrast()` or `luminance()`.
- `mix-color-css($a, $b, $weight)` and `adjust-lightness-css($color, $amount)` return a `color-mix()` or a relative `oklch()` expression, so the result follows `--tblr-*` overrides in the browser. Use these where the value is emitted as it is.

```diff
- $my-hover: theme-color-darker($primary);
+ $my-hover: adjust-lightness-css(var(--primary), -10%);
```

### Variables that turned into color-mix()

This is the one change in 1.6 that can stop a Sass build, and the one exception to "nothing breaks". 69 variables that were plain Sass colors are now `color-mix()` expressions on top of a custom property, so that they follow `--tblr-*` overrides in the browser. `$primary-bg-subtle`, for example, used to be `tint-color($primary, 80%)`, and is now `mix-color-css(var(--white), var(--primary), 80%)`. The same happened to the `*-bg-subtle`, `*-text-emphasis` and `*-border-subtle` families and their `-dark` twins, `$body-secondary-color`, `$body-tertiary-color`, `$input-focus-border-color`, the dark mode border colors, and a few navbar, dropdown and switch colors. The theme colors such as `$primary`, the grays, `$body-color`, `$body-bg` and `$link-color` are still Sass colors.

You can still override them with anything Sass accepts. But a Sass color function such as `darken()` or `rgba()` fails on their default values, because the default isn't a color, it's a string with `var()` inside. Build the value from the base color instead, with Tabler's own functions:

```diff
- $my-subtle-hover: darken($primary-bg-subtle, 5%);
+ $my-subtle-hover: shade-color(tint-color($primary, 80%), 5%);
```

### Dropping the deprecated layer

Everything on this page that is kept for older projects sits behind one flag. Once your project no longer uses any of it, turn the flag off and the CSS gets about 1.4 kB (gzip) smaller:

```scss
@use '@tabler/core/scss/tabler' with (
  $enable-deprecated: false
);
```

That is also a good test before 2.0: if the project still looks right with the flag off, the CSS side of the upgrade is done.

## Visual changes

None of these break markup, but they change how a page looks or scrolls. Worth a quick look at your screens after the upgrade.

- **The default gray is neutral.** Every gray in Tabler comes from the `--tblr-gray-50` … `--tblr-gray-950` scale. In 1.5 that scale had a slight blue tint; in 1.6 the default is `neutral`, a pure gray, so backgrounds, borders and muted text look a little different. The Sass defaults `$gray-50` … `$gray-950` changed the same way. To keep the 1.5 look, load `tabler-themes.css` and set `data-bs-theme-base="gray"` on `<html>`. A visitor who picked `gray` in the theme settings keeps it. See [Theme base colors](/ui/plugins/theme-base-colors).
- **The focus ring is a solid outline.** The soft halo around focused buttons and inputs is gone. Focus is a single 2px ring, stronger in dark mode. See [The focus ring is an outline](#the-focus-ring-is-an-outline).
- **No reserved scrollbar gutter.** 1.5 set `scrollbar-gutter: stable` on `html`, which left an empty strip on the right of the navbar on pages too short to scroll. That rule is gone. Layout shifts between short and long pages are back to the browser default, which on macOS and most mobile browsers means none.
- **Scroll chaining is contained.** Scrolling to the end of a modal body, an offcanvas body or a scrollable dropdown no longer scrolls the page behind it.
- **Native `<dialog>` gets a backdrop.** A `<dialog>` opened with `showModal()` has the same backdrop as a modal, and `.modal-blur` on it blurs the page behind.
- **Colors are computed in oklab.** Tints, shades and hover states are mixed in the `oklab` color space instead of `sRGB`. Mixed colors are a touch less muddy, mostly noticeable in the lighter `-lt` backgrounds. Solid colors are the same as before.
- **`.form-selectgroup-label`** no longer applies the icon-only margin to icons nested deeper inside the label.
- **Striped tables respect custom backgrounds.** A `<tr>` or `<td>` with `.bg-*`, `.table-*`, `.text-bg-*` or an inline `background` keeps that background inside `.table-striped` and `.table-striped-columns`. Before, the stripe painted over it.
- **`pre` is 13px.** Code blocks have their own size now, `$pre-font-size` (`0.92857143em`, 13px at the default base size), and `$markdown-pre-font-size` inside `.markdown`. In 1.5 `pre` inherited the size of its parent.
- **`.card-options` is in the flow.** In 1.5 it was `position: absolute` in the top right corner of `.card-header`. It is a regular flex item now, pushed to the end with `margin-inline-start: auto`. If your CSS positioned it or reserved space for it, remove that.
- **A disabled switch looks disabled.** A `.form-switch` that is `disabled` and off gets a filled track and a darker knob. Before, it looked the same as an enabled one.
- **Tom Select matches `.form-control`.** The control uses Tabler's input metrics in every size, so it is as tall as the inputs next to it, and it no longer grows on focus when the selected item has an avatar, a flag or a badge.
- **The accordion plus toggle rotates.** `.accordion-button-toggle-plus` used to hide the first `<path>` of the inline SVG when the item was open, which didn't work with sprite icons or icon fonts. It now rotates the whole icon a quarter turn into a close icon. If your own CSS targeted `path:first-child` in that toggle, remove it. Any icon source works, but the icon has to be a plus for the rotation to make sense.

## What is new in 1.6

Besides the changes above, 1.6 adds:

- [Datepicker](/ui/plugins/date-picker), a calendar popup or inline calendar with single, multiple and range selection, see above.
- [Legend](/ui/components/legend), a colored marker plus label for chart series, with an interactive mode that toggles series on click.
- [Signal](/ui/components/signal), a row of bars that shows a level, such as priority or signal strength.
- [Sparkline](/ui/components/sparkline), inline SVG line, bar and circle charts rendered from `data-bs-values`, with no chart library.
- [Password strength](/ui/forms/strength), a segmented meter that scores the password as the user types and fires `change.bs.strength`.
- [OTP input](/ui/forms/otp-input), grouped single-character slots for one-time codes, with masking and validation states.
- [Clipboard](/ui/plugins/clipboard), a copy button with a copied state, built on the browser API, see above.
- [Confetti](/ui/components/confetti), a shower of pieces from any button with `data-bs-toggle="confetti"`.
- A `switch-icon-loading` state for [Switch icon](/ui/components/switch-icon). Pass a promise to `event.wait()` in `toggle.bs.switch-icon` and the button shows a spinner until it settles.
- `Autosize`, `CountUp`, `InputMask`, `Sortable` and `SwitchIcon` as real components with instances, methods and events, see above.
- `data-tblr-countup` as an alias of `data-countup`.
- `.navbar-floating` for [navbars](/ui/layout/navbars) and `.offcanvas-floating` for [offcanvas](/ui/components/offcanvas), which detach the element from the edge of the screen. The theme settings `data-bs-navbar-style="floating"` and `data-bs-offcanvas-style="floating"` on `<html>` do the same for the whole page.
- `.page-section-title` and `.page-section-description` for a section heading inside the page body, between the page header and the cards.
- `.theme-dark` as a class alternative to `data-bs-theme="dark"`. The dark mode selectors match both.
- `tabler.js` no longer stops on page load when one element has an invalid `data-*` config. The error is logged and every other component is still created, so a workaround that initialized components by hand can go.
- Drag styles for [Sortable](/ui/plugins/sortable): `.sortable-ghost`, `.sortable-chosen`, and `.sortable-drag` for lists that turn on `forceFallback`.
- A billing page in the preview, with plan usage, payment method and invoices.
- The Bootstrap component port is compiled with strict TypeScript, so the type declarations in the package are tighter. Configs are typed per component, see [Stricter TypeScript types](#stricter-typescript-types).

The full list is in the [changelog](https://github.com/tabler/tabler/blob/dev/core/CHANGELOG.md).
