Releases: danpacho/tailwindest
v3.2.2
Bug Fixes 🐛
tools.rotary's compose method does not correctly handle merging behavior. It disappears original T/F property when return new instance using compose.
Now these compose tests are passed correctly.
it("should handle multiple compositions on ToggleStyler", () => {
const toggle = tw.toggle({
base: { color: "gray" },
truthy: { color: "green" },
falsy: { color: "red" },
})
const composed1 = toggle.compose({ backgroundColor: "white" })
const composed2 = composed1.compose({ padding: "10px" })
const composed3 = composed2.compose({
color: "black",
})
expect(composed1.style(true)).toEqual({
color: "green",
backgroundColor: "white",
})
expect(composed2.style(false)).toEqual({
color: "red",
backgroundColor: "white",
padding: "10px",
})
expect(composed3.style(true)).toEqual({
color: "green",
backgroundColor: "white",
padding: "10px",
})
})Full Changelog: v3.2.1...v3.2.2
v3.2.1
New Features
- [bug + feature] override variants base when
compose, add multiple class literal forclass@danpacho (#163)
Bug Fixes
- [bug + feature] override variants base when
compose, add multiple class literal forclass@danpacho (#163)
Overview
-
Fix
rotary.composefunction's base style overriding logic.const btn1 = tw.rotary({ variants: { warning: {...} }, base: { fontSize: 'text-xs' }, }) const btn2 = btn.compose({ fontSize: 'text-xl' // change base font size to xl }) const res1 = btn1.class("warning") // text-xs ... const res2 = btn2.class("warning") // text-xl ...
-
Support add
classmethod's multiple extra classes.const base = tw.style({...}) const withExtra = base.class("c1", "c2", ["c3", "c4"], "c5") // ... c1 c2 c3 c4 c5
-
Support statically typed className strings for
classmethod's extra classes.import type { Tailwind, TailwindNestGroups } from "~/tailwind.ts" export type Tailwindest = CreateTailwindest<{ tailwind: Tailwind tailwindNestGroups: TailwindNestGroups useArbitrary: true }> export type TailwindLiteral = CreateTailwindLiteral<Tailwind> export const tw = createTools<{ tailwindest: Tailwindest tailwindLiteral: TailwindLiteral useArbitrary: true // enable arbitrary strings useTypedClassLiteral: true // ✅ enable typed class literal <-- [added] >() // now, extra classes arguments are fully typed. const box = tw.style({...}).class("bg-red-100") // ✅ <-- statically typed
Full Changelog: v3.2.0...v3.2.1
v3.2.0
New Features 🚀
Bug Fixes 🐛
API Changes
createTools generic parameter
import {
createTools,
type CreateTailwindest,
type CreateTailwindLiteral,
} from "tailwindest"
import type { Tailwind, TailwindNestGroups } from "./tailwind"
export type Tailwindest = CreateTailwindest<{
tailwind: Tailwind
tailwindNestGroups: TailwindNestGroups
groupPrefix: "$" // prefix for nest groups, [optional]
useArbitrary: true // enable arbitrary values, [optional]
}>
export type TailwindLiteral = CreateTailwindLiteral<Tailwind>
export const tw = createTools<{
tailwindest: Tailwindest
tailwindLiteral: TailwindLiteral
useArbitrary: true // enable arbitrary values, [optional]
}>()From 3.2.0, generic parameter should be passed explicitly like below.
{
tailwindest: Tailwindest
tailwindLiteral: TailwindLiteral
useArbitrary: true // enable arbitrary values, [optional]
}Full Changelog: v3.1.1...v3.2.0
v3.1.1
Bug Fixes 🐛
-
[bug]
twMergedoes not matchcreatetools-mergertyping @danpacho (#151) -
Change public merger interface for more generic approach.
export type Merger<ClassList extends Array<any> = any[]> = ( ...classList: ClassList ) => string
-
Change internal
join,deflogic. Remove duplicated merging process, fix invalid argument spreading. -
Export public interface types for merging
TailwindestMerger: merger function shapeTailwindestClassList: default tailwindest's native merging target valid class lists.
-
Can inject custom merger, based on
TailwindestMergerandTailwindestClassList.const merger_1: TailwindestMerger<TailwindestClassList> = (...values) => { ... } const merger_2: TailwindestMerger<Array<string> | string> = (...values) => { ... } ...
Full Changelog: v3.1.0...v3.1.1
v3.1.0 🚀
Introducing a new API for flexible and powerful styling.
tw.def(classList, ...styleList)
const condition: boolean = true;
const container = tw.def(
// 🚀 Powered by clsx
[
"flex",
"size-fit",
"flex-col",
"items-center",
"justify-center",
"gap-y-12", // ✅ Statically typed literals
"md:flex-row md:gap-x-7", // ✅ Arbitrary strings
"lg:gap-x-24",
condition ? "p-3" : "p-1", // ✅ Conditional styling
["dark:text-white", "text-black"], // ✅ Array-based styling
],
// 🚀 Default merging behavior
{ // ✅ Record-based styling
backgroundColor: "bg-white",
dark: {
backgroundColor: "dark:bg-black",
},
},
{ // ✅ Support for infinite record styling
// Additional styles here...
}
);Key Features:
- Classname management with
clsx-like functionality. - Infinite
Tailwindestrecord styling for maximum flexibility. - Statically typed literals tailored for
tailwindcss. - Returns a simple
stringfor easy integration.
This API shines for foundational styling needs, offering a clean and intuitive way to build styles.
tw.join(...classList)
The join function now supports statically typed literals for tailwindcss, making it safer and more reliable. It also accepts any string, giving you the flexibility to pass custom strings while harnessing TypeScript’s type-checking power.
tw.mergeRecord(...recordList: Array<Style>)
- Now supports infinite style records for merging.
- Updated merging behavior: Instead of simply overriding by key (with arrays previously being concatenated), it now provides smarter, more predictable merging logic.
Note
This refined API suite offers developers a robust, type-safe, and flexible way to handle styling, blending the best of tailwindcss with TypeScript’s precision.
Here’s the polished version with your additional section about legacy code changes, integrated naturally into the documentation. I’ve refined the phrasing for clarity and professionalism while keeping the technical accuracy intact.
Legacy Code Updates Required
Warning
Please note that legacy code will need to be updated to align with these changes.
Before:
const tw = createTools<Tailwindest>();After:
const tw = createTools<{
tailwindest: TailwindCustom;
}>();I appreciate your understanding as we transition to this improved structure, which provides better type safety and consistency moving forward.
New Features 🚀
Breaking 🤯
Full Changelog: v3.0.2...v3.1.0
v3.0.2
v3.0.1
v3.0.0 🚀
v3 release
Today marks huge steps for tailwindest and TypeScript lovers.
As far as I know, there is a persistent demand for type safety in tailwindcss, and tailwindest focuses on solving that problem.
However, there have been requests to improve tailwindest for various reasons.
Thankfully, with these v3 updates, all users can now build a fully type-typed version of the tailwindcss product without any duck-typings and headaches.
1. create-tailwind-type
Now you can generate a complete TypeScript type definition for your own tailwind configuration with a single command.
npx create-tailwind-typePreviously, tailwindest provided pre-defined tailwindcss class name types by default. However, there were some major issues:
- Human Error: Because the number of tailwind class names is enormous, human error can occur.
- Customization Difficulty: The
tailwindesttype supports customization via individual fields, but it is somewhat verbose and can cause headaches. - Maintenance: Correct and perfect tailwindcss types are needed; however, when minor features are added or some classes are removed, all types must be redefined.
For these reasons, v3 addresses these issues with create-tailwind-type.
It uses:
- The internal tailwind
compiler postcssto analyze className properties
and finally generates an efficient type set by analyzing the entire className structure.
This allows you to generate your own version of a perfect tailwind type set.
Furthermore, excellent documentation is available. All the docs have been generated and analyzed through the work of @jbs-marcus, with the idea of static site data extraction. Thank you @jbs-marcus.
2. Tailwindest v3
Tailwindest offers CSS-in-JS styling solutions with a pre-defined Tailwindest type.
From now on, tailwindest no longer provides any pre-defined type set; it only supplies the styling tool logic itself.
Before v3, we used the Tailwindest type set when creating tools like this:
import { createTools, type Tailwindest } from "tailwindest"
const tw = createTools<Tailwindest>()Now, the type is entirely dependent on the user, meaning that you can customize everything generated by create-tailwind-type.
Migration Guidelines
-
Create Tailwind Types
First, you need to build your own types using a
tailwind.cssfile that includes all your customization configurations.
Important
npx create-tailwind-type -A # disable arbitrary valuesWarning
Currently, the -A option should be passed.
This command generates type definitions for each custom configuration.
-
Create Tools
After step 1, you can use the generated types to create tools.
import { createTools, type CreateTailwindest } from "tailwindest" import type { Tailwind, TailwindNestGroups } from "./tailwind" // Import generated tailwind types import { twMerge } from "tailwind-merge" export const tw = createTools< CreateTailwindest<{ tailwind: Tailwind tailwindNestGroups: TailwindNestGroups groupPrefix: "$" // prefix for nest groups, [optional] }> >({ merger: twMerge, // set tailwind-merge as merger, [optional] })
Additionally, tools like
twMerge, which serve as tailwind custom style order mergers, can be injected via configuration. Merging each style property correctly in tailwindcss can be challenging.
Added Features
-
Additional Styling Arguments for
.class()and.style()t.style({ backgroundColor: "bg-red-100" }).class("bg-red-200 flex") // returns "bg-red-200 flex" if <tailwind-merge> is injected, or "bg-red-100 bg-red-200 flex" otherwise t.style({ backgroundColor: "bg-red-100" }).style({ backgroundColor: "bg-red-200" }) // returns merged objects.
All tools can now accept additional styling arguments for convenience.
-
joinis Addedtw.join()is a wrapper forclsx, the well-known classname generation package.In issue #125, there was a request to simplify the library. The integration with
clsxwas chosen as the best option. However, strict type support forjoinis not available because it significantly slows down the TypeScript language server. If you need complete type support for the join function, please refer to tailwind-intellisense-regex-list.close #125
-
mergerOption Added tocreateToolsFrom now on,
createToolsaccepts an options argument for future purposes. Themergeroption is used to merge an array of className strings into a single string. For this purpose,tailwind-mergeis a perfect fit. If the user wants to merge class names before generating the final output, simply inject themergeroption. All classes will then be processed through the merger.
Breaking API Changes
There are two API changes:
-
For
createTools.style(stylesheet), the returnedclassandstyleare now functions.t.style(styles).class // ❌ t.style(styles).class() // ✅ t.style(styles).style // ❌ t.style(styles).style() // ✅
-
To create a
Tailwindesttype set, useCreateTailwindest.type Tailwindest = CreateTailwindest<{ tailwind: Tailwind tailwindNestGroups: TailwindNestGroups groupPrefix: "$" // prefix for nest groups, [optional] }>
The
CreateTailwindesttype accepts a generation configuration interface.interface TailwindestConfig { /** * Tailwind type */ tailwind: any /** * Tailwind nest group literal type */ tailwindNestGroups: string /** * Prefix of nest group * @default '' */ groupPrefix?: string /** * Option to enable arbitrary strings * * If enabled, all `${string}` can be used as valid style property */ useArbitrary?: true | false }
Legacy Supports
- The
Tailwindesttype will still be provided for tailwindcss v3 users.
A huge thank you to everyone using Tailwindest! Happy coding 🚀
Full Changelog: v2.3.6...v3.0.0
v2.3.6 🔮
Bug Fixes 🐛
- [fix] aspect ratio supports
arbitrary values@danpacho, @jbs-marcus (#121)
Full Changelog: v2.3.5...v2.3.6
v2.3.5 🔮
New Features 🚀
Add missing
x,ydirections foroverflowproperty for adjust proper expected behavior of multipleoverflowpropsBecause, tailwind allows us to write overflow classes like this.
<Box className="overflow-hidden overflow-x-auto overflow-y-scroll" />Now, we can write it using tailwindest via new properties, overflowX and overflowY
const box = tw.style({
overflow: "overflow-hidden",
overflowX: "overflow-x-auto",
overflowY: "overflow-y-scroll",
})
<Box className={box.class} />Credits 🔮
Thank you @jbs-marcus!
Full Changelog: v2.3.4...v2.3.5

