Tailwind CSS filters: blur, grayscale, brightness and more
Published 8 min read
On this page
Filters in Tailwind CSS work by stacking utilities on one element. Add grayscale, blur-sm and brightness-75 to the same image and Tailwind combines them into a single CSS filter property. You don't need a separate filter class to switch them on anymore, and you can change or remove one filter with a variant like hover: without touching the others.
This guide covers every filter and backdrop-filter utility in Tailwind CSS v4, with the actual values, and a set of copy-paste recipes for images: black and white with color on hover, a dimmed hero, blurred backgrounds, a vintage look, drop shadows on transparent PNGs, dark-mode logos and frosted glass.
How filters work in Tailwind#
Every filter utility sets its own CSS variable, and all of them write the same filter declaration that reads those variables. This is the CSS that brightness-50 generates:
.brightness-50 {
--tw-brightness: brightness(50%);
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,)
var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,)
var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
}Variables that aren't set fall back to nothing, so only the filters you add take effect. Two things follow from this:
- The order is fixed: blur, brightness, contrast, grayscale, hue-rotate, invert, saturate, sepia, drop-shadow. The order of your classes in the HTML doesn't change it. If you need a different order, write the whole value yourself with
filter-[...]. - In Tailwind v2 you had to add
filterorbackdrop-filterto enable the other classes. Since v3 that is no longer needed, and in v4 those two classes only exist for backward compatibility. You can leave them out.
Filter utilities reference#
These are the filter utilities in Tailwind CSS v4 with the values from the default theme.
| Utility | What it does | Values |
|---|---|---|
blur-* | Gaussian blur | xs 4px, sm 8px, md 12px, lg 16px, xl 24px, 2xl 40px, 3xl 64px, none |
brightness-* | Darker below 100, brighter above | Any number as a percent: brightness-50 is 50%, brightness-125 is 125% |
contrast-* | Lower or raise contrast | Any number as a percent, e.g. contrast-125 |
saturate-* | Less or more color intensity | Any number as a percent, e.g. saturate-50, saturate-150 |
grayscale, grayscale-* | Remove color | grayscale is 100%, grayscale-0 turns it off, grayscale-50 is half |
sepia, sepia-* | Warm brown tone | sepia is 100%, any number as a percent |
invert, invert-* | Invert colors | invert is 100%, invert-0 turns it off |
hue-rotate-* | Shift all hues around the color wheel | Any number in degrees, e.g. hue-rotate-90, negative with -hue-rotate-30 |
drop-shadow-* | Shadow that follows the shape of the content | xs, sm, md, lg, xl, 2xl, none, plus colors |
filter-none | Remove all filters | Sets filter: none |
In v4 the number-based utilities take any number, not just the steps from the docs. brightness-73 and hue-rotate-37 both work without arbitrary value brackets. For values that aren't whole numbers or that need a unit, use brackets: blur-[2px], brightness-[0.85], or a full custom value like filter-[url(#noise)] for an SVG filter.
Blur and drop shadow names changed in v4
If you're coming from Tailwind v3, the blur and drop shadow scales shifted one step down. The names in v3 now mean something bigger, so an upgrade without renaming makes your blurs and shadows heavier.
| v3 | v4 | v4 value |
|---|---|---|
blur-sm | blur-xs | 4px |
blur | blur-sm | 8px |
drop-shadow-sm | drop-shadow-xs | 0 1px 1px, 5% black |
drop-shadow | drop-shadow-sm | 0 1px 2px, 15% black |
The bare blur and drop-shadow classes still compile in v4 with their old values, but the docs no longer list them. The upgrade tool (npx @tailwindcss/upgrade) renames these for you.
Image recipes#
Most people looking for "tailwind image filter" want one of the following. Each snippet works on its own.
Black and white image with color on hover
The classic logo wall or team page effect. grayscale removes the color, hover:grayscale-0 brings it back, and transition makes the change smooth.
<img
src="/team/anna.jpg"
alt="Anna, lead designer"
class="grayscale transition duration-300 hover:grayscale-0"
/>If the hover target is a card around the image, mark the card as a group and use group-hover:grayscale-0 on the image.
<a href="/team/anna" class="group block">
<img src="/team/anna.jpg" alt="" class="grayscale transition duration-300 group-hover:grayscale-0" />
<p class="mt-3 font-medium">Anna</p>
</a>Dimmed hero image under text
White text on a photo is hard to read. Lower the brightness of the image so the text stands out. brightness-50 works for most photos, brightness-75 for darker ones.
<section class="relative isolate overflow-hidden">
<img
src="/hero.jpg"
alt=""
class="absolute inset-0 -z-10 size-full object-cover brightness-50"
/>
<div class="px-6 py-32 text-center text-white">
<h1 class="text-5xl font-bold">Build faster</h1>
</div>
</section>A dark overlay (bg-black/50 on a separate element) gets you a similar result. Brightness keeps the image's own colors darker instead of putting a gray layer on top, and it saves you an extra element.
Blurred image background
A blurred, scaled-up copy of an image makes a soft background, for example behind album art or a product photo. The scale-110 hides the faded edges that blur creates, and overflow-hidden on the parent clips the rest.
<div class="relative overflow-hidden rounded-xl">
<img src="/cover.jpg" alt="" class="absolute inset-0 size-full scale-110 object-cover blur-2xl" />
<img src="/cover.jpg" alt="Album cover" class="relative mx-auto w-64 py-10" />
</div>The same trick works as a loading placeholder: show a tiny version of the image with blur-md and swap in the full image when it's loaded.
Sepia and vintage look
Full sepia looks heavy. A partial sepia with slightly lower saturation and a little extra contrast gives a more believable old-photo look.
<img src="/street.jpg" alt="Street in 1960s style" class="sepia-60 saturate-75 contrast-110" />Since all three combine into one filter, you can tune each value separately until it looks right.
Drop shadow on a transparent PNG or SVG
shadow-* sets box-shadow, which always draws around the rectangular box of the element. On a transparent PNG or an SVG icon that gives you a square shadow around a round shape. drop-shadow-* is a filter and follows the visible pixels instead.
<!-- Square shadow around the image box -->
<img src="/sneaker.png" alt="Sneaker" class="shadow-xl" />
<!-- Shadow that follows the shoe -->
<img src="/sneaker.png" alt="Sneaker" class="drop-shadow-xl" />In v4 you can color drop shadows with any color from the palette and set the opacity with a slash. See the full list of Tailwind CSS colors for the names.
<svg class="size-12 text-indigo-500 drop-shadow-lg drop-shadow-indigo-500/50">...</svg>
<!-- Only lower the opacity of the default black shadow -->
<img src="/sneaker.png" alt="Sneaker" class="drop-shadow-xl/25" />Drop shadows also follow text, so drop-shadow-md on a heading over a photo is a quick way to add a text shadow. Tailwind v4 also has dedicated text-shadow-* utilities for that.
Invert a logo in dark mode
A black logo disappears on a dark background. If the logo is a single color, dark:invert turns it white without a second image file.
<img src="/logo-black.svg" alt="Acme" class="h-8 dark:invert" />This only works well for black or very dark one-color logos. A colored logo turns into its opposite colors, so blue becomes orange. For those, use a separate dark logo file or an inline SVG with fill-current.
Backdrop filters and frosted glass#
Backdrop filters apply to whatever is behind an element, not to the element itself. Every filter has a backdrop- version with the same values: backdrop-blur-*, backdrop-brightness-*, backdrop-contrast-*, backdrop-grayscale, backdrop-hue-rotate-*, backdrop-invert, backdrop-saturate-* and backdrop-sepia. There's also backdrop-opacity-*, which sets the opacity of the backdrop effect, and backdrop-filter-none to remove it all.
The most common use is a frosted glass navbar that stays readable while content scrolls under it:
<header class="sticky top-0 z-50 border-b border-white/20 bg-white/30 backdrop-blur-md">
<nav class="mx-auto flex max-w-6xl items-center justify-between px-6 py-4">
...
</nav>
</header>And a glass card on top of a photo or gradient:
<div class="relative">
<img src="/mountains.jpg" alt="" class="size-full object-cover" />
<div class="absolute inset-x-6 bottom-6 rounded-2xl bg-white/20 p-6 text-white backdrop-blur-lg backdrop-saturate-150">
<p class="text-lg font-semibold">Tour du Mont Blanc</p>
</div>
</div>Two conditions have to be true for the effect to show. The element needs a translucent background, like bg-white/30 or bg-black/40. A solid bg-white covers the blurred backdrop completely. And there has to be something behind it with detail: text, an image, a gradient. Blur on top of a flat color looks exactly like that flat color.
Tailwind outputs both backdrop-filter and -webkit-backdrop-filter, so you don't need to add a prefix for Safari.
Animating filters#
The default transition class includes filter and backdrop-filter in its property list, so filter changes on hover or focus animate without extra setup. The default duration is 150ms. For images, duration-300 or duration-500 usually feels better.
<img src="/photo.jpg" alt="" class="blur-sm transition duration-500 hover:blur-none" />If you only want to animate the filter and nothing else on the element, use transition-[filter].
Blur and big brightness changes can be uncomfortable for people who prefer reduced motion. Put the transition behind motion-safe:, or turn it off with motion-reduce::
<img
src="/photo.jpg"
alt=""
class="grayscale motion-safe:transition motion-safe:duration-300 hover:grayscale-0"
/>
<!-- or the other way around -->
<img src="/photo.jpg" alt="" class="grayscale transition duration-300 hover:grayscale-0 motion-reduce:transition-none" />The hover state still changes in both cases. Only the animation goes away.
Performance and browser support#
Color filters like grayscale, sepia, brightness and invert are cheap. Blur is the expensive one, and its cost grows with both the radius and the size of the element. A blur-3xl on a full-screen background, or a backdrop-blur-xl on a sticky header that has to be redrawn on every scroll frame, can make scrolling stutter on low-end phones. Test on a real device, and pick the smallest blur that still looks right. For a static blurred background, a pre-blurred image file is cheaper than blurring in the browser.
Animating a blur is heavier than animating a color filter, because the browser recalculates the blur every frame. Keep blur animations short and on small elements.
A filter or backdrop filter other than none also creates a new stacking context and becomes the containing block for fixed children. If a fixed modal inside a blurred element suddenly scrolls with the page or ends up under other content, that's why. Move the modal outside the filtered element.
Browser support is no longer a concern. CSS filters work in all current browsers, and backdrop-filter has been supported in Chrome, Edge, Safari and Firefox for several years. Tailwind v4 itself targets Safari 16.4, Chrome 111 and Firefox 128, which all support both.
FAQ#
How do I make an image black and white in Tailwind?
Add grayscale to the <img>. For partial desaturation use a number, like grayscale-50. To bring the color back on hover, add hover:grayscale-0 and transition.
What is the difference between drop-shadow and shadow?
shadow-* uses box-shadow and draws around the rectangular box of the element, including its border radius. drop-shadow-* uses the drop-shadow() filter and follows the visible shape of the content, so it's the right one for transparent PNGs, SVG icons and text. Box shadows support inset and spread, drop shadows don't.
Why does backdrop-blur not work?
Usually the background is solid. Use a translucent one like bg-white/30 so the blurred content can show through. Also check that something with detail actually sits behind the element, and that a parent with overflow-hidden or its own background isn't covering it. On Tailwind v4, make sure you use the new names: backdrop-blur-sm is now 8px, and the old 4px value is backdrop-blur-xs.
Can I use custom filter values in Tailwind?
Yes. Number-based utilities take any number directly, like brightness-85 or hue-rotate-15. For other values use brackets, like blur-[2px]. To change the blur or drop shadow scale for your whole project, set --blur-* or --drop-shadow-* variables in an @theme block in your CSS. More details are in the Tailwind filter docs.