Pure TailwindMIT licensed

Brutalist Tailwind Close Button

Neo-brutalism with honest physics: a thick black border and a zero-blur shadow-[4px_4px_0_#000]; hover lifts the button with hover:-translate-1 while the shadow grows to 8px, and press slams it down with active:translate-1 active:shadow-none — transform and shadow move in opposition, so the "floor" never moves. Set in Space Grotesk and Space Mono.

Live Demo
Plain CSSTailwind v4
Try it

Untitled UI Pro: 5,000+ React + Tailwind CSS v4 components · from $349 one-time

Untitled UI React · Affiliate link

Get Untitled UI Pro

The code

<section class="tcb-27 w-full min-h-svh grid place-items-center bg-tcb27-bg px-6 py-12 font-tcb27-sans text-black" aria-label="Brutalist close button demo">
  <div class="grid w-full justify-items-center gap-8">
    <div class="w-full max-w-[22rem] border-3 border-black bg-white p-5 shadow-[8px_8px_0_#000]">
      <div class="mb-4 flex items-start justify-between gap-4">
        <span class="bg-black px-2 py-1.5 font-tcb27-mono text-xs leading-tight font-bold tracking-[0.08em] text-tcb27-paper">NOTICE №4</span>
        <button type="button" aria-label="Close notice" class="grid size-11 flex-none cursor-pointer place-items-center border-3 border-black bg-tcb27-paper shadow-[4px_4px_0_#000] transition-[translate,box-shadow] duration-100 ease-out hover:-translate-1 hover:shadow-[8px_8px_0_#000] focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-black active:translate-1 active:shadow-none motion-reduce:transition-none">
          <span aria-hidden="true" class="relative size-4.5 before:absolute before:top-1/2 before:left-1/2 before:h-1 before:w-5 before:-translate-1/2 before:rotate-45 before:bg-black after:absolute after:top-1/2 after:left-1/2 after:h-1 after:w-5 after:-translate-1/2 after:-rotate-45 after:bg-black"></span>
        </button>
      </div>
      <p class="text-[17px] leading-snug font-semibold">Your free trial ends in 3 days.</p>
      <a href="#" class="mt-5 inline-flex min-h-11 items-center border-3 border-black bg-black px-4 font-tcb27-mono text-sm font-bold text-tcb27-paper shadow-[4px_4px_0_var(--color-tcb27-paper),4px_4px_0_3px_#000] transition-[translate] duration-100 hover:-translate-0.5 focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-black active:translate-0.5">UPGRADE →</a>
    </div>
    <p aria-hidden="true" class="border-2 border-black bg-white px-3.5 py-2 font-tcb27-mono text-[11.5px]">hover:-translate-1 · active:translate-1 active:shadow-none</p>
  </div>
</section>
@import "tailwindcss";

@theme {
  --color-tcb27-bg: #efede6;
  --color-tcb27-bg: oklch(0.94 0.008 90);
  --color-tcb27-paper: #f2e33a;
  --color-tcb27-paper: oklch(0.9 0.18 100);
  --font-tcb27-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-tcb27-mono: 'Space Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
   stage is sized before the browser build compiles. */

.tcb-27 {
  width: 100%;
  min-height: 100svh;
}

Setup — do this once per project

Skip this if your project already runs Tailwind v4.

1Load Tailwind
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>

Compiles in the browser — perfect for a CodePen or a quick test, not for production.

2Add the stylesheetRequiredthe @theme block is what makes the custom utilities exist
@import "tailwindcss";

@theme {
  --color-tcb27-bg: #efede6;
  --color-tcb27-bg: oklch(0.94 0.008 90);
  --color-tcb27-paper: #f2e33a;
  --color-tcb27-paper: oklch(0.9 0.18 100);
  --font-tcb27-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-tcb27-mono: 'Space Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
   stage is sized before the browser build compiles. */

.tcb-27 {
  width: 100%;
  min-height: 100svh;
}
3Fonts used by this demooptional — skip if you have your own type stack
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400..700&family=Space+Mono:wght@400;700&display=swap">

What changed in the port

Which parts became utilities, which stayed CSS, and why.

  • transform: translate(-4px,-4px) became hover:-translate-1; every rule collapsed into state variants on one button.
  • UI upgrade from the CSS original: the notice gained a brutalist "UPGRADE →" action, so the × isn't the only way forward, and the type moved to Space Grotesk / Space Mono for the proper neo-brutalist voice.
  • UI upgrade: the focus ring offset grew to 4px so it separates from the 3px border instead of merging with it.
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS demo from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Brutalist Tailwind Close Button
Source: https://codefronts.com/components/tailwind-css-close-buttons/brutalist-stamp/

Neo-brutalism with honest physics: a thick black border and a zero-blur shadow-[4px_4px_0_#000]; hover lifts the button with hover:-translate-1 while the shadow grows to 8px, and press slams it down with active:translate-1 active:shadow-none — transform and shadow move in opposition, so the "floor" never moves. Set in Space Grotesk and Space Mono.
## HTML
```html
<section class="tcb-27 w-full min-h-svh grid place-items-center bg-tcb27-bg px-6 py-12 font-tcb27-sans text-black" aria-label="Brutalist close button demo">
  <div class="grid w-full justify-items-center gap-8">
    <div class="w-full max-w-[22rem] border-3 border-black bg-white p-5 shadow-[8px_8px_0_#000]">
      <div class="mb-4 flex items-start justify-between gap-4">
        <span class="bg-black px-2 py-1.5 font-tcb27-mono text-xs leading-tight font-bold tracking-[0.08em] text-tcb27-paper">NOTICE №4</span>
        <button type="button" aria-label="Close notice" class="grid size-11 flex-none cursor-pointer place-items-center border-3 border-black bg-tcb27-paper shadow-[4px_4px_0_#000] transition-[translate,box-shadow] duration-100 ease-out hover:-translate-1 hover:shadow-[8px_8px_0_#000] focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-black active:translate-1 active:shadow-none motion-reduce:transition-none">
          <span aria-hidden="true" class="relative size-4.5 before:absolute before:top-1/2 before:left-1/2 before:h-1 before:w-5 before:-translate-1/2 before:rotate-45 before:bg-black after:absolute after:top-1/2 after:left-1/2 after:h-1 after:w-5 after:-translate-1/2 after:-rotate-45 after:bg-black"></span>
        </button>
      </div>
      <p class="text-[17px] leading-snug font-semibold">Your free trial ends in 3 days.</p>
      <a href="#" class="mt-5 inline-flex min-h-11 items-center border-3 border-black bg-black px-4 font-tcb27-mono text-sm font-bold text-tcb27-paper shadow-[4px_4px_0_var(--color-tcb27-paper),4px_4px_0_3px_#000] transition-[translate] duration-100 hover:-translate-0.5 focus-visible:outline-3 focus-visible:outline-offset-4 focus-visible:outline-black active:translate-0.5">UPGRADE →</a>
    </div>
    <p aria-hidden="true" class="border-2 border-black bg-white px-3.5 py-2 font-tcb27-mono text-[11.5px]">hover:-translate-1 · active:translate-1 active:shadow-none</p>
  </div>
</section>
```
## CSS
```css
@import "tailwindcss";

@theme {
  --color-tcb27-bg: #efede6;
  --color-tcb27-bg: oklch(0.94 0.008 90);
  --color-tcb27-paper: #f2e33a;
  --color-tcb27-paper: oklch(0.9 0.18 100);
  --font-tcb27-sans: 'Space Grotesk', system-ui, sans-serif;
  --font-tcb27-mono: 'Space Mono', ui-monospace, monospace;
}
/* Root rule: the full-bleed contract, stated in CSS as well as in the markup's utilities, so the
   stage is sized before the browser build compiles. */

.tcb-27 {
  width: 100%;
  min-height: 100svh;
}
```

How this works

Keep the floor still. Shadow offset + translate always equals 4px, so the shadow's far corner stays fixed while the face moves:

rest:  translate 0    shadow 4px
hover: translate -4px shadow 8px
press: translate +4px shadow 0

That constant is what makes it feel like a physical key rather than a floating card.

Make it yours

  • Colour pop: swap --color-tcb27-paper for hot pink or cyan.
  • Chunkier: border-4 and 6px shadows.
  • Rounded brutalism: add rounded-lg — the shadow follows the radius.

Gotchas — read before shipping

  • -translate-1 is -0.25rem on both axes in v4; use -translate-x-1 -translate-y-1 if your spacing scale differs.
  • Pure black on yellow is 17:1 — keep the focus ring black too, offset so it doesn't merge with the border.

Browser support

ChromeSafariFirefoxEdge
111+16.4+128+111+

The floor is Tailwind v4's generated sheet.

Techniques used in this demo

Utilitiesfirst-class utility or variant

Search CodeFronts

Loading…