Open Source

Neo-Brutalist
Design System

Bold 3px borders. Hard offset shadows. Uppercase everything. Squared corners. Zero blur, zero apologies.

Works with React · Vue 3 · Svelte · Pure CSS · Tailwind CSS

Install
CSS only (any framework)
$ npm i @mariojgt/neo-css
React
$ npm i @mariojgt/neo-css @mariojgt/neo-react
Vue 3
$ npm i @mariojgt/neo-css @mariojgt/neo-vue
Svelte
$ npm i @mariojgt/neo-css @mariojgt/neo-svelte
// Import the CSS once in your entry file
import '@mariojgt/neo-css/dist/neo.css'

// React — named imports, fully tree-shakeable
import { NeoButton, NeoCard, NeoAlert, NeoTag } from '@mariojgt/neo-react'

// Vue 3 — global plugin or individual imports
import NeoVue from '@mariojgt/neo-vue'
createApp(App).use(NeoVue).mount('#app')

// Svelte — individual component imports
import { NeoButton, NeoCard } from '@mariojgt/neo-svelte'

// Tailwind preset
// tailwind.config.js
module.exports = { presets: [require('@mariojgt/neo-css/tailwind-preset')] }
Buttons
Variants
Sizes
/* CSS */
<button class="neo-btn neo-btn-primary neo-btn-md">Primary</button>

// React
<NeoButton variant="primary" size="md">Primary</NeoButton>

// Vue
<NeoButton variant="accent" size="lg">Accent</NeoButton>

// Svelte
<NeoButton variant="ghost" on:click={handler}>Ghost</NeoButton>
Tags & Badges
Tags
Brand Accent Ghost Premium Hot
Badges
Default Published Draft Archived
<span class="neo-tag neo-tag-accent neo-tag-rotate">Hot</span>
<span class="neo-badge neo-badge-success">Published</span>

// React
<NeoTag variant="accent" rotated>Hot</NeoTag>
<NeoBadge variant="success">Published</NeoBadge>
Cards

.neo-card

Standard card. 3px border, 5px shadow. Hover to lift.

.neo-card-brand

Green top accent bar.

.neo-star

Adds a ★ in the top-right corner.

.neo-card-pattern

Micro-grid pattern on hover.

.neo-stat-card

12,847

+23% this month

<div class="neo-card">Standard</div>
<div class="neo-card-brand">Brand</div>
<div class="neo-card neo-star">Starred</div>

// React
<NeoCard variant="brand" pattern>Content</NeoCard>
<NeoCard variant="stat">12,847</NeoCard>
Form Controls
/* CSS classes */
<input    class="neo-input" />
<select   class="neo-select">...</select>
<textarea class="neo-input"></textarea>

// React
<NeoInput    label="Name"  placeholder="Your name..." />
<NeoTextarea label="Bio"   placeholder="About you..." />
<NeoSelect   label="Level" :options="opts" />
Table
CourseStudentsRatingStatus
React Mastery 2,431 ★ 4.9 Published
Node.js Deep Dive 1,847 ★ 4.7 Published
TypeScript Pro 963 ★ 4.8 Draft
/* CSS */
<table class="neo-table">
  <thead><tr><th>Course</th>...</tr></thead>
  <tbody><tr><td>React Mastery</td>...</tr></tbody>
</table>

// React — generic typed component
<NeoTable
  rowKey="id"
  columns={[{ key: 'name', header: 'Course' }]}
  data={courses}
/>
Toggle & Tabs
Toggle Group
Tab Bar
// React
const [view, setView] = React.useState('grid')

<NeoToggleGroup value={view} onChange={setView}>
  <NeoToggleItem value="grid">Grid</NeoToggleItem>
  <NeoToggleItem value="list">List</NeoToggleItem>
</NeoToggleGroup>

<NeoTabBar value={tab} onChange={setTab}>
  <NeoTab value="details">Details</NeoTab>
  <NeoTab value="media">Media</NeoTab>
</NeoTabBar>
Alerts

Success — Your changes have been saved.

Warning — Your subscription expires in 3 days.

Error — Something went wrong. Please try again.

Info — New courses drop every week.

<div class="neo-alert neo-alert-success">...</div>

// React
<NeoAlert variant="success" title="Saved" icon={<CheckIcon/>}>
  Your changes have been saved.
</NeoAlert>

// Vue
<NeoAlert variant="warning" title="Heads up">
  <template #icon><WarningIcon/></template>
  Expires soon.
</NeoAlert>
Decorative Elements
Header BarPremium

Branded diagonal-stripe header strip for cards and modals.

.neo-header-bar

Dashed divider with scissors:


Content below the cut.

.neo-divider

Price Display

$49.99 .neo-price

Gradient Text

Emerald Gradient

.neo-text-gradient
Animations

Fade In Up

.animate-neo-fade-in-up

Float

.animate-neo-float
🔔

Ping Slow

.animate-neo-ping-slow

Gradient Shift

.animate-neo-gradient-shift
<div class="animate-neo-fade-in-up">Fades in on load</div>
<span class="animate-neo-float">★</span>
<span class="animate-neo-ping-slow"></span>
<h1   class="animate-neo-gradient-shift">Gradient</h1>
Toast Notifications
Live demo — click to fire
// Drop-in vanilla JS helper — zero dependencies
import { neoToast } from '@mariojgt/neo-css/toast'

// neoToast(variant, title, message, duration?)
neoToast('success', 'Saved!',   'Changes saved.')       // 4 s auto-dismiss
neoToast('warning', 'Heads Up', 'Expires soon.')       // 4 s auto-dismiss
neoToast('error',   'Error',    'Try again.')           // 4 s auto-dismiss
neoToast('info',    'Tip',      'Pro tip here.')        // 4 s auto-dismiss
neoToast('success', 'Sticky',  'No dismiss.', 0)       // duration 0 = stays

// React — tiny wrapper hook
const { toast } = useNeoToast()
toast.success('Saved!', 'All good.')
toast.error('Oops',   'Try again.')

// Vue — composable
const { toast } = useNeoToast()
toast.warning('Watch out', 'Expires soon.')
Themes

Override CSS custom properties on :root to switch the entire palette instantly. Pick one below — every component on this page updates live.

Emerald

The default. Deep teal brand with amber accent.

Violet

Electric purple brand with hot-pink accent.

Crimson

Bold red brand with golden-orange accent.

// JS — zero dependencies, works everywhere
setNeoTheme('emerald')  // default
setNeoTheme('violet')
setNeoTheme('crimson')

// Or supply your own token overrides
setNeoTheme({ '--neo-brand': '#0ea5e9', '--neo-brand-light': '#38bdf8', '--neo-brand-dark': '#0284c7' })

/* CSS — override tokens directly in your stylesheet */
:root {
  --neo-brand:       #7c3aed;
  --neo-brand-light: #a855f7;
  --neo-brand-dark:  #6d28d9;
  --neo-accent:      #ec4899;
  --neo-accent-dark: #db2777;
}
Theme Builder

Tweak the tokens below — every component on this page updates in real time. Hit Copy CSS to grab the override block.

Brand Color

Accent Color

Surfaces

Live Preview

Success Warning Error Default

Sample Card

Border top picks up your brand color.

Tag Accent
Changes apply instantly across every component.

Generated CSS


          
        
Framework Examples

Available on npm — fully typed, tree-shakeable, zero extra dependencies beyond the CSS theme.

ReactTypeScript
import { NeoButton, NeoCard, NeoAlert }
  from '@mariojgt/neo-react'

export default function Demo() {
  return (
    <NeoCard variant="brand" style={{padding:'1.5rem'}}>
      <NeoAlert variant="success" title="Done">
        Changes saved.
      </NeoAlert>
      <NeoButton variant="primary">
        Get Started
      </NeoButton>
    </NeoCard>
  )
}
Vue 3Composition API
<!-- main.ts -->
import NeoVue from '@mariojgt/neo-vue'
createApp(App).use(NeoVue).mount('#app')

<!-- Component.vue -->
<template>
  <NeoCard variant="brand">
    <NeoButton
      variant="primary"
      @click="handleClick"
    >
      Click me
    </NeoButton>
  </NeoCard>
</template>
Svelte 4SFC
<!-- App.svelte -->
<script>
  import { NeoButton, NeoCard }
    from '@mariojgt/neo-svelte'
  let count = 0
</script>

<NeoCard variant="brand">
  <NeoButton
    variant="accent"
    on:click={() => count++}
  >
    Clicked {count}×
  </NeoButton>
</NeoCard>
Pure CSSAny framework
<!-- HTML -->
<link rel="stylesheet"
  href="https://unpkg.com/@mariojgt/neo-css/dist/neo.css">

<button class="neo-btn neo-btn-primary">
  Primary
</button>

<div class="neo-card neo-star"
     style="padding:1.5rem">
  Featured Card
</div>
ReactModal & Accordion
import { NeoModal, NeoAccordion, NeoButton }
  from '@mariojgt/neo-react'

const faq = [
  { id: 'q1', trigger: 'Is it free?',
    content: 'MIT licensed.' },
]
const [open, setOpen] = useState(false)

<>
  <NeoAccordion items={faq} defaultOpen={['q1']} />
  <NeoButton onClick={() => setOpen(true)}>Help</NeoButton>
  <NeoModal open={open} title="FAQ"
    onClose={() => setOpen(false)}>
    Full details here.
  </NeoModal>
</>
Vue 3Tooltip & Avatar
<!-- main.ts -->
import NeoVue from '@mariojgt/neo-vue'
createApp(App).use(NeoVue).mount('#app')

<!-- Profile.vue -->
<NeoTooltip tip="Online">
  <NeoAvatar size="md" color="brand"
    status="online">MJ</NeoAvatar>
</NeoTooltip>

<NeoAvatarGroup>
  <NeoAvatar size="md">A</NeoAvatar>
  <NeoAvatar size="md">B</NeoAvatar>
  <NeoAvatar size="md">+4</NeoAvatar>
</NeoAvatarGroup>
Svelte 4Gaming UI
<script>
  import { NeoLeaderboard, NeoProgressBar }
    from '@mariojgt/neo-svelte'
  let xp = 62, hp = 80
  const entries = [
    { rank: 1, name: 'mariojgt', score: '142,830' },
  ]
</script>

<NeoLeaderboard entries={entries} />
<NeoProgressBar variant="xp"
  value={xp} label="⚡ XP" striped />
<NeoProgressBar variant="hp"
  value={hp} label="♥ HP" />
Pure CSSRarity & Skeleton
<!-- Rarity cards -->
<div class="neo-item-card neo-rarity
  neo-rarity-legendary">
  <div class="neo-item-icon">👑</div>
  <p class="neo-item-name">Crown</p>
  <p class="neo-item-rarity">Legendary</p>
</div>

<!-- Skeleton loader -->
<div class="neo-skeleton neo-skeleton-title"></div>
<!-- Keyboard badge -->
<span class="neo-kbd">⌘ K</span>
Full Example Card
Creative Studio Premium

Award-winning design studio crafting bold brands and cutting-edge digital experiences.

UI/UX Dev Brand

$899

per project

Components

The building blocks that put this kit on the same level as shadcn, DaisyUI, and Radix.

Keyboard Shortcuts
⌘ K ⌃ ⇧ P Esc ↵ Enter Press ⌘ K to open the command palette
<span class="neo-kbd">⌘ K</span>
<span class="neo-kbd">⌃ ⇧ P</span>
<span class="neo-kbd">Esc</span>

// React
import { NeoKbd } from '@mariojgt/neo-react'
<NeoKbd>⌘ K</NeoKbd>

// Vue / Svelte (same API)
import { NeoKbd } from '@mariojgt/neo-vue'
<NeoKbd>⌘ K</NeoKbd>
Tooltips
✓ Verified
<!-- Pure CSS — add data-tip to any element -->
<button class="neo-btn neo-btn-primary"
  data-tip="Creates a new project">
  New Project
</button>

// React
import { NeoTooltip, NeoButton } from '@mariojgt/neo-react'
<NeoTooltip tip="Creates a new project">
  <NeoButton>New Project</NeoButton>
</NeoTooltip>

// Vue
<NeoTooltip tip="Creates a new project">
  <NeoButton>New Project</NeoButton>
</NeoTooltip>

// Svelte
import { NeoTooltip } from '@mariojgt/neo-svelte'
<NeoTooltip tip="Creates a new project">
  <NeoButton>New Project</NeoButton>
</NeoTooltip>
Skeleton Loaders
Card skeleton
List skeleton
// React import { NeoSkeleton } from '@mariojgt/neo-react' <NeoSkeleton variant="thumb" /> <NeoSkeleton variant="title" /> <NeoSkeleton variant="text" /> <NeoSkeleton variant="avatar"/> <NeoSkeleton variant="btn" /> // Vue / Svelte — same API <NeoSkeleton variant="thumb" />
<!-- Shimmer skeleton — pure CSS -->
<div class="neo-skeleton neo-skeleton-thumb"></div>
<div class="neo-skeleton neo-skeleton-title"></div>
<div class="neo-skeleton neo-skeleton-text"></div>
<div class="neo-skeleton neo-skeleton-avatar"></div>
<div class="neo-skeleton neo-skeleton-btn"></div>

// React
import { NeoSkeleton } from '@mariojgt/neo-react'
<NeoSkeleton variant="thumb" />
<NeoSkeleton variant="title" />
<NeoSkeleton variant="text"  />
<NeoSkeleton variant="avatar"/>
<NeoSkeleton variant="btn"  />

// Vue / Svelte — same API
<NeoSkeleton variant="thumb" />
Avatars
Sizes & variants
MJ
DK
AB
🎮
Avatar group
MJ
AB
KC
+4
<div class="neo-avatar neo-avatar-md neo-avatar-brand neo-avatar-online">MJ</div>

<!-- Group -->
<div class="neo-avatar-group">
  <div class="neo-avatar neo-avatar-md">MJ</div>
  <div class="neo-avatar neo-avatar-md">AB</div>
  <div class="neo-avatar neo-avatar-md">+4</div>
</div>

// React
import { NeoAvatar, NeoAvatarGroup } from '@mariojgt/neo-react'
<NeoAvatar size="md" color="brand" status="online">MJ</NeoAvatar>

<NeoAvatarGroup>
  <NeoAvatar size="md">MJ</NeoAvatar>
  <NeoAvatar size="md">AB</NeoAvatar>
  <NeoAvatar size="md">+4</NeoAvatar>
</NeoAvatarGroup>

// Vue / Svelte — same props
<NeoAvatar size="lg" color="accent">AB</NeoAvatar>
Accordion
A Neo-Brutalist design system built for developers who want bold, opinionated UI without compromising on DX. Works with React, Vue, Svelte and plain HTML/CSS.
Yes. We ship a first-class Tailwind preset (@mariojgt/neo-css/tailwind-preset) that maps all Neo design tokens to Tailwind utilities.
100% MIT licensed. Use it in personal projects, commercial products, games — whatever you want.
<div class="neo-accordion">
  <div class="neo-accordion-item open">
    <button class="neo-accordion-trigger" onclick="neoAccordion(this)">
      Title <span class="neo-accordion-chevron">▼</span>
    </button>
    <div class="neo-accordion-body">Content here.</div>
  </div>
</div>

// React
import { NeoAccordion } from '@mariojgt/neo-react'
const items = [
  { id: 'a', trigger: 'What is Neo UI?', content: 'A neo-brutalist design system.' },
  { id: 'b', trigger: 'Free?',           content: '100% MIT licensed.' },
]
<NeoAccordion items={items} defaultOpen={['a']} />

// Vue
<NeoAccordion :items="items" :default-open="['a']" />

// Svelte
import { NeoAccordion } from '@mariojgt/neo-svelte'
<NeoAccordion items={items} defaultOpen={['a']} />
Modal
<!-- Trigger -->
<button onclick="neoModalOpen('my-modal')">Open</button>

<!-- Modal HTML -->
<div class="neo-modal-backdrop" id="my-modal">
  <div class="neo-modal">
    <div class="neo-modal-header">
      <h2 class="neo-modal-title">Title</h2>
      <button class="neo-modal-close"
        onclick="neoModalClose('my-modal')">✕</button>
    </div>
    <div class="neo-modal-body">Body text...</div>
    <div class="neo-modal-footer">
      <button class="neo-btn neo-btn-primary">Confirm</button>
    </div>
  </div>
</div>

// JS
neoModalOpen('my-modal')
neoModalClose('my-modal')

// React
import { NeoModal, NeoButton } from '@mariojgt/neo-react'
const [open, setOpen] = React.useState(false)

<NeoModal open={open} title="Confirm Action"
  onClose={() => setOpen(false)}>
  Body text here.
</NeoModal>

// Vue
<NeoModal :open="isOpen" title="Title" @close="isOpen = false">
  Body text here.
  <template #footer>
    <NeoButton variant="primary">OK</NeoButton>
  </template>
</NeoModal>

// Svelte
import { NeoModal } from '@mariojgt/neo-svelte'
<NeoModal open={isOpen} title="Title" on:close={() => isOpen = false}>
  Body text here.
</NeoModal>
Command Palette
// Open with JS or keyboard shortcut
neoCommandOpen()

// Register custom commands
neoCommandRegister([
  { icon: '🏠', label: 'Go Home', action: () => location.href = '/' },
  { icon: '⚡', label: 'New Game', badge: 'hot', action: startGame },
  { icon: '⚙', label: 'Settings', action: openSettings },
])

// Keyboard shortcut built-in: ⌘K or Ctrl+K
Rarity Item Cards
⚔️

Iron Sword

Common

🛡️

Forest Shield

Uncommon

🔮

Arcane Orb

Rare

🗡️

Soul Reaver

Epic

👑

Crown of Ages

Legendary

<div class="neo-item-card neo-rarity neo-rarity-legendary">
  <div class="neo-item-icon">👑</div>
  <p   class="neo-item-name">Crown of Ages</p>
  <p   class="neo-item-rarity">Legendary</p>
</div>

/* Variants: neo-rarity-common | uncommon | rare | epic | legendary */

// React
import { NeoRarityCard } from '@mariojgt/neo-react'
<NeoRarityCard name="Crown of Ages" rarity="legendary" icon="👑" />

// Vue
<NeoRarityCard name="Arcane Orb" rarity="rare" icon="🔮" />

// Svelte
import { NeoRarityCard } from '@mariojgt/neo-svelte'
<NeoRarityCard name="Soul Reaver" rarity="epic" icon="🗡️" />
Leaderboard
# Player Score
🥇
MJ
mariojgt
142,830
🥈
DK
darkwolf99
98,410
🥉
XK
xkira
87,200
4
SC
speedchaser
71,540
5
NX
nexusplayer
64,000
<div class="neo-leaderboard">
  <div class="neo-lb-header">...header...</div>
  <div class="neo-lb-row">
    <span class="neo-lb-rank neo-lb-rank-1">🥇</span>
    <span class="neo-lb-name">mariojgt</span>
    <span class="neo-lb-score">142,830</span>
  </div>
</div>

// React
import { NeoLeaderboard } from '@mariojgt/neo-react'
const entries = [
  { rank: 1, name: 'mariojgt',   score: '142,830' },
  { rank: 2, name: 'darkwolf99', score: '98,410'  },
  { rank: 3, name: 'xkira',      score: '87,200'  },
]
<NeoLeaderboard entries={entries} />

// Vue
<NeoLeaderboard :entries="entries" />

// Svelte
import { NeoLeaderboard } from '@mariojgt/neo-svelte'
<NeoLeaderboard entries={entries} />
Gaming Utilities

Drop-in classes and JS helpers designed for game UIs, dashboards, and anything that needs some impact.

Camera Shake
Click to trigger
// JS — shake the whole page
neoShake('sm')   // subtle
neoShake('md')   // noticeable
neoShake('lg')   // earthquake
neoShake('md', el) // shake a specific element

/* CSS classes */
<div class="neo-shake-md">Shakes on mount</div>
Glitch Text
// React — NeoProgressBar component import { NeoProgressBar } from '@mariojgt/neo-react' <NeoProgressBar variant="xp" value={62} label="⚡ XP" valueLabel="6,240 / 10,000" striped /> <NeoProgressBar variant="hp" value={68} label="♥ HP" /> <NeoProgressBar variant="mp" value={40} label="✦ MP" /> // Vue <NeoProgressBar variant="xp" :value="xp" label="⚡ XP" striped /> // Svelte import { NeoProgressBar } from '@mariojgt/neo-svelte' <NeoProgressBar variant="hp" value={hp} label="♥ HP" />
GAME OVER
<!-- data-text must match inner text -->
<span class="neo-glitch" data-text="GAME OVER">
  GAME OVER
</span>

// Toggle off
el.classList.toggle('neo-glitch-pause')
XP · HP · MP Bars
⚡ XP — Level 14 6,240 / 10,000
♥ HP 340 / 500
✦ MP 80 / 200
<!-- HTML structure -->
<div class="neo-xp-bar">
  <div class="neo-xp-label">
    <span class="neo-xp-label-text">⚡ XP</span>
    <span class="neo-xp-label-val">6,240 / 10,000</span>
  </div>
  <div class="neo-xp-track" data-striped>
    <div class="neo-xp-fill" style="width:62%"></div>
  </div>
</div>

// Variants
"neo-xp-fill"              // green XP
"neo-xp-fill neo-hp-fill"  // red HP
"neo-xp-fill neo-mp-fill"  // blue MP
"neo-xp-track-sm"          // slim variant
"neo-xp-track-lg"          // chunky variant

// React — NeoProgressBar component
import { NeoProgressBar } from '@mariojgt/neo-react'
<NeoProgressBar variant="xp" value={62}
  label="⚡ XP" valueLabel="6,240 / 10,000" striped />
<NeoProgressBar variant="hp" value={68} label="♥ HP" />
<NeoProgressBar variant="mp" value={40} label="✦ MP" />

// Vue
<NeoProgressBar variant="xp" :value="xp" label="⚡ XP" striped />

// Svelte
import { NeoProgressBar } from '@mariojgt/neo-svelte'
<NeoProgressBar variant="hp" value={hp} label="♥ HP" />
Achievement Unlocked
// neoAchievement(icon, title, description)
neoAchievement('🏆', 'First Blood', 'You landed your first hit.')
neoAchievement('⚡', 'Speedrunner', 'Under 5 min.')
neoAchievement('💎', 'Legend',      'Rank S on all stages.')
Combo Counter
0 COMBO
// JS counter helpers
neoComboHit()    // increment + animate
neoComboReset()  // reset to 0

<!-- HTML -->
<div class="neo-combo">
  <span class="neo-combo-count">12</span>
  <span class="neo-combo-label">COMBO</span>
</div>
More FX

Add .neo-scanlines to any element for a CRT effect.

// Particle burst at cursor position
btn.addEventListener('click', e => neoParticles(e))

// Screen flash (hit feedback)
neoFlash()

// Typewriter
neoTypewriter(element, 'INSERT COIN TO CONTINUE_', 55)

/* CRT scanlines */
<div class="neo-scanlines">...</div>
Charge Button

Hold the cursor over the button — a power bar charges, then fires when full.

/* CSS charge bar */
<button class="neo-btn neo-btn-primary neo-btn-charge">
  Hold to Charge
</button>

// JS — fire after 1.4 s hover
startCharge(el)   // bind to mouseenter
cancelCharge(el)  // bind to mouseleave

Neo Brutalist Modal

This is a fully keyboard-accessible modal with a backdrop blur, spring animation, and a close button. Click outside or press Esc to dismiss.

⚠ Danger Zone

This action is irreversible. Are you sure you want to delete this item permanently?