Fix the bugs found in the pre-1.6 review of dev (#3112)

This commit is contained in:
Paweł Kuna authored and GitHub committed 2026-09-21 18:20:16 +02:00
1 parent d9dc168665
commit 7bfeb12ab7
55 files changed
+728 -106

No files matched your search

@@ -39,9 +39,12 @@ Feature|Used for|Chrome|Firefox|Safari
`@property`|The animated gradient on cards|85|128|16.4
`:has()`|State that depends on a child, for example a selected table row or the folded sidebar|105|121|15.4
`color-mix()`|Tints, shades and translucent surfaces|111|113|16.2
Relative colors, `oklch(from …)`|The darker hover shade of every color and the dark mode borders|122|128|16.4
Opera 109 and Samsung Internet 27 are the first releases built on Chromium 123.
Safari 16.4 to 17 follow an older draft of relative colors, where math on the hue needs a `deg` unit. Tabler only changes the lightness, which works the same in every version. If you override a Tabler color with `light-dark()`, its `-darken` shade needs Safari 18.
## Unsupported browsers
Internet Explorer is not supported, and neither is any browser released before the versions above. There is no polyfill to add: the features that set the floor are CSS, so a missing one cannot be patched with JavaScript.
@@ -27,6 +27,7 @@ Load `tabler-theme.js`|Pages follow the OS color scheme now - see [Color mode](#
Use payment provider icons|Check the [removed providers](#removed-payment-providers)
Link files inside `dist/libs`|Check the [moved paths](#smaller-distlibs-folder)
Load `tabler.rtl.css`|You can drop it - plain `tabler.css` now handles RTL
Have `.text-gray-*` classes in your markup|They color the text now - see [Gray text utilities](#gray-text-utilities)
## Update the package
@@ -277,6 +278,19 @@ These changes are not breaking, but they change how a page looks. Check your scr
- **Layout**: the `margin-inline-start: calc(100vw - 100%)` hack on the root element is gone, so there is no white gap on the left when a scrollbar is present.
- **Trending**: the component uses the `arrow-up` and `arrow-down` icons instead of `trending-up` and `trending-down`.
### Gray text utilities
Tabler 1.4 had no `.text-gray-*` classes, only `.text-gray-*-fg`. A class like `.text-gray-200` in your markup did nothing, and the text kept the color of its parent. Tabler 1.5 adds `.text-gray-50` to `.text-gray-950`, so the same class now sets the color. On `.text-gray-200` that is a very light gray, which is hard to read on a white page.
Pick the shade you want to see, or remove the class:
```diff
- <p class="text-gray-200">Last updated 3 hours ago</p>
+ <p class="text-gray-600">Last updated 3 hours ago</p>
```
For muted text, `.text-secondary` follows the theme and keeps enough contrast in dark mode.
## RTL
The Sass sources use logical properties and a `--tblr-dir` multiplier, so plain `tabler.css` works in both directions. Set `dir` on the document and drop the RTL stylesheet:
@@ -7,7 +7,7 @@ order: 1
related: [/ui/getting-started/upgrade/1-5, /ui/getting-started/customize]
---
Tabler 1.6 is a much smaller step than 1.5 was. If you only load the compiled files from `dist/`, the upgrade usually takes a few minutes. There are three things that can bite you, and they all live in your own code, not in Tabler's: any `rgba(var(--tblr-*-rgb), …)` in your CSS, any call to the old `autosize()`, `countUp` or `ClipboardJS` globals, and any use of `tabler.tabler.getColor()`.
Tabler 1.6 is a much smaller step than 1.5 was. If you only load the compiled files from `dist/`, the upgrade usually takes a few minutes. There are four things that can bite you, and they all live in your own code, not in Tabler's: any `rgba(var(--tblr-*-rgb), …)` in your CSS, any call to the old `autosize()`, `countUp`, `ClipboardJS` or `Litepicker` globals, any use of `tabler.tabler.getColor()`, and any `.legend` used as a colored dot.
Projects that compile Tabler from the Sass sources should also read [Sass changes](#sass-changes).
@@ -23,6 +23,10 @@ Use `--tblr-primary-rgb` or any `--tblr-*-rgb` variable|Replace it with `color-m
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 [Litepicker is replaced by Datepicker](#litepicker-is-replaced-by-datepicker)
Use `<span class="legend">` as a colored dot|Rename to `.legend-dot` (the old markup still works), see [Legend is a component now](#legend-is-a-component-now)
Want the 1.5 grays back|Load `tabler-themes.css` and set `data-bs-theme-base="gray"`, see [The default gray is neutral](#the-default-gray-is-neutral)
Use `data-sortable`|Dragging looks different, see [Sortable drags a styled copy](#sortable-drags-a-styled-copy)
Hide `path:first-child` in `.accordion-button-toggle-plus` from your own CSS|Drop that rule, see [Visual changes](#visual-changes)
Call `tabler.tabler.getColor()` or `tabler.tabler.hexToRgba()`|Read the variable yourself, see [Removed JavaScript helpers](#removed-javascript-helpers)
Use `.form-hint`|Rename to `.form-text` (the old name still works)
@@ -100,7 +104,7 @@ 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`|[Table](/ui/components/table)
`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. What changes is the JavaScript side.
@@ -140,7 +144,16 @@ Options you passed to countUp.js in `data-countup` keep their names: `startVal`,
### IMask and SortableJS stay external
`InputMask` and `Sortable` are thin wrappers, so you still install [IMask](/ui/plugins/input-mask) and [SortableJS](/ui/components/table) 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.
`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.
#### Sortable drags a styled copy
The `Sortable` component now turns on the SortableJS `forceFallback` option. A dragged item is an HTML copy that Tabler styles with `.sortable-drag`, instead of the browser's own drag image. Turn the option off on a list to get the 1.5 behavior back:
```diff
- <ul class="list-group" data-sortable>
+ <ul class="list-group" data-sortable='{"forceFallback":false}'>
```
### Clipboard is built in
@@ -178,6 +191,35 @@ If you created the library yourself, switch to the component and its events:
The browser API works in secure contexts only, so on plain `http` the copy fails and `error.bs.clipboard` fires. `localhost` counts as secure.
### Litepicker is replaced by Datepicker
[Litepicker](https://github.com/wakirin/Litepicker) has been archived since 2023, so Tabler dropped it. The package is gone from the dependencies and from `dist/libs`, and its styles are gone from `tabler-vendors.css`. A page that loads `dist/libs/litepicker/dist/litepicker.js` gets a 404 after the upgrade.
The new [Datepicker](/ui/plugins/date-picker) plugin 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. Tabler only removed its own copy and styles, so a project that installs Litepicker on its own keeps working, but without Tabler's look.
### 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:
@@ -208,6 +250,17 @@ 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 nothing breaks today. 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.
## 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, so nothing breaks. Rename when you touch the markup anyway:
@@ -321,6 +374,22 @@ A lot of Bootstrap variables that were plain Sass colors are now `color-mix()` e
You can still override them with anything Sass accepts. Just be aware that a Sass color function such as `darken()` or `rgba()` won't work on their default values any more, because the default isn't a color, it's a string with `var()` inside.
## 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 blue tint. In 1.6 the default is `neutral`, a pure gray, so backgrounds, borders and muted text look slightly different. The Sass defaults `$gray-50` … `$gray-950` changed the same way.
The old scale ships in `tabler-themes.css` as `gray`. To keep the 1.5 look, load that stylesheet and set the base on `<html>`:
```diff
- <html>
+ <html data-bs-theme-base="gray">
<head>
<link rel="stylesheet" href="/dist/css/tabler.min.css" />
+ <link rel="stylesheet" href="/dist/css/tabler-themes.min.css" />
```
`tabler-theme.js` also treats `neutral` as the default now. A visitor who picked `gray` in the theme settings keeps it. See [Theme base colors](/ui/plugins/theme-base-colors) for the other palettes.
## 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.
@@ -338,7 +407,9 @@ None of these break markup, but they change how a page looks or scrolls. Worth a
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.
@@ -347,6 +418,8 @@ Besides the changes above, 1.6 adds:
- 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.
- Drag styles for [Sortable](/ui/plugins/sortable): `.sortable-ghost`, `.sortable-chosen` and `.sortable-drag`.
- 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.
+14
View File
@@ -31,6 +31,20 @@ The plugin itself ships in `tabler.js`. The calendar it renders comes from Vanil
<TabsPackage name="vanilla-calendar-pro" />
If you use a bundler, put the library on `window` before Tabler loads. The plugin reads `window.VanillaCalendarPro` and does nothing without it. Imports run before the rest of a file, so do it in a file of its own and import that one first:
```javascript
// vanilla-calendar-global.js
import * as VanillaCalendarPro from 'vanilla-calendar-pro'
window.VanillaCalendarPro = VanillaCalendarPro
```
```javascript
import './vanilla-calendar-global.js'
import '@tabler/core'
```
Or include it from a CDN, before `tabler.js`:
<Code lang="html" code={`<script src="${site.cdnUrl}/dist/libs/vanilla-calendar-pro/index.js"></script>`} />
+141
View File
@@ -0,0 +1,141 @@
---
title: Sortable
summary: Sortable lets users reorder the items of a list, a table or a grid by dragging them. It wraps SortableJS in a Tabler component and styles the dragged item.
description: Make lists, table rows and cards draggable with the data-sortable attribute, SortableJS options as JSON and the Sortable component.
docs-libs: [sortablejs]
added-in: '1.6.0'
related: [/ui/components/list-group, /ui/components/table]
---
import Example from '@components/Example.astro'
import TabsPackage from '@components/TabsPackage.astro'
import CodeDocs from '@components/CodeDocs.astro';
import { Code } from 'astro:components'
import { site } from '@shared/lib/site.ts'
## Overview
Use Sortable where the order is up to the user, such as a task list, table rows or dashboard cards. The component is part of `tabler.js`. The dragging itself comes from [SortableJS](https://sortablejs.github.io/Sortable/), which you load separately.
## Installation
Install the SortableJS library:
<TabsPackage name="sortablejs" />
If you use a bundler, put the library on `window` before Tabler loads. The component reads `window.Sortable` and does nothing without it. Imports run before the rest of a file, so do it in a file of its own and import that one first:
```javascript
// sortable-global.js
import Sortable from 'sortablejs'
window.Sortable = Sortable
```
```javascript
import './sortable-global.js'
import '@tabler/core'
```
Or include it from a CDN, before `tabler.js`:
<Code lang="html" code={`<script src="${site.cdnUrl}/dist/libs/sortablejs/Sortable.min.js"></script>`} />
## Usage
### Basic list
Add `data-sortable` to the parent element. Its direct children become draggable.
<Example column>
<ul class="list-group" data-sortable>
<li class="list-group-item">Design the landing page</li>
<li class="list-group-item">Write the release notes</li>
<li class="list-group-item">Review open pull requests</li>
</ul>
</Example>
### Options
Pass [SortableJS options](https://github.com/SortableJS/Sortable#options) as JSON in the attribute. This list animates the items as they move.
<Example column>
<ul class="list-group" data-sortable='{"animation":150}'>
<li class="list-group-item">First</li>
<li class="list-group-item">Second</li>
<li class="list-group-item">Third</li>
</ul>
</Example>
### Drag handle
Set `handle` to a selector to start the drag only from that element. The rest of the item stays clickable.
```html
<ul class="list-group" data-sortable='{"animation":150,"handle":".sortable-handle"}'>
<li class="list-group-item d-flex gap-2">
<span class="sortable-handle cursor-move">⋮⋮</span>
Design the landing page
</li>
</ul>
```
### Table rows
Put `data-sortable` on the `tbody` to reorder the rows of a table.
```html
<table class="table">
<tbody data-sortable='{"animation":150}'>
<tr><td>First row</td></tr>
<tr><td>Second row</td></tr>
</tbody>
</table>
```
### Drag styles
Tabler styles the classes SortableJS adds while dragging: `.sortable-ghost` marks the drop position, `.sortable-chosen` the picked item and `.sortable-drag` the copy that follows the pointer.
The component turns on the `forceFallback` option by default. SortableJS then drags an HTML copy of the item instead of the browser's drag image, so `.sortable-drag` can style it. To get the browser's drag image back, turn the option off:
```html
<ul class="list-group" data-sortable='{"forceFallback":false}'>
…
</ul>
```
## JavaScript
Tabler wraps the plugin in a `Sortable` component that works like the Bootstrap components: it is created once per element and stored on it. On page load Tabler creates one for every element with `data-sortable`. This is the code that runs:
<CodeDocs name="sortable-init" file="core/js/src/sortable.ts" />
Create the component yourself for a list added later. Options come from `data-sortable`, from the config object, or both. The object wins.
```js
const list = new tabler.Sortable(document.getElementById('tasks'), { animation: 150 });
```
Method|Description
---|---
`toArray()`|Returns the `data-id` of every item, in the current order.
`sort(order, useAnimation)`|Reorders the items to match an array of ids.
`dispose()`|Destroys the SortableJS instance and removes the component.
The `sortable` getter returns the SortableJS instance, so everything from the [SortableJS API](https://github.com/SortableJS/Sortable#methods) is available:
```js
const list = tabler.Sortable.getOrCreateInstance(document.getElementById('tasks'));
list.sortable.option('disabled', true);
```
## Accessibility
- Dragging needs a pointer. SortableJS has no keyboard support, so give keyboard users another way to change the order, such as "Move up" and "Move down" buttons.
- Use a drag handle when the items contain links or buttons, so a click on them does not start a drag.
- Save the new order only after the drop, and tell the user when saving fails.
## SCSS variables
<CodeDocs name="sortable-variables" file="core/scss/_variables.scss" />
+1 -1
View File
@@ -28,7 +28,7 @@ Or include it from a CDN. You need three files: the stylesheet, the library, and
<Code
lang="html"
code={`<link rel="stylesheet" href="${site.cdnUrl}/dist/libs/jsvectormap/dist/jsvectormap.min.css" />
code={`<link rel="stylesheet" href="${site.cdnUrl}/dist/libs/jsvectormap/dist/jsvectormap.css" />
<script src="${site.cdnUrl}/dist/libs/jsvectormap/dist/jsvectormap.min.js"></script>
<script src="${site.cdnUrl}/dist/libs/jsvectormap/dist/maps/world.js"></script>`}
/>