Skip to content

How to Convert Any React Project to Neobrutalism in 10 Minutes

Want to give your boring React app a bold makeover? Learn how to transform any React project into a stunning neobrutalist design in just 10 minutes using Neobrutalism. Step-by-step tutorial with before/after examples.

Let's be real: your React app probably looks like every other React app out there. Clean? Sure. Professional? Absolutely. Memorable? Not even close.


But what if I told you that in just 10 minutes, you could transform your generic-looking project into something that screams personality? Something that makes people go, "Whoa, what's THAT?"


That's the power of neobrutalism—a design style that's bold, unapologetic, and impossible to ignore. And with Neobrutalism, converting your React project is ridiculously easy.


Grab your coffee (or energy drink, no judgment), and let's turn that vanilla app into something spicy.


What the Heck is Neobrutalism Anyway?

Before we dive in, let's get on the same page. Neobrutalism is a design movement that takes inspiration from the raw, concrete-heavy brutalist architecture of the 1950s and gives it a modern, digital twist.


Think:

  • Thick black borders on everything
  • Hard shadows (none of that soft blur nonsense)
  • High contrast colors like black, white, and neon yellow
  • Zero rounded corners (sharp and angular, baby)
  • Asymmetric layouts that break the grid

It's anti-perfectionism. It's rebellious. It's the design equivalent of wearing a leather jacket to a board meeting. And it works.


Why Neobrutalism?

You could build neobrutalist components from scratch, but why reinvent the wheel when Neobrutalism exists? It's a React UI library built specifically for neobrutalism, with:

  • Pre-built components with that signature brutal aesthetic
  • Easy installation via CLI
  • Fully customizable with Tailwind CSS
  • Works with Next.js, Vite, Remix—basically any React setup

Plus, it's free and open-source. Let's get started.



Step 1: Set Up Your Project (2 minutes)

First things first. If you're working with an existing React project, you're already ahead. If not, let's spin up a quick Next.js app (but this works for any React framework).


pnpm create next-app@latest my-brutal-app
cd my-brutal-app
npx create-next-app@latest my-brutal-app
cd my-brutal-app
yarn create next-app@latest my-brutal-app
cd my-brutal-app
bunx --bun create-next-app@latest my-brutal-app
cd my-brutal-app

Say yes to TypeScript and Tailwind CSS when prompted. We'll need both.


If you're using Vite or Create React App, that's cool too—the setup is nearly identical.



Step 2: Install Neobrutalism (1 minute)

Now for the magic. We need to initialize shadcn (Neobrutalism uses it under the hood) and install the Neobrutalism utilities.


Run this command:

pnpm dlx shadcn@latest init
npx shadcn@latest init
yarn dlx shadcn@latest init
bunx --bun shadcn@latest init

You'll get some prompts. Here's what you should pick:

  • Style: Default
  • Base color: Slate (doesn't matter much, we'll override it)
  • CSS variables: Yes

Next, install the Neobrutalism utils:

pnpm dlx shadcn@latest add https://neobrutalism.com/r/utils.json
npx shadcn@latest add https://neobrutalism.com/r/utils.json
yarn dlx shadcn@latest add https://neobrutalism.com/r/utils.json
bunx --bun shadcn@latest add https://neobrutalism.com/r/utils.json

Done. That's it. You now have the foundation to build brutalist interfaces.



Step 3: Add the Neobrutalist Theme (2 minutes)

This is where the transformation really begins. Open your global.css file (usually in app/globals.css or src/index.css) and replace the theme variables with Neobrutalism's signature brutal theme.


Paste this into your CSS:

@theme {
  --font-head: var(--font-head);
  --font-sans: var(--font-sans);
  --radius: 0;
 
  --shadow-xs: 1px 1px 0 0 var(--border);
  --shadow-sm: 2px 2px 0 0 var(--border);
  --shadow: 3px 3px 0 0 var(--border);
  --shadow-md: 4px 4px 0 0 var(--border);
  --shadow-lg: 6px 6px 0 0 var(--border);
  --shadow-xl: 10px 10px 0 1px var(--border);
  --shadow-2xl: 16px 16px 0 1px var(--border);
 
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-secondary: var(--secondary);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-border: var(--border);
}
 
:root {
  --radius: 0;
  --background: #fff;
  --foreground: #000;
  --primary: #ffdb33;
  --primary-foreground: #000;
  --secondary: #000;
  --secondary-foreground: #fff;
  --border: #000;
}
 
.dark {
  --background: #1a1a1a;
  --foreground: #f5f5f5;
  --primary: #ffdb33;
  --primary-foreground: #000;
  --secondary: #3a3a3a;
  --secondary-foreground: #f5f5f5;
  --border: #3a3a3a;
}

What just happened?

  • We killed all border-radius (no more rounded corners!)
  • We swapped soft shadows for hard, offset shadows
  • We set up a bold black/white/yellow color scheme
  • We added dark mode support (because we're not savages)

Already, your app is starting to look different. But we're not done yet.



Step 4: Install Your First Components (2 minutes)

Let's grab some actual components. We'll start with the essentials: Button, Card, and Input.


Run these commands one by one:

pnpm dlx shadcn@latest add https://neobrutalism.com/r/button.json
npx shadcn@latest add https://neobrutalism.com/r/card.json
npx shadcn@latest add https://neobrutalism.com/r/input.json
npx shadcn@latest add https://neobrutalism.com/r/button.json
npx shadcn@latest add https://neobrutalism.com/r/card.json
npx shadcn@latest add https://neobrutalism.com/r/input.json
yarn dlx shadcn@latest add https://neobrutalism.com/r/button.json
npx shadcn@latest add https://neobrutalism.com/r/card.json
npx shadcn@latest add https://neobrutalism.com/r/input.json
bunx --bun shadcn@latest add https://neobrutalism.com/r/button.json
npx shadcn@latest add https://neobrutalism.com/r/card.json
npx shadcn@latest add https://neobrutalism.com/r/input.json

Each component gets added to your components/neobrutalism/ folder, ready to use. No need to write a single line of CSS.



Step 5: Swap Out Your Components (2 minutes)

Now comes the fun part—replacing your boring old components with the new brutal ones.


Before:

// Your old, generic button
<button className="bg-blue-500 text-white px-4 py-2 rounded">
  Click Me
</button>

After:

import { Button } from "@/components/neobrutalism/Button";
 
<Button>Click Me</Button>

Just like that, you've got a button with thick black borders, a hard shadow, and that signature neobrutalist vibe.


Let's do the same for a card:


Before:

<div className="bg-white shadow-lg rounded-lg p-6">
  <h2 className="text-2xl font-bold">My Card</h2>
  <p className="text-gray-600">Some generic content here.</p>
</div>

After:

import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/neobrutalism/Card";
 
<Card>
  <CardHeader>
    <CardTitle>My Card</CardTitle>
    <CardDescription>Now with 100% more attitude.</CardDescription>
  </CardHeader>
  <CardContent>
    Some bold content here.
  </CardContent>
</Card>

Same structure, completely different vibe. The card now has sharp edges, bold borders, and a hard shadow that makes it pop off the page.



Step 6: Add Neobrutalist Fonts (1 minute)

Typography is HUGE in neobrutalism. The default system fonts won't cut it. Neobrutalism recommends Archivo Black for headings and Space Grotesk for body text.


If you're using Next.js, add this to your app/layout.tsx:

import { Archivo_Black, Space_Grotesk } from "next/font/google";
 
const archivoBlack = Archivo_Black({
  subsets: ["latin"],
  weight: "400",
  variable: "--font-head",
  display: "swap",
});
 
const spaceGrotesk = Space_Grotesk({
  subsets: ["latin"],
  weight: "400",
  variable: "--font-sans",
  display: "swap",
});
 
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={`${archivoBlack.variable} ${spaceGrotesk.variable}`}>
        {children}
      </body>
    </html>
  );
}

Now your headings are chunky and bold, while your body text stays clean and readable.



Step 7: Fine-Tune and Customize (Optional)

You're basically done at this point, but if you want to customize further, Neobrutalism makes it easy.


Want a different accent color? Change the --primary variable in your CSS.

:root {
  --primary: #ff006e; /* Hot pink instead of yellow */
}

Want softer shadows? Adjust the shadow variables.

--shadow: 2px 2px 0 0 var(--border); /* Smaller offset */

Want to add more components? Check out the full library at neobrutalism.com/docs/components. There are inputs, badges, dialogs, tables, and more—all styled with that brutal aesthetic.



Before and After: The Transformation

Alright, let's see the difference. Here's what a simple landing page looks like before and after the neobrutalist conversion.


Before: Generic React App

export default function GenericLanding() {
  return (
    <div className="min-h-screen bg-gray-50 flex items-center justify-center">
      <div className="max-w-md bg-white shadow-lg rounded-lg p-8">
        <h1 className="text-3xl font-bold text-gray-900 mb-4">
          Welcome to My App
        </h1>
        <p className="text-gray-600 mb-6">
          This is a clean, minimal design that looks like every other React app.
        </p>
        <input
          type="email"
          placeholder="Enter your email"
          className="w-full px-4 py-2 border border-gray-300 rounded mb-4"
        />
        <button className="w-full bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
          Get Started
        </button>
      </div>
    </div>
  );
}

What's wrong with this?

Nothing, technically. It's functional. It's clean. But it's also completely forgettable. If you showed this to 100 people, they'd confuse it with a dozen other sites they've seen this week.


After: Neobrutalist Makeover

import { Button } from "@/components/neobrutalism/Button";
import { Card, CardHeader, CardTitle, CardContent } from "@/components/neobrutalism/Card";
import { Input } from "@/components/neobrutalism/Input";
 
export default function BrutalLanding() {
  return (
    <div className="min-h-screen bg-[#ffdb33] flex items-center justify-center p-4">
      <Card className="max-w-md w-full">
        <CardHeader>
          <CardTitle className="text-4xl font-head uppercase">
            Welcome to My App
          </CardTitle>
        </CardHeader>
        <CardContent className="space-y-4">
          <p className="text-lg font-sans">
            This is a bold, memorable design that actually stands out.
          </p>
          <Input type="email" placeholder="Enter your email" />
          <Button className="w-full">Get Started</Button>
        </CardContent>
      </Card>
    </div>
  );
}

What changed?

  • Background: Went from boring gray to electric yellow
  • Typography: Used bold, uppercase heading with Archivo Black
  • Borders: Everything has thick black borders
  • Shadows: Hard, offset shadows instead of soft blurs
  • Corners: Zero border-radius—sharp and angular
  • Vibe: From "corporate brochure" to "indie startup with attitude"

This is the same component structure, the same layout, but it feels completely different. People will remember this.



Another Example: Dashboard Widget

Let's look at a more complex example—a dashboard stats card.


Before: Bland Dashboard

export default function GenericStats() {
  return (
    <div className="grid grid-cols-3 gap-4">
      <div className="bg-white rounded-lg shadow p-6">
        <p className="text-gray-500 text-sm">Total Users</p>
        <p className="text-3xl font-bold text-gray-900">1,284</p>
        <p className="text-green-500 text-sm">+12% from last month</p>
      </div>
      <div className="bg-white rounded-lg shadow p-6">
        <p className="text-gray-500 text-sm">Revenue</p>
        <p className="text-3xl font-bold text-gray-900">$52,340</p>
        <p className="text-green-500 text-sm">+8% from last month</p>
      </div>
      <div className="bg-white rounded-lg shadow p-6">
        <p className="text-gray-500 text-sm">Active Now</p>
        <p className="text-3xl font-bold text-gray-900">127</p>
        <p className="text-red-500 text-sm">-3% from last hour</p>
      </div>
    </div>
  );
}

After: Brutal Dashboard

import { Card, CardContent } from "@/components/neobrutalism/Card";
 
export default function BrutalStats() {
  return (
    <div className="grid grid-cols-3 gap-6">
      <Card className="bg-[#ffdb33]">
        <CardContent className="pt-6">
          <p className="text-sm font-bold uppercase mb-2">Total Users</p>
          <p className="text-5xl font-head mb-2">1,284</p>
          <p className="text-sm font-bold">▲ 12% from last month</p>
        </CardContent>
      </Card>
      <Card className="bg-white">
        <CardContent className="pt-6">
          <p className="text-sm font-bold uppercase mb-2">Revenue</p>
          <p className="text-5xl font-head mb-2">$52,340</p>
          <p className="text-sm font-bold">▲ 8% from last month</p>
        </CardContent>
      </Card>
      <Card className="bg-black text-white">
        <CardContent className="pt-6">
          <p className="text-sm font-bold uppercase mb-2">Active Now</p>
          <p className="text-5xl font-head mb-2">127</p>
          <p className="text-sm font-bold">▼ 3% from last hour</p>
        </CardContent>
      </Card>
    </div>
  );
}

What's different?

  • Color blocking: Each card has a distinct background (yellow, white, black)
  • Bold typography: Numbers are huge and use the display font
  • High contrast: White text on black creates instant visual hierarchy
  • Uppercase labels: Makes everything feel more intentional and bold
  • Arrows instead of color: Uses ▲ and ▼ symbols for clarity

Same data, wildly different presentation. The brutal version feels confident and designed, not just assembled.



Pro Tips for Neobrutalist Design

Now that you've got the basics down, here are some tips to really nail the aesthetic:


1. Embrace Asymmetry

Don't be afraid to break the grid. Offset elements, overlap borders, let things breathe unevenly. Perfection is boring.


2. Use Color Intentionally

Neobrutalism loves high-contrast color combos. Black and white as your base, then add one or two accent colors (yellow, pink, cyan). Don't go rainbow—pick a vibe and commit.


3. Go Big on Typography

Headings should be MASSIVE. Body text can be normal, but your H1s should command attention. Use bold, uppercase letters when you want to make a statement.


4. Add Micro-Interactions

Brutal doesn't mean static. Add hover effects where buttons slightly shift or shadows get bigger. Keep it subtle but noticeable.

<Button className="hover:translate-x-1 hover:translate-y-1 transition-transform">
  Click Me
</Button>

5. Don't Overdo It

Not every element needs a thick border. Not every section needs a bright background. Balance is still important—just tilted toward boldness.



What to Do Next

Congrats! You just gave your React project a complete visual overhaul in about 10 minutes. Here's what you can do from here:


Explore More Components

Neobrutalism has a full library of components—badges, dialogs, tables, tabs, and more. Check out the component docs and see what else you can add.


Customize Your Theme

Play with the CSS variables to match your brand. Change accent colors, adjust shadow intensity, or tweak spacing to make it yours.


Build Something Cool

Now that your app doesn't look generic, show it off! Share it on Twitter, post it on Reddit, add it to your portfolio. People notice neobrutalism.


Join the Community

Neobrutalism has an active Discord where designers and developers share projects, ask questions, and geek out over brutal design. Jump in and say hi.



Final Thoughts

Most React apps look the same because most developers reach for the same tools—Material UI, Bootstrap, shadcn with default settings. There's nothing wrong with those (they're great!), but they won't help you stand out.


Neobrutalism is a shortcut to personality. It's bold, memorable, and surprisingly easy to implement with the right tools. Neobrutalism gives you everything you need to make the switch without rebuilding from scratch.


In just 10 minutes, you went from "another React app" to "wait, what's THAT?" And honestly? That's powerful.


So go ahead—make your app impossible to ignore.


Now get out there and build something brutal. 🚀


← Back to blogs