UniStyle › Usage › Differences from Tailwind
UniStyle borrows Tailwind's utility names and its general approach, so most Tailwind knowledge carries over. This page lists where it differs.
| Tailwind | UniStyle |
|---|---|
class="p-4 hover:bg-gray-100" | (s/c (s/p 16) (s/hover (s/bg (sc/gray 90)))) |
p-4 is 4 spacing units (1rem by default) | (s/p 4) is 4px |
p-[13px], w-[50%] | (s/p 13), (s/w "50%") |
rounded-lg, shadow-sm, text-sm | (s/rounded 8), (s/shadow "..."), (s/font-size 14) |
bg-green-600 | (s/bg (sc/green 40)) |
bg-black/50 | (s/bg (sc/neutral 0 50)) |
2xl:p-8 | (s/xxl (s/p 32)) |
dark:bg-gray-900 | a token with a dark theme value, see Themes and colors |
group/item, group-hover/item: | :item in s/c, (s/ancestor-hover :item ...) |
@apply | def-component, see Components and variants |
p-4! (!p-4 in v3) | not supported |
| tailwind-merge | built in: s/c keeps the last style for each property |
Utilities are macros that return class names, not strings you type into
class. A misspelled utility is an undefined var, which the compiler and
clj-kondo report, rather than a class that silently does nothing. Your editor
can also complete and navigate to them.
Arguments are values, not a fixed scale:
(s/p 4) is padding: 4px, not 4 of Tailwind's
spacing units. There's no --spacing scale; use constants if you want one.(s/w "50%"), (s/p "1em"). There's no
arbitrary-value syntax because every value is arbitrary.(s/bg :card-bg) is
background-color: var(--card-bg).rounded-lg, shadow-sm, or text-sm;
write the value, or define a constant or token for it.See the Utility reference for every utility and what it accepts.
Most utilities keep Tailwind's name and take the value as an argument:
(s/flex), (s/items-center), (s/gap 8), (s/opacity 50), (s/z 10),
(s/line-clamp 3). Negative values are negative arguments: -mt-4 is
(s/mt -16). These differ:
| Tailwind | UniStyle |
|---|---|
text-red-500 (color) | (s/color (sc/red 50)) |
text-sm (size) | (s/font-size 14), or (s/text 14 "20px") for size and line height |
leading-5 | (s/line-height "20px") |
break-all, break-keep | (s/word-break-all), (s/word-break-keep) |
wrap-break-word (break-words in v3) | (s/overflow-wrap-break-word) |
decoration-2 | (s/decoration-thickness 2) |
blur-sm | (s/blur 8) |
aspect-video | (s/aspect-ratio "16 / 9") |
@container | (s/container-inline-size) |
@md:flex | (s/container "(min-width: 28rem)" (s/flex)) |
border-2 border-red-500 is (s/border 2 (sc/red 50)), and
ring-2 ring-blue-500 is (s/ring 2 (sc/blue 50)). Use s/border-width or
s/border-color to change just one.grid-cols-3 is
(s/grid-cols "repeat(3, minmax(0, 1fr))").s/text needs both arguments, and a number line height is unitless:
(s/text 14 20) sets line-height: 20, so write (s/text 14 "20px").w-1/2 is (s/w "50%"),
h-screen is (s/h "100vh"), -translate-x-1/2 is (s/translate-x "-50%").rounded-full is (s/rounded 9999),
rounded-lg is (s/rounded 8), shadow-sm is a (s/shadow "...") string.s/transition needs a value. Bare transition is closest to
(s/transition-colors) or (s/transition-all).| Tailwind | Instead |
|---|---|
ring-offset-2 | an outer (s/shadow "...") or (s/outline-offset 2) with s/outline |
animate-spin and other animations | def-animation |
container (centered max-width wrapper) | (s/w "100%") with (s/max-w ...) and (s/mx-auto); note that s/container is a container query modifier |
arbitrary properties [mask-type:luminance] | (s/raw {:mask-type "luminance"}) |
| Tailwind | UniStyle |
|---|---|
2xl: | (s/xxl ...) |
group/item and group-hover/item: | :item in the parent's s/c, (s/ancestor-hover :item ...) on the child |
group-data-[state=open]: | (s/group-attr= :data-state "open" ...) |
peer/name | not available; s/peer uses the single peer class |
data-[state=open]: | (s/attr= :data-state "open" ...) |
aria-[sort=ascending]: | (s/attr= :aria-sort "ascending" ...) |
arbitrary variants like [&_p]: | (s/sel "p" ...); selectors are relative to the element and can't contain & |
In Tailwind, which of two conflicting classes wins depends on their order in the
generated CSS, not in class, so libraries like tailwind-merge exist to drop
the losers. In UniStyle, s/c knows which properties each class sets and keeps
the last one:
(s/c (s/px 10) (s/py 5) (s/p 20)) ; => "p-20"
So a component can accept a class prop and append it, and the caller's styles
win. See Basics.
Tailwind prefixes each class with its variant (hover:bg-gray-100 hover:text-black). UniStyle wraps any number of utilities, and modifiers nest:
(s/hover (s/bg "#f3f4f6")
(s/color "#000"))
(s/md (s/hover (s/p 16)))
The breakpoints sm, md, lg, and xl keep Tailwind's names and default
widths; 2xl is xxl, since Clojure names can't start with a digit. They can't
be configured: use s/media for other widths, or s/container for container
queries. See Modifiers.
There's no dark: variant. Define a theme and give tokens a value for it; the
same (s/bg background) then switches with the theme, without a second class:
(s/def-theme dark)
(s/def-token background
dark (sc/neutral 10)
(sc/neutral 98))
Themes can be applied to a whole page or to a part of it. See Themes and colors.
The palette families match Tailwind's (green, neutral, sky, ...), but:
(sc/green 47) is interpolated
between Tailwind's anchor shades, so in-between shades are approximations.(sc/green 40) is the string
"oklch(62.7% 0.194 149.214)", usable anywhere a color is, including inline
styles and canvas. The palette adds no CSS variables to your stylesheet./50: palette colors take it directly,
as in (sc/neutral 0 50), and (s/alpha color 50) adds it to any other color
or CSS variable.Tailwind scans source files for class names. UniStyle generates CSS when the macros expand, so the bundle contains exactly the styles of the namespaces your build includes. Two consequences:
`bg-${color}-500` either;
UniStyle rejects any non-constant argument at compile time. For runtime
values, set a CSS variable in :style with s/var-def and read it in a
utility; see Runtime values.@source (or
content in v3), add the build hook.theme, base, components, and
variants layers; utilities are unlayered, so they override component styles.
See Cascade layers.!important. Use composition order or a layer instead.import-preflight to include Tailwind's reset;
see Base styles and preflight.us-f00e74e5. Don't rely on
generated names in tests or selectors; see
Development vs release builds.Usage
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |