Tailwind `&` Selector
After noticing the & selector being used in shadcn/ui components, I decided to do some digging to try and understand how it works. Below are some of the instances the selector may come in handy.
Targeting a Child Element
A simple example is when building a reusable button component for a design system and you want to ensure that any icons placed inside the button follow a consistent style by default.
Here’s how shadcn achieves this:
import * as React from "react";
import { cn } from "@/lib/utils";
export const Button = ({
className,
...props
}: React.ComponentProps<"button">) => {
return (
<button
className={cn(
"[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0",
className
)}
{...props}
/>
);
};
What’s happening here is that all <svg> icons inside the button automatically get a default size of 16px (the Tailwind size-4 class) and have pointer events disabled. In this case, the & acts as a reference to the current element, in this example, the button itself. So when you see [&_svg]:pointer-events-none, Tailwind is essentially generating a CSS rule that targets any <svg> inside that button.
In plain CSS, it would look like this:
button svg {
pointer-events: none;
}
Targeting Sibling elements
Here’s a simple example, checking the checkbox changes the opacity of the text next to it.
Here’s the code:
const CheckboxExample = () => {
return (
<label className="...">
<input type="checkbox" className="checkbox" />
<small className="opacity-70 [.checkbox:checked+&]:opacity-100]">
Agree to terms and conditions
</small>
</label>
);
};
In this case, the selector [.checkbox:checked+&] checks if the checkbox is in a checked state and then applies styles to the element that immediately follows it , the <small> text.
Using Data attributes
I talked about data attributes in a previous article . Here’s a quick example that uses them to animate an icon inside a Radix accordion trigger:
<AccordionTrigger className="data-[state=open]:[&_.icon]:rotate-45">
<PlusIcon className="icon transition-transform duration-300" />
</AccordionTrigger>
Targeting Nested Elements
The & selector also comes in handy when you want to style nested elements. For example, say you want to target a grandchild element. You can do that easily like this:
Nested opacity change on hover
and here’s the code:
<div className="hover:[&_.wrapper_.text]:opacity-50">
<div className="wrapper">
<p className="text">Nested opacity change on hover</p>
</div>
</div>
Winding up
In summary, & gives you control over how styles are applied in relation to the current element. You can use it to target the element itself, its states (like &:hover), its children ([&_span]), siblings ([&+p]), or even complex combinations of nested selectors.