A PostCSS plugin that transforms any two‑argument clamp()
call into a fully fluid value, seamlessly integrating with Tailwind CSS utilities. Made for Tailwind v4.
Instead of the standard three-value clamp(min, preferred, max)
, you supply just a minimum and maximum:
<div class="text-[clamp(16px,50px)]"></div>
This will generate the following CSS:
.text-\[clamp\(16px\,50px\)\] {
font-size: clamp(1rem, calc(1rem + 0.0379 * (100vw - 40rem)), 3.125rem);
}
The supplied values are used to generate the expression inside the clamp()
function, where the fluid transformation is calculated using Tailwind's smallest and largest breakpoints.
Install the plugin from npm:
npm install -D clampwind
Add the plugin to your postcss.config.js
file:
// postcss.config.mjs
import tailwindcss from "@tailwindcss/postcss"
import clampwind from "clampwind"
export default {
plugins: [
tailwindcss(),
clampwind(),
]
}
If you are using CommonJS-based build tools like Webpack, you will need to use the require
syntax and add .default
to the import.
// postcss.config.js
module.exports = {
plugins: {
require("@tailwindcss/postcss"),
require('clampwind').default
}
};
If you are using Vite, you are probably using Tailwind with @tailwindcss/vite
. You need to import the plugin and use it in your postcss.config.js
file.
// postcss.config.js
import clampwind from 'clampwind';
export default {
plugins: [
clampwind()
]
};
Allow clamped values to use either px or rem interchangeably.
<div class="text-[clamp(1rem,50px)]"></div>
Use the native Tailwind syntax to clamp values within a specific range by using breakpoint modifiers.
<div class="md:max-lg:text-[clamp(16px,50px)]"></div>
If no unit is specified, default to your theme’s --spacing
scale.
<div class="text-[clamp(16,50)]"></div>
Clamp using Tailwind’s predefined size tokens.
<div class="text-[clamp(var(--text-sm),50px)]"></div>
Clamp using CSS custom properties.
<div class="text-[clamp(var(--custom-value),50px)]"></div>
Clamp values based on container query breakpoints.
<div class="@md:text-[clamp(16px,50px)]"></div>
Support clamped ranges that shrink or go below zero.
<div class="text-[clamp(50px,16px)]"></div>
Output validation errors as CSS comments for easy debugging.
.text-\[clamp\(16%\,50px\)\] {
font-size: clamp(16%,50px); /* Invalid clamp() values */
}
To use this plugin you need to use the clamp()
function but with only two arguments, the first one is the minimum value and the second one is the maximum value.
Write the Tailwind utility you want to make fluid, without any breakpoint modifier, for example:
<div class="text-[clamp(16px,50px)]"></div>
This will use Tailwind default largest and smallest breakpoint.
.text-\[clamp\(16px\,50px\)\] {
font-size: clamp(1rem, calc(...) , 3.125rem);
}
Simply add regular Tailwind breakpoint modifiers to the utility, for example:
<div class="md:max-lg:text-[clamp(16px,50px)]"></div>
To clamp the CSS property between the two breakpoints you need to use the max-
modifier, in this case the CSS property will be clamped between the md
and lg
breakpoints.
This will generate the following css:
.md\:max-lg\:text-\[clamp\(16px\,50px\)\] {
@media (width >= 48rem) { /* >= 768px */
@media (width < 64rem) { /* < 1024px */
font-size: clamp(1rem, calc(...), 3.125rem);
}
}
}
If you want to define a clamp value from a single breakpoint, clampwind will automatically generate the calculation from the defined breakpoint to the smallest or largest breakpoint depending on the direction, for example:
<div class="md:text-[clamp(16px,50px)]"></div>
This will generate the following css:
.md\:text-\[clamp\(16px\,50px\)\] {
@media (width >= 48rem) { /* >= 768px */
font-size: clamp(1rem, calc(...), 3.125rem);
}
}
Or if you use the max-
modifier:
.max-md\:text-\[clamp\(16px\,50px\)\] {
@media (width < 48rem) { /* < 768px */
font-size: clamp(1rem, calc(...), 3.125rem);
}
}
With Tailwind v4 it's really easy to use one-time custom breakpoints, and this plugin will automatically detect them and use them to clamp the CSS property.
<div class="min-[1000px]:max-xl:text-[clamp(16px,50px)]"></div>
This will generate the following css:
.min-\[1000px\]\:max-xl\:text-\[clamp\(16px\,50px\)\] {
@media (width >= 1000px) { /* >= 1000px */
@media (width < 64rem) { /* < 1600px */
font-size: clamp(1rem, calc(...), 3.125rem);
}
}
}
A quick way to define two clamped values is to use the Tailwind spacing scale values, for example:
<div class="text-[clamp(16,50)]"></div>
The bare values size depends on the theme --spacing
size, so if you have have it set to 1px
it will generate the following css:
.text-\[clamp\(16\,50\)\] {
font-size: clamp(1rem, calc(...), 3.125rem);
}
You can also use custom properties in your clamped values, for example like this:
<div class="text-[clamp(var(--text-sm),50px)]"></div>
or like this:
<div class="text-[clamp(--text-sm,--text-lg)]"></div>
But this won't work when using two custom properties directly in the CSS with @apply
, so you need to use the var()
function instead.
.h2 {
@apply text-[clamp(var(--text-sm),var(--text-lg))];
}
Clampwind supports container queries, just by using the normal Tailwind container query syntax, for example:
<div class="@md:text-[clamp(16px,50px)]"></div>
This will generate the following css:
.@md\:text-\[clamp\(16px\,50px\)\] {
@container (width >= 28rem) { /* >= 448px */
font-size: clamp(1rem, calc(...), 3.125rem);
}
}
Tailwind v4 introduced the new CSS-based configuration and clampwind embraces it.
To add new breakpoints in Tailwind v4 you normally define them inside the @theme
directive.
But Tailwind by default, will not output in your CSS any custom properties that are not referenced in your CSS, for this reason you should use the @theme static
directive instead of @theme
to create custom breakpoints.
@theme static {
--breakpoint-4xl: 1600px;
}
You can use any custom properties in your clamped values, for example:
<div class="text-[clamp(--custom-value,50px)]"></div>
You just need to make sure that the custom property is defined in your :root
selector.
:root {
--custom-value: 16px;
}
If you are using pixel values in your clamped values, clampwind will automatically convert them to rem. For the conversion it scans your generated css and if you have set pixel values for the root font-size
or for your --text-base
custom property in your :root
selector, it will use that value to convert the pixel values to rem values. If you haven't set a font-size in your :root
selector, it will use the default value of 16px.
:root {
font-size: 18px; /* 18px = 1.125rem */
}
or like this:
:root {
--text-base: 18px; /* 18px = 1.125rem */
}
This project is licensed under the Apache-2.0 license.
Copyright © 2025 Daniele De Pietri.