| |

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 VariantApplies 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

VariantApplies 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

CombinationApplies 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

TailwindCSS
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

SyntaxMatches
[&: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

PitfallWhy It HappensFix
Not-first applies to allUsed without a base styleCombine with base
Not-last border missingThe variant is on the elementApply to all items
Not-hover no effectNo hover state definedAdd hover:
Class negation failsnot- is pseudo-class onlyUse arbitrary variant
Order mattersVariants compose left to rightCheck the order
Not-empty invertedWrong directionUse 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

ItemValue
Variantnot-*
PurposeApply when the negated condition is false
Equivalent[&:not(...)]:
Commonnot-first:, not-last:, not-hover:
Compositionnot-first:not-last:
CSS:not(:first-child)
VersionTailwind v3.2+
Arbitrary[&:not(...)]: for class negation

Key takeaways:

  • The not-* variant applies a utility when the negated condition is false. not-first:mt-4 applies the margin to every element that is not the first child. It is the inverse of the first: variant.
  • The not-* variant is the shorthand for the :not() pseudo-class. not-first:mt-4 generates 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-4 applies the margin to the elements that are neither first nor last. md:not-first:mt-4 applies the negation on medium screens and up.
  • The not-* variant negates pseudo-class variants, not classes. The not-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-0 applies a margin to all and removes it from the first. not-first:mt-4 applies 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!