GODRICH
#css-animation#button#loader#transition#scroll#dashboard#ui#design-trends

Neobrutalism UI Kit: 9 Landing Sections, No Blur

A neobrutalism UI kit trades soft, blurred drop shadows for thick black borders and flat right-angle corners — and the shadows never blur, they only sit offset

Designers file this look on Dribbble and Pinterest under neo brutalism css, and a full one-page build comes first — scroll it from the top nav down to the last footer line before the nine pieces below get taken apart individually. That missing blur is the first detail worth noticing.

Open the full page

The nine pieces that page is built from sit below as their own grid, arranged in the order a first-time visitor actually meets them on the page — get their attention, look around, check the price, find a reason to trust it, feel pushed toward the button, then sign up — rather than by which pattern is trendiest. Four of the nine (hero, number badges, pricing card, and button) carry an actual gesture instead of sitting still: a rotation, a shadow that travels, a state that reacts to a click. Within the same design pillar, Mesh Gradient CSS pushes blur as far in one direction as this kit pushes it out, while Y2K Web Design keeps the loud color and swaps the flat fill for chrome.

Auto-plays · click a tile to jump to its section · all nine in one zip

01Offset-shadow hero

What moves

A solid yellow duplicate of the headline sits behind the real text and drifts in and out of register, the way a badly aligned print run doubles up.

Offset-shadow hero
Open in a new tab

01 · Offset-shadow hero — Measured area 0.671% · moving frames 10/23Original by GODRICH · SCSS and React ship in the zip · See the password

오프셋 텍스트섀도우배지 회전→0radius 0

In the code

The corner sticker badge rests at a tilt and snaps flat for a beat before tilting back again.

<div class="relative border-[3px] border-ink bg-cream p-8 shadow-brutal">
  <span class="absolute -right-3 -top-3 border-[3px] border-ink
               bg-orange px-3 py-1 text-xs font-black text-cream">NEW</span>
  <h1 class="relative font-display text-4xl font-black leading-tight">
    <span class="absolute -left-1 -top-1 -z-10 text-yellow"
          aria-hidden="true">Nothing hidden, right from the start</span>
    Nothing hidden, right from the start
  </h1>
  <button class="mt-3 rounded-full border-[3px] border-ink bg-ink
                 px-6 py-3 text-sm font-black text-cream
                 shadow-[4px_4px_0_#ffd23f]">Start now</button>
</div>

02Stamp nav

What moves

The active menu item snaps from small past full size and back, overshooting once before it settles, the way a rubber stamp comes down and bounces.

Stamp nav
Open in a new tab

02 · Stamp nav — Measured area 0.461% · moving frames 10/23Original by GODRICH · SCSS and React ship in the zip · See the password

scale 오버슈트radius 0white-space: nowrap

In the code

Every label keeps to a single line under width pressure — nothing wraps, nothing gets cut off.

<nav class="flex items-center gap-4 border-[3px] border-ink bg-ink
            px-4 py-3">
  <span class="shrink-0 whitespace-nowrap font-black text-cream">SLABKIT</span>
  <div class="flex min-w-0 flex-1 gap-2 overflow-x-auto">
    <span class="shrink-0 whitespace-nowrap border-[3px] border-cream
                 bg-orange px-3 py-1.5 text-xs font-bold text-cream">Home</span>
    <span class="shrink-0 whitespace-nowrap px-3 py-1.5 text-xs
                 font-bold text-cream/70">Features</span>
  </div>
  <button class="shrink-0 whitespace-nowrap rounded-full border-[3px]
                 border-cream bg-yellow px-4 py-2 text-xs
                 font-black text-ink">Get started</button>
</nav>

03Shadow-detach cards

What moves

Each card's hard shadow stays fixed in place while the card body itself slides up and to the left, so the gap between the two visibly opens and closes.

Shadow-detach cards
Open in a new tab

03 · Shadow-detach cards — Measured area 20.788% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · See the password

그림자 고정카드만 이동radius 0

In the code

Four cards start on a stagger, so the set breathes like a wave instead of moving as one block.

<div class="relative">
  <div class="absolute inset-0 translate-x-2 translate-y-2 bg-ink"></div>
  <div class="relative flex flex-col gap-2 border-[3px] border-ink
              bg-cream p-4">
    <span class="block h-6 w-6 bg-blue"></span>
    <p class="text-sm font-bold">Fast search</p>
  </div>
</div>

04Crooked number badges

What moves

Each square number badge rests at its own tilt, no two angles matching, and one by one straightens out for a beat before tilting back.

Crooked number badges
Open in a new tab

04 · Crooked number badges — Measured area 0.738% · moving frames 22/23Original by GODRICH · SCSS and React ship in the zip · See the password

회전 랜덤순차 정렬radius 0

In the code

Because every angle differs, the set never lines up all at once, which is what keeps it reading as alive instead of repeating.

<li class="flex items-center gap-3 border-[3px] border-ink bg-cream
           p-2 pr-5 shadow-brutal-sm">
  <span class="grid h-9 w-9 flex-none -rotate-6 place-items-center
               border-[3px] border-ink bg-blue text-xs font-black
               text-cream">01</span>
  <span class="text-sm font-bold">Quick start</span>
</li>

05Sticky-note pricing card

What moves

Only the recommended plan sits tilted, stuck on top of the tier beside it like a pasted note, while every other card stays dead level.

Sticky-note pricing card
Open in a new tab

05 · Sticky-note pricing card — Measured area 3.044% · moving frames 10/23Original by GODRICH · SCSS and React ship in the zip · See the password

rotate 고정radius 0레이어 겹침

In the code

It also breathes — a slow scale pulse while holding that tilt — so the pick reads as chosen without a comparison table doing any of the work.

<div class="relative -ml-2 flex-[1.1] -rotate-3 border-[3px]
            border-ink bg-yellow p-6 shadow-brutal">
  <span class="absolute -top-3 left-3 border-[3px] border-ink
               bg-blue px-3 py-1 text-xs font-black text-cream">Recommended</span>
  <p class="font-black">Pro</p>
  <p class="mt-1 text-sm text-ink/70">$9/mo</p>
</div>

06Block quote-mark testimonial

What moves

A quotation mark rendered as a solid color block, not a glyph, slides in and out inside its own narrow lane to the left of the quote text, so it never crosses into the words themselves.

Block quote-mark testimonial
Open in a new tab

06 · Block quote-mark testimonial — Measured area 1.378% · moving frames 22/23Original by GODRICH · SCSS and React ship in the zip · See the password

블록 따옴표정사각 아바타radius 0

In the code

The avatar sits in a thick-bordered square frame instead of a circle, keeping the same square vocabulary as the rest of the card.

<div class="relative flex-1 overflow-hidden border-[3px] border-ink
            bg-cream py-4 pl-8 pr-4 shadow-brutal-sm">
  <span class="absolute inset-y-0 left-0 w-6 bg-blue"></span>
  <p class="relative text-sm font-bold">"It feels like it wraps around your fingertip."</p>
  <p class="relative mt-2 text-xs text-ink/60">Oh Ha-neul · Product Designer</p>
</div>

07Marching-stripe CTA band

What moves

Hard-edged diagonal stripes cover the whole band, and only the background-position shifts, so the pattern marches forever with no visible seam.

Marching-stripe CTA band
Open in a new tab

07 · Marching-stripe CTA band — Measured area 31.335% · moving frames 23/23Original by GODRICH · SCSS and React ship in the zip · See the password

사선 스트라이프background-position 루프radius 0

In the code

The button sits on a fully opaque fill, so its label stays legible no matter where the stripes land underneath it.

<div class="relative overflow-hidden border-[3px] border-ink bg-ink
            px-10 py-12 shadow-brutal">
  <span class="absolute inset-0" aria-hidden="true"
        style="background-image:repeating-linear-gradient(45deg,
               #17141a 0 24px,#ffd23f 24px 48px)"></span>
  <h3 class="relative font-display text-3xl font-black
             text-cream">Bring your team in today</h3>
</div>

08Ruler-drawn divider footer

What moves

The thick rule between footer columns draws itself from top to bottom once, like a ruler line, then holds before retracting for the next pass.

Ruler-drawn divider footer
Open in a new tab

08 · Ruler-drawn divider footer — Measured area 0.15% · moving frames 16/23Original by GODRICH · SCSS and React ship in the zip · See the password

scaleY 드로잉상단 테두리만radius 0

In the code

Only the top border carries any weight — every other corner in the footer stays a hard right angle.

<footer class="flex items-stretch border-t-[6px] border-ink
               bg-cream px-4 pb-6 pt-8">
  <div class="flex-1 px-2">
    <p class="mb-2 text-xs font-black text-blue">Product</p>
    <p class="text-sm font-bold">Features</p>
  </div>
  <span class="w-[3px] flex-none bg-ink"></span>
  <div class="flex-1 px-2">
    <p class="mb-2 text-xs font-black text-ink/50">Company</p>
    <p class="text-sm font-bold">About</p>
  </div>
</footer>

09Press-into-shadow button

What moves

Press the button and its body travels exactly as far as its own shadow offset while the shadow shrinks to zero at the same instant, so it looks like it sinks into the spot its shadow used to occupy.

Press-into-shadow button
Open in a new tab

09 · Press-into-shadow button — Measured area 5.142% · moving frames 19/23Original by GODRICH · SCSS and React ship in the zip · See the password

press 오프셋 이동radius pill(버튼만)focus 그림자 팝

In the code

The input's shadow pops in from nothing on focus, arriving together with the border color change instead of before it.

<form class="flex gap-3 border-[3px] border-ink bg-cream p-6
            shadow-brutal">
  <input class="flex-1 border-[3px] border-ink bg-paper px-4 py-3
                text-sm" type="email" placeholder="Email address">
  <button class="rounded-full border-[3px] border-ink bg-blue
                 px-5 py-3 text-sm font-black text-cream">Sign up</button>
</form>

Custom tailwind.config

Two values cover every radius used across this kit — zero, or a full pill — and both hard shadows get one name each (shadow-brutal, shadow-brutal-sm) so nine section files and the one-pager never redeclare them by hand. Four colors total, three primaries plus the cream base, keep the whole kit inside one small palette.

theme: {
  extend: {
    colors: {
      cream: "#fff7e6",
      ink: "#17141a",
      blue: "#2f6df6",
      yellow: "#ffd23f",
      orange: "#ff4d1f",
    },
    boxShadow: {
      brutal: "8px 8px 0 #17141a",
      "brutal-sm": "4px 4px 0 #17141a",
    },
  },
},

Vibe-coding prompt

Carry that config into a fresh project, then give Claude Code or Cursor a handful of constraints instead of a full design brief — something close to what's below does the job, and the version actually typed into the zip's own prompt.md goes further than this excerpt.

Every card, nav bar, button, and input gets border-radius: 0 — no exceptions.
The one exception is anything actually pressable (a real button element),
which stays a full pill instead.
Borders are always 3px or thicker, one ink color, no border gradients.
box-shadow never gets a blur radius — offset and color only, third value stays 0.
To make one card stand out from its neighbors, reach for rotation
(around -3deg) before reaching for color or size.

Handing an agent that exact instruction and letting it rebuild page/index.html on its own produced the screenshot below, captured at a full 1280px-wide viewport.

result

Where it breaks (the trap)

neobrutalism ui css — where does it break?

320px was where things fell apart first. The number-badge list had its badge size and gaps set close to literal pixel values, and at a narrow viewport the list's actual height reached 232px against a 200px ceiling — 32px over, confirmed by rendering the page and reading the container's own scrollHeight back. Swapping the badge size and the gaps for a clamp() with a lower floor brought the height back under 200px.

The next snag

The second trap showed up in the React port. The footer component has to return a divider and a column side by side, and writing import { Fragment } from "react" threw a "no exported member" error under this project's type declarations. import React from "react" followed by React.Fragment works under every configuration this project has hit so far, so that's the safer default going forward.

The last snag

The marching stripes only avoid a visible seam if background-position shifts by exactly one pattern cycle — twice the stripe width — on every loop; any shorter or longer distance and the stripes visibly jump each time the animation repeats. How much of a flat, unblurred color block survives once it is pasted into an email body is measured separately in 9 Transactional Email Templates. All three fixes already sit inside the zip that the password sfjr6qe2 unlocks.

Turning on reduced motion doesn't touch these nine demos the same way twice: the duplicated headline, the nav stamp, and the sliding cards all freeze outright, while the recommended pricing card instead follows the split that MDN's prefers-reduced-motion documentation recommends — it keeps the tilt, since that carries information about which plan is picked, and cancels only the breathing scale, since that part is pure decoration.

Accessibility

What we checked

yellow (#ffd23f) only ever fills a background block here and never sits directly under small text — pale text on bright yellow loses contrast fast, so every label instead sits on ink or cream, whichever the background actually separates from. Every box-shadow declaration in this kit follows MDN's box-shadow documentation and sets offset and color only, holding the blur radius at zero — the shadow-detach cards in section 03 skip box-shadow altogether and paint that same hard edge as a separate solid-color block instead, but either way the edge stays crisp for low-vision readers instead of dissolving into a soft halo. The nav's brand mark and its CTA button both carry shrink-0 whitespace-nowrap, and the link group in the middle carries min-w-0, so nothing clips or wraps mid-word as the viewport narrows.

Where to go next

The rest of this site's trend write-ups are filed under design trends, and the about page covers what the whole project is for.

FAQ

How do these neobrutalism ui examples differ from glassmorphism or neumorphism?

Glassmorphism blurs a translucent glass panel over whatever sits behind it, and neumorphism keeps a card almost the exact color of its background and carves depth out of a soft double shadow. Neobrutalism goes the other way and leaves the borders thick and the color blocks flat and unblurred, which makes it the highest-contrast of the three and, for that reason, often the easiest one to keep accessible. The soft-shadow end of that same spectrum gets its own nine sections in Neumorphism Design Kit.

Is it ever okay to add a little blur to the shadow?

Adding any blur at all softens the exact signal this style depends on. Every box-shadow here keeps its third value — the blur radius — locked at zero and changes only offset and color, and even the card in section 03, which draws its shadow as a separate solid-color block instead of a real box-shadow, keeps that same hard, unblurred edge.

Does neobrutalism hold up in dark mode?

It does, as long as the background flips to ink while the cards keep cream or one of the primary color blocks. If the shadow color also gets lighter along with the background, it stops reading as separate from the border, so the safest move is leaving the shadow on ink (or something darker still) even after the rest of the palette flips.

Enter the archive password

The password is inside this article. You will find it as you read.