Tailwind CSS 33 🎨 The not-* Variant for Negation Selection
A variant applies a utility when a condition is true. The not-* variant applies a utility when a condition is false. It is the negation of a pseudo-class, and it is the tool for the styling that needs to apply to everything except a specific state or position. The not-first:mt-4 applies a top margin to every element that is not the first child. The not-hover:opacity-50 dims every element that is not hovered. The variant is the inverse of the one it negates.
This chapter covers the not-* variant in full. You will learn the syntax, the pseudo-classes it can negate, the difference from the :not() pseudo-class in plain CSS, and the patterns that use negation for spacing, borders, and state styling.
Key point: The not-* variant applies a utility when the negated condition is false. not-first:mt-4 is equivalent to [&:not(:first-child)]:mt-4. The variant is the Tailwind shorthand for the :not() pseudo-class, and it composes with the other variants the same way. It is available in Tailwind v3.2 and later, with the full support in v4.
Why the not-* variant matters
The inverse problem. The structural variants apply when the element is the first, the last, the odd, or the even. Sometimes the styling needs the inverse: everything except the first, everything except the last. The not-* variant provides the inverse without the arbitrary [&:not(...)] syntax.
The readability problem. The [&:not(:first-child)]:mt-4 arbitrary variant works, but it is verbose. The not-first:mt-4 is shorter and clearer. The intent is visible in the class name.
The spacing problem. A list with a top margin on every item has an extra margin above the first. The not-first:mt-4 applies the margin to every item except the first, which is the correct spacing. The first:mt-0 achieves the same result by applying a margin to all and removing it from the first. The two patterns are equivalent; the not-* variant is the more direct expression.
The border problem. A list with a bottom border on every item has a redundant border after the last. The not-last:border-b applies the border to every item except the last. The last:border-b-0 achieves the same result with a removal.
The state problem. An element that is hovered should change its appearance. The elements that are not hovered should remain in their default state. The not-hover: variant applies the default styling to the non-hovered elements, which is the inverse of hover:.
The composition problem. The not-* variant composes with the other variants. md:not-first:mt-4 applies the negation on medium screens and up. dark:not-hover:opacity-50 applies the negation in dark mode. The variant system handles the composition.
a. The not-* syntax and the pseudo-classes it negates
The not-* variant takes the name of a pseudo-class variant and negates it.
<div class="not-first:mt-4">Item</div>
The not-first: applies mt-4 when the element is not the first child. It is equivalent to [&:not(:first-child)]:mt-4.
The variant negates the structural variants and the state variants.
| Negated Variant | Applies When |
|---|---|
not-first: | Not the first child |
not-last: | Not the last child |
not-only: | Not the only child |
not-odd: | Not odd (even) |
not-even: | Not even (odd) |
not-empty: | Not empty |
not-hover: | Not hovered |
not-focus: | Not focused |
not-disabled: | Not disabled |
not-checked: | Not checked |
not-required: | Not required |
not-invalid: | Not invalid |
The not-first: is the most common. The not-last: is the second. The not-hover: and not-focus: are used for the default states that should apply when the element is not in the interactive state.
<ul>
<li class="not-first:border-t">Item 1</li>
<li class="not-first:border-t">Item 2</li>
<li class="not-first:border-t">Item 3</li>
</ul>
The first item has no top border. The other items have a top border. The result is a separator between the items, with no separator above the first.
The not-last: is the inverse.
<ul>
<li class="not-last:border-b">Item 1</li>
<li class="not-last:border-b">Item 2</li>
<li class="not-last:border-b">Item 3</li>
</ul>
The last item has no bottom border. The other items have a bottom border. The result is a separator between the items, with no separator below the last.
The not-* variant can negate the state variants.
<button class="bg-gray-100 not-hover:bg-white hover:bg-blue-500">
Hover me
</button>
The button has a white background when it is not hovered and a blue background when it is. The not-hover:bg-white is the explicit default, and the hover:bg-blue-500 is the hover state.
The not-disabled: variant applies when the element is not disabled.
<button class="not-disabled:hover:bg-blue-600 disabled:opacity-50" disabled>
Save
</button>
The button is dimmed when disabled. The not-disabled:hover:bg-blue-600 applies the hover state only when the button is not disabled. A disabled button does not respond to hover.
The not-* variant can negate the -of-type variants.
<div>
<h1>Title</h1>
<p class="not-first-of-type:mt-4">Para 1</p>
<p class="not-first-of-type:mt-4">Para 2</p>
</div>
The first <p> has no top margin. The second <p> has a top margin. The <h1> is ignored.
The not-* variant can negate the empty: variant.
<div class="not-empty:p-4">Content</div>
The <div> has padding when it is not empty. An empty <div> has no padding.
b. The not-* variant vs the :not() pseudo-class
The not-* variant is the Tailwind shorthand for the CSS :not() pseudo-class. The two are equivalent.
/* CSS */
.item:not(:first-child) {
margin-top: 1rem;
}
<!-- Tailwind -->
<div class="not-first:mt-4">Item</div>
The Tailwind class generates the CSS with the :not(:first-child) selector. The result is the same.
The :not() pseudo-class in CSS accepts a selector list in modern browsers. The Tailwind not-* variant negates a single variant at a time. The two cannot be nested directly.
/* CSS: not first and not last */
.item:not(:first-child):not(:last-child) {
margin: 1rem 0;
}
<!-- Tailwind: two not- variants -->
<div class="not-first:not-last:my-4">Item</div>
The not-first:not-last: applies the margin to the elements that are neither first nor last. The two not-* variants compose.
The not-* variant is available in Tailwind v3.2 and later. The arbitrary variant [&:not(...)]: is the alternative for versions that do not have the not-* variant.
<div class="[&:not(:first-child)]:mt-4">Item</div>
The arbitrary variant works in any version that supports arbitrary variants (v3.0+). The not-* variant is the shorthand.
The not-* variant is limited to the variants that Tailwind knows. The arbitrary variant accepts any selector.
<div class="[&:not(.special)]:mt-4">Item</div>
The arbitrary variant negates a class selector. The not-* variant does not have a class negation because Tailwind’s variants are pseudo-classes.
The two are complementary. The not-* variant is the shorthand for the common cases. The arbitrary variant is the escape hatch for the rest.
c. The patterns
Spacing without the first.
<div>
<p class="not-first:mt-4">Paragraph 1</p>
<p class="not-first:mt-4">Paragraph 2</p>
<p class="not-first:mt-4">Paragraph 3</p>
</div>
The spacing is between the paragraphs, not above the first. The not-first:mt-4 is the direct expression of the intent.
Border without the last.
<ul>
<li class="not-last:border-b">Item 1</li>
<li class="not-last:border-b">Item 2</li>
<li class="not-last:border-b">Item 3</li>
</ul>
The separator is between the items, not below the last.
Both first and last.
<ul>
<li class="not-first:not-last:border-t border-b">Item 1</li>
<li class="not-first:not-last:border-t border-b">Item 2</li>
<li class="not-first:not-last:border-t border-b">Item 3</li>
</ul>
The borders are on the middle items. The first and last have no borders.
Default state without hover.
<button class="not-hover:opacity-75 hover:opacity-100">
Hover me
</button>
The button is at 75% opacity when not hovered and 100% when hovered.
Hover only when not disabled.
<button class="not-disabled:hover:bg-blue-600 disabled:opacity-50" disabled>
Save
</button>
The hover state applies only when the button is not disabled. The disabled state is dimmed.
Default styling without focus.
<input class="not-focus:border-gray-300 focus:border-blue-500" />
The input has a gray border when not focused and a blue border when focused.
Required without a value.
<input class="not-placeholder-shown:border-blue-500" />
The input has a blue border when the placeholder is not shown (the input has a value).
Alternating without the first.
<li class="not-first:even:bg-gray-50">Item</li>
The even items after the first have a gray background. The combination of not-first: and even: is unusual but valid.
The not-* variant is the tool for the styling that applies to everything except a specific state or position. The pattern is common: the spacing between elements, the borders between elements, the default state that is not the interactive state.
Complete Example Session
<!-- ============================================ -->
<!-- PART 1: NOT-FIRST SPACING -->
<!-- ============================================ -->
<div>
<p class="not-first:mt-4">Paragraph 1</p>
<p class="not-first:mt-4">Paragraph 2</p>
<p class="not-first:mt-4">Paragraph 3</p>
</div>
<!-- ============================================ -->
<!-- PART 2: NOT-LAST BORDER -->
<!-- ============================================ -->
<ul>
<li class="not-last:border-b">Item 1</li>
<li class="not-last:border-b">Item 2</li>
<li class="not-last:border-b">Item 3</li>
</ul>
<!-- ============================================ -->
<!-- PART 3: NOT-FIRST BORDER-TOP -->
<!-- ============================================ -->
<ul>
<li class="not-first:border-t">Item 1</li>
<li class="not-first:border-t">Item 2</li>
<li class="not-first:border-t">Item 3</li>
</ul>
<!-- ============================================ -->
<!-- PART 4: NOT-FIRST AND NOT-LAST -->
<!-- ============================================ -->
<ul>
<li class="not-first:not-last:border-t border-b">Item 1</li>
<li class="not-first:not-last:border-t border-b">Item 2</li>
<li class="not-first:not-last:border-t border-b">Item 3</li>
</ul>
<!-- ============================================ -->
<!-- PART 5: NOT-HOVER -->
<!-- ============================================ -->
<button class="not-hover:opacity-75 hover:opacity-100">
Hover me
</button>
<!-- ============================================ -->
<!-- PART 6: NOT-DISABLED HOVER -->
<!-- ============================================ -->
<button class="not-disabled:hover:bg-blue-600 disabled:opacity-50" disabled>
Save
</button>
<!-- ============================================ -->
<!-- PART 7: NOT-FOCUS -->
<!-- ============================================ -->
<input class="not-focus:border-gray-300 focus:border-blue-500" />
<!-- ============================================ -->
<!-- PART 8: NOT-FIRST-OF-TYPE -->
<!-- ============================================ -->
<div>
<h1>Title</h1>
<p class="not-first-of-type:mt-4">Para 1</p>
<p class="not-first-of-type:mt-4">Para 2</p>
</div>
<!-- ============================================ -->
<!-- PART 9: NOT-EMPTY -->
<!-- ============================================ -->
<div class="not-empty:p-4">Content</div>
<!-- ============================================ -->
<!-- PART 10: ARBITRARY NOT WITH CLASS -->
<!-- ============================================ -->
<div class="[&:not(.special)]:mt-4">Item</div>
The ten parts covered not-first spacing, not-last border, not-first border-top, not-first:not-last, not-hover, not-disabled:hover, not-focus, not-first-of-type, not-empty, and the arbitrary not with a class selector.
Quick Reference
Not Variants
| Variant | Applies When |
|---|---|
not-first: | Not the first child |
not-last: | Not the last child |
not-only: | Not the only child |
not-odd: | Even |
not-even: | Odd |
not-empty: | Not empty |
not-hover: | Not hovered |
not-focus: | Not focused |
not-disabled: | Not disabled |
not-checked: | Not checked |
not-required: | Not required |
not-invalid: | Not invalid |
not-first-of-type: | Not the first of its type |
not-last-of-type: | Not the last of its type |
Composition
| Combination | Applies When |
|---|---|
not-first:not-last: | Neither first nor last |
md:not-first: | Medium screens and not first |
dark:not-hover: | Dark mode and not hovered |
not-disabled:hover: | Not disabled and hovered |
CSS Equivalence
| Tailwind | CSS |
|---|---|
not-first:mt-4 | :not(:first-child) { margin-top: 1rem } |
not-last:border-b | :not(:last-child) { border-bottom: 1px } |
not-hover:opacity-75 | :not(:hover) { opacity: 0.75 } |
not-empty:p-4 | :not(:empty) { padding: 1rem } |
Arbitrary Variant
| Syntax | Matches |
|---|---|
[&:not(:first-child)]: | Not first child |
[&:not(.special)]: | Not the class special |
[&:not([disabled])]: | Not disabled attribute |
Best Practices
✅ Do This:
<!-- Use not-first: for spacing -->
<p class="not-first:mt-4">Paragraph</p> <!-- ✅ -->
<!-- Use not-last: for borders -->
<li class="not-last:border-b">Item</li> <!-- ✅ -->
<!-- Use not-disabled: for hover on enabled elements -->
<button class="not-disabled:hover:bg-blue-600">Save</button> <!-- ✅ -->
<!-- Use not-hover: for the default state -->
<button class="not-hover:opacity-75 hover:opacity-100">Hover</button> <!-- ✅ -->
<!-- Combine not- variants -->
<li class="not-first:not-last:my-4">Middle</li> <!-- ✅ -->
<!-- Use the arbitrary variant for class negation -->
<div class="[&:not(.special)]:mt-4">Item</div> <!-- ✅ -->
❌ Don’t Do This:
<!-- Don't use not-first: when first:mt-0 is simpler -->
<p class="mt-4 not-first:mt-4"> <!-- redundant --> <!-- ⚠️ -->
<!-- Don't expect not- to negate a class -->
<div class="not-special:mt-4"> <!-- not a variant --> <!-- ❌ -->
<!-- Don't forget that not- composes left to right -->
<button class="hover:not-disabled:bg-blue-600"> <!-- wrong order --> <!-- ⚠️ -->
<!-- Don't use not-hover: without a hover: state -->
<button class="not-hover:opacity-75">No hover state</button> <!-- ⚠️ -->
<!-- Don't nest not- in ways that contradict -->
<div class="not-first:not-first:mt-4"> <!-- no effect --> <!-- ❌ -->
<!-- Don't use not- for the empty state when empty: is clearer -->
<div class="not-empty:hidden"> <!-- inverted logic --> <!-- ⚠️ -->
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Not-first applies to all | Used without a base style | Combine with base |
| Not-last border missing | The variant is on the element | Apply to all items |
| Not-hover no effect | No hover state defined | Add hover: |
| Class negation fails | not- is pseudo-class only | Use arbitrary variant |
| Order matters | Variants compose left to right | Check the order |
| Not-empty inverted | Wrong direction | Use empty: instead |
Real-World Examples
1. List Spacing
<div>
<p class="not-first:mt-4">First paragraph</p>
<p class="not-first:mt-4">Second paragraph</p>
</div>
2. List Borders
<ul>
<li class="not-last:border-b">Item 1</li>
<li class="not-last:border-b">Item 2</li>
</ul>
3. Hover Default
<button class="not-hover:opacity-75 hover:opacity-100">Hover</button>
4. Enabled Hover
<button class="not-disabled:hover:bg-blue-600 disabled:opacity-50">Save</button>
5. Focus Default
<input class="not-focus:border-gray-300 focus:border-blue-500" />
6. Not First and Last
<li class="not-first:not-last:my-4">Middle item</li>
7. Not First of Type
<p class="not-first-of-type:mt-4">Paragraph</p>
8. Not Empty Padding
<div class="not-empty:p-4">Content</div>
9. Arbitrary Class Negation
<div class="[&:not(.special)]:mt-4">Item</div>
10. Responsive Not-First
<p class="md:not-first:mt-4">Paragraph</p>
Visual
not-first vs first
┌─────────────────────────────────────────────────────────────┐
│ first:mt-0 │
│ All items get mt-4, the first gets mt-0. │
│ │
│ Item 1 (mt-0) │
│ Item 2 (mt-4) │
│ Item 3 (mt-4) │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ not-first:mt-4 │
│ Only the items that are not first get mt-4. │
│ │
│ Item 1 (no margin) │
│ Item 2 (mt-4) │
│ Item 3 (mt-4) │
│ │
│ The two produce the same result. │
│ │
└─────────────────────────────────────────────────────────────┘
not-last Border
┌─────────────────────────────────────────────────────────────┐
│ not-last:border-b │
│ │
│ Item 1 │
│ ───────────── │
│ Item 2 │
│ ───────────── │
│ Item 3 │
│ │
│ The border is between the items, not below the last. │
│ │
└─────────────────────────────────────────────────────────────┘
not-hover Default
┌─────────────────────────────────────────────────────────────┐
│ WITHOUT not-hover: │
│ │
│ Button: no background by default │
│ Hover: bg-blue-500 │
│ │
│ The default state is unstyled. │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ WITH not-hover:bg-white │
│ │
│ Button: bg-white by default │
│ Hover: bg-blue-500 │
│ │
│ The default state is explicit. │
│ │
└─────────────────────────────────────────────────────────────┘
Composition
┌─────────────────────────────────────────────────────────────┐
│ not-first:not-last:my-4 │
│ │
│ Item 1 (first) no margin │
│ Item 2 (middle) my-4 │
│ Item 3 (middle) my-4 │
│ Item 4 (last) no margin │
│ │
│ The margin is on the middle items only. │
│ │
└─────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| Variant | not-* |
| Purpose | Apply when the negated condition is false |
| Equivalent | [&:not(...)]: |
| Common | not-first:, not-last:, not-hover: |
| Composition | not-first:not-last: |
| CSS | :not(:first-child) |
| Version | Tailwind v3.2+ |
| Arbitrary | [&:not(...)]: for class negation |
Key takeaways:
- The
not-*variant applies a utility when the negated condition is false.not-first:mt-4applies the margin to every element that is not the first child. It is the inverse of thefirst:variant. - The
not-*variant is the shorthand for the:not()pseudo-class.not-first:mt-4generates the same CSS as[&:not(:first-child)]:mt-4. The shorthand is clearer and shorter. - The
not-*variant composes with other variants.not-first:not-last:my-4applies the margin to the elements that are neither first nor last.md:not-first:mt-4applies the negation on medium screens and up. - The
not-*variant negates pseudo-class variants, not classes. Thenot-special:syntax is not a variant. For class negation, the arbitrary variant[&:not(.special)]:is the syntax. - The
not-*and the positive variant produce the same result in different ways.first:mt-0applies a margin to all and removes it from the first.not-first:mt-4applies the margin only to the non-first. The two are equivalent; the choice is a matter of expression. - The
not-disabled:hover:pattern is common. It applies the hover state only when the element is not disabled. A disabled button should not respond to hover.
Remember: The not-* variant is the negation of the pseudo-class variants. It applies a utility when the condition is false, and it is the direct expression of “everything except this.” Use it for spacing between elements, borders between elements, and default states that are not the interactive state. Combine it with the other variants, and remember that the arbitrary variant is the escape hatch for the cases the not-* variant does not cover. The negation is the same logic as the positive variant, inverted, and the intent is visible in the class name.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!