Graffiti

github

Graffiti is good defaults with some magic tricks

Install

npm install @drop-in/graffiti

Then drop in to your project.

import @drop-in/graffiti

or

Just copy and paste from

Give you LLM our docs

Base

Foundation styles that work out of the box - no classes needed.

Typography Defaults

H1 - Large Heading

H2 - Med Heading

H3 - Small Heading

H4 - Xtra Small Heading

H5 - Base Heading
H6 - Small Text Heading

This is a paragraph of body text. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

Vertical Spacing

--vs-s: 0.5rem
--vs-base: 1rem
--vs-m: 1.5rem
--vs-l: 2rem
--vs-xl: 4rem

Border Radius

--br-xs: 2px
--br-s: 4px
--br-m: 8px
--br-l: 16px

Border

--border-05
--border-1
--border-2

Padding

--pad-xs: 2px
--pad-s: 6px
--pad-m: 12px
--pad-l: 25px

Line Heights

Consistent line height tokens for better typography control

--lh-tight: 1.2
This is tight line height, useful for headings and display text where you want compact vertical spacing. The quick brown fox jumps over the lazy dog.
--lh-normal: 1.5
This is normal line height, the default for body text. It provides comfortable reading with balanced spacing. The quick brown fox jumps over the lazy dog. The five boxing wizards jump quickly.
--lh-loose: 1.8
This is loose line height, creating extra vertical breathing room. Useful for larger body text or when you want more space between lines. The quick brown fox jumps over the lazy dog.

Shadows

Modern layered shadows - subtle in light mode, deeper and more intense in dark mode

--shadow-1
Subtle
--shadow-2
Light lift
--shadow-3
Moderate
--shadow-4
Strong
--shadow-5
Dramatic
--shadow-6
Maximum

Colors

OKLCH color system with automatic 1-9 scales generated from base colors (scale 5) using relative color syntax

Yellow Scale

--yellow
--yellow-1
--yellow-2
--yellow-3
--yellow-4
--yellow-5
--yellow-6
--yellow-7
--yellow-8
--yellow-9

Amber Scale

--amber
--amber-1
--amber-2
--amber-3
--amber-4
--amber-5
--amber-6
--amber-7
--amber-8
--amber-9

Orange Scale

--orange
--orange-1
--orange-2
--orange-3
--orange-4
--orange-5
--orange-6
--orange-7
--orange-8
--orange-9

Red Scale

--red
--red-1
--red-2
--red-3
--red-4
--red-5
--red-6
--red-7
--red-8
--red-9

Pink Scale

--pink
--pink-1
--pink-2
--pink-3
--pink-4
--pink-5
--pink-6
--pink-7
--pink-8
--pink-9

Purple Scale

--purple
--purple-1
--purple-2
--purple-3
--purple-4
--purple-5
--purple-6
--purple-7
--purple-8
--purple-9

Indigo Scale

--indigo
--indigo-1
--indigo-2
--indigo-3
--indigo-4
--indigo-5
--indigo-6
--indigo-7
--indigo-8
--indigo-9

Blue Scale

--blue
--blue-1
--blue-2
--blue-3
--blue-4
--blue-5
--blue-6
--blue-7
--blue-8
--blue-9

Green Scale

--green
--green-1
--green-2
--green-3
--green-4
--green-5
--green-6
--green-7
--green-8
--green-9

Lime Scale

--lime
--lime-1
--lime-2
--lime-3
--lime-4
--lime-5
--lime-6
--lime-7
--lime-8
--lime-9

Highlighter Scale

--highlighter
--highlighter-1
--highlighter-2
--highlighter-3
--highlighter-4
--highlighter-5
--highlighter-6
--highlighter-7
--highlighter-8
--highlighter-9

Brown Scale

--brown
--brown-1
--brown-2
--brown-3
--brown-4
--brown-5
--brown-6
--brown-7
--brown-8
--brown-9

Teal Scale

--teal
--teal-1
--teal-2
--teal-3
--teal-4
--teal-5
--teal-6
--teal-7
--teal-8
--teal-9

Gray Scale

--gray-1
--gray-2
--gray-3
--gray-4
--gray-5
--gray-6
--gray-7
--gray-8
--gray-9

Slate Scale

--slate
--slate-1
--slate-2
--slate-3
--slate-4
--slate-5
--slate-6
--slate-7
--slate-8
--slate-9

White Scale (Static)

Does not change with light/dark mode. Use --fg/--bg for adaptive colors.

--white
--white-1
--white-2
--white-3
--white-4
--white-5
--white-6
--white-7
--white-8
--white-9

Black Scale (Static)

Does not change with light/dark mode. Use --fg/--bg for adaptive colors.

--black
--black-1
--black-2
--black-3
--black-4
--black-5
--black-6
--black-7
--black-8
--black-9

Theming Variables

--fg
Foreground color
--bg
Background color

Foreground Scale

Contrasting shades that automatically adapt to light/dark mode. Great for borders, subtle backgrounds, and text emphasis.

--fg
--fg-05
--fg-1
--fg-2
--fg-3
--fg-4
--fg-5
--fg-6
--fg-7
--fg-8
--fg-9

Background Scale

Contrasting tints that automatically adapt to light/dark mode. Useful for layered surfaces and subtle overlays.

--bg
--bg-05
--bg-1
--bg-2
--bg-3
--bg-4
--bg-5
--bg-6
--bg-7
--bg-8
--bg-9

Layouts

.layout-card

Auto-fill responsive card grid

Card 1
Card 2
Card 3
Card 4

.layout-sidebar

Sidebar + main content (250px default)

Main Content

.layout-sidebar.narrow

Main Content

.layout-sidebar.wide

Main Content

.layout-sidebar.invert

Main Content

.layout-sidebar.fill

Full-height sticky sidebar for app shells. Combine with .split.vertical for sidebar internal layout.

App Shell Layout

Main Content

The sidebar stays fixed while this content scrolls independently.

Content block 1
Code
<!-- App Shell Layout Demo -->
<!-- Uses .layout-sidebar.fill for sticky full-height sidebar -->
<!-- Uses .split.vertical for sidebar internal layout (nav top, footer bottom) -->

<div class="layout-sidebar fill" style="--layout-gap: 0; height: 400px;">
  <aside class="split vertical box">
    <nav class="stack no-list">
      <strong>APP NAME</strong>
      <a href="#home">Home</a>
      <a href="#dashboard">Dashboard</a>
      <a href="#settings">Settings</a>
    </nav>
    <div class="stack">
      <small>v1.0.0</small>
      <button class="mini">Upgrade</button>
    </div>
  </aside>
  <section class="stack" style="padding: var(--pad-l);">
    <h3>Main Content</h3>
    <p>The sidebar stays fixed while this content scrolls independently.</p>
    <div class="box">Content block 1</div>
  </section>
</div>

.layout-split

50/50 two column layout

Left Column
Right Column

.layout-split.no-stack

Stays side-by-side on mobile

Left
Right

.layout-three-col

Three equal columns

Column 1
Column 2
Column 3

.layout-readable

Max-width for optimal readability (default: start-aligned)

Learning to drop in on a skateboard is an exciting and challenging milestone for any skateboarder. Before attempting to drop in, ensure that you have a solid foundation of basic skateboarding skills.

.layout-readable.center

Centered readable content with max-width constraint.

.layout-readable.end

End-aligned readable content with max-width constraint.

.layout-readable with .full-bleed child

Regular readable content...

Full bleed element breaks out of container!

More readable content...

.layout-holy-grail

Sidebar

Content

Other sidebar

.stack

Vertical flexbox stack with gap

Item 1
Item 2
Item 3

.grid

Minimal grid utility (like .flex)

200px
Flexible
200px

.cluster

Horizontal wrapping list with gap (perfect for tags, pills, breadcrumbs)

Tag 1 Tag 2 Tag 3 Tag 4 Tag 5 Tag 6

.carousel

Horizontal scroll with CSS scroll-snap (no JavaScript required)

Carousel

Code
<div class="carousel" style="background: var(--fg-05); padding: 1rem">
  <div class="box" style="min-width: 250px; height: 200px">Slide 1</div>
  <div class="box" style="min-width: 250px; height: 200px">Slide 2</div>
  <div class="box" style="min-width: 250px; height: 200px">Slide 3</div>
  <div class="box" style="min-width: 250px; height: 200px">Slide 4</div>
  <div class="box" style="min-width: 250px; height: 200px">Slide 5</div>
</div>

.reel

Vertical scroll with CSS scroll-snap (customizable height with --reel-height)

Reel Layout

Panel 1
Panel 2
Panel 3
Panel 4
Code
<div class="reel" style="--reel-height: 300px;">
  <div class="box" style="min-height: 150px">Panel 1</div>
  <div class="box" style="min-height: 150px">Panel 2</div>
  <div class="box" style="min-height: 150px">Panel 3</div>
  <div class="box" style="min-height: 150px">Panel 4</div>
</div>

.flex

Display flex with 20px gap

Flex Item 1
Flex Item 2
Flex Item 3

.split

Flex with space-between and top alignment (used in header)

Left Side
Right Side

.split.vertical

Vertical split - pushes first and last children to opposite ends

Top
Bottom

.readable

Max-width 900px container

This content is constrained to 900px max-width for optimal readability. Unlike .layout-readable, this doesn't include padding.

Elements

Standalone building blocks you can use anywhere.

Boxes

.box
Simple
.box-glow
Subtle
.box.semi-gloss
Semi Gloss
.box-ghost
Simple
You can make a custom box with CSS variables box-shadow: var(--box), var(--shadow-5);

.avatar

Circular avatar for user images or initials. Supports multiple sizes and optional border.

Avatar Variants

User avatar User avatar User avatar User avatar User avatar
A BC JD ST XL
User avatar AB User avatar CD
Team member Team member Team member Team member Team member
Code
<div class="stack">
	<!-- Size variants with images -->
	<div class="cluster">
		<span class="avatar xs">
			<img src="https://i.pravatar.cc/150?u=1" alt="User avatar" />
		</span>
		<span class="avatar s">
			<img src="https://i.pravatar.cc/150?u=2" alt="User avatar" />
		</span>
		<span class="avatar">
			<img src="https://i.pravatar.cc/150?u=3" alt="User avatar" />
		</span>
		<span class="avatar l">
			<img src="https://i.pravatar.cc/150?u=4" alt="User avatar" />
		</span>
		<span class="avatar xl">
			<img src="https://i.pravatar.cc/150?u=5" alt="User avatar" />
		</span>
	</div>

	<!-- Initials fallback (no image) -->
	<div class="cluster">
		<span class="avatar xs">A</span>
		<span class="avatar s">BC</span>
		<span class="avatar">JD</span>
		<span class="avatar l">ST</span>
		<span class="avatar xl">XL</span>
	</div>

	<!-- Bordered variant -->
	<div class="cluster">
		<span class="avatar bordered">
			<img src="https://i.pravatar.cc/150?u=6" alt="User avatar" />
		</span>
		<span class="avatar bordered">AB</span>
		<span class="avatar l bordered">
			<img src="https://i.pravatar.cc/150?u=7" alt="User avatar" />
		</span>
		<span class="avatar l bordered">CD</span>
	</div>

	<!-- Row of avatars side by side -->
	<div class="cluster">
		<span class="avatar">
			<img src="https://i.pravatar.cc/150?u=10" alt="Team member" />
		</span>
		<span class="avatar">
			<img src="https://i.pravatar.cc/150?u=11" alt="Team member" />
		</span>
		<span class="avatar">
			<img src="https://i.pravatar.cc/150?u=12" alt="Team member" />
		</span>
		<span class="avatar">
			<img src="https://i.pravatar.cc/150?u=13" alt="Team member" />
		</span>
		<span class="avatar">
			<img src="https://i.pravatar.cc/150?u=14" alt="Team member" />
		</span>
	</div>
</div>

.button

Button styling for links and non-button elements

Button Variants

Code
<div class="stack">
  <!-- Default and semantic variants -->
  <div class="cluster">
    <button>Default</button>
    <button class="primary">Primary</button>
    <button class="success">Success</button>
    <button class="warning">Warning</button>
    <button class="error">Error</button>
    <button class="ghost">Ghost</button>
    <button class="minimal">Minimal</button>
  </div>

  <!-- Mini size variants -->
  <div class="cluster">
    <button class="mini">Default</button>
    <button class="mini primary">Primary</button>
    <button class="mini success">Success</button>
    <button class="mini warning">Warning</button>
    <button class="mini error">Error</button>
    <button class="mini ghost">Ghost</button>
    <button class="mini minimal">Minimal</button>
  </div>
</div>

.table

A wrapping div for overflow scrolling, but also generic tables styles defined by default without the wrapping claas.

HiHellosup✅ Icon or emoji in thisYo
HiHellosupSome data in this cell that might be a bit long I don't know.Yo
HiHellosupSome data in this cell that might be a bit long I don't know.Yo
HiHellosupSome data in this cell that might be a bit long I don't know.Yo
HiHellosupSome data in this cell that might be a bit long I don't know.Yo
HiHellosupSome data in this cell that might be a bit long I don't know.Yo
HiHellosupSome data in this cell that might be a bit long I don't know.Yo

.callout

An informational callout

Callout Variants

Default callout for general information and tips.

Warning callout for important notices that need attention.

Error callout for critical issues or destructive actions.

Success callout for confirmations and positive feedback.

Ghost callout for subtle, neutral messages.

Add .hard to any variant for a stronger left border accent.

Warning with the hard modifier for extra emphasis.

Callouts support multiple elements

They automatically stack children with consistent spacing.

Code
<div class="stack">
  <!-- Default callout (blue) -->
  <div class="callout">
    <p>Default callout for general information and tips.</p>
  </div>

  <!-- Warning variant -->
  <div class="callout warning">
    <p>Warning callout for important notices that need attention.</p>
  </div>

  <!-- Error variant -->
  <div class="callout error">
    <p>Error callout for critical issues or destructive actions.</p>
  </div>

  <!-- Success variant -->
  <div class="callout success">
    <p>Success callout for confirmations and positive feedback.</p>
  </div>

  <!-- Ghost variant -->
  <div class="callout ghost">
    <p>Ghost callout for subtle, neutral messages.</p>
  </div>

  <!-- Hard modifier (stronger left border) -->
  <div class="callout hard">
    <p>Add <code>.hard</code> to any variant for a stronger left border accent.</p>
  </div>

  <div class="callout warning hard">
    <p>Warning with the hard modifier for extra emphasis.</p>
  </div>

  <!-- Multi-element callout -->
  <div class="callout success">
    <h5>Callouts support multiple elements</h5>
    <p>They automatically stack children with consistent spacing.</p>
  </div>
</div>

Forms

Form inputs and validation states.

Toggle Switch

Accessible toggle/switch input using native checkbox semantics

Toggle Variants

Code
<div class="stack">
  <!-- Basic toggles -->
  <div class="cluster">
    <input type="checkbox" class="toggle" />
    <input type="checkbox" class="toggle" checked />
    <input type="checkbox" class="toggle" checked style="--toggle-color: var(--green)" />
  </div>

  <!-- Disabled states -->
  <div class="cluster">
    <input type="checkbox" class="toggle" disabled />
    <input type="checkbox" class="toggle" checked disabled />
  </div>

  <!-- Compact variant -->
  <div class="cluster">
    <input type="checkbox" class="toggle compact" />
    <input type="checkbox" class="toggle compact" checked />
  </div>

  <!-- With labels -->
  <div class="stack">
    <label class="cluster">
      <input type="checkbox" class="toggle" />
      <span>Enable notifications</span>
    </label>
    <label class="cluster">
      <input type="checkbox" class="toggle" checked />
      <span>Dark mode</span>
    </label>
  </div>
</div>

Form Validation States

Built-in styles for error, success, and warning states

Please enter a valid email address
Username is available!
Password is weak. Consider using a stronger password.

UI-Components

Composed components built from multiple elements.

Accordion

Native HTML accordion using details/summary with smooth animations via @starting-style and allow-discrete.

Accordion Variants

Getting Started

Graffiti is a drop-in CSS library that styles native HTML elements automatically. No classes required for basic styling—just write semantic HTML.

Installation Options

Install via npm with npm install graffiti-css, or include directly from a CDN. The library works with any framework or vanilla HTML.

View Source Code

The right-aligned variant places the toggle indicator on the opposite side, useful for "show code" toggles or secondary actions.

Frequently Asked Questions

The minimal variant removes extra padding and uses a simple +/− indicator, perfect for compact FAQ sections or nested accordions.

Code
<div class="stack">
  <!-- Basic details/summary -->
  <details>
    <summary>Getting Started</summary>
    <p>
      Graffiti is a drop-in CSS library that styles native HTML elements automatically.
      No classes required for basic styling—just write semantic HTML.
    </p>
  </details>

  <!-- Bordered variant -->
  <details class="bordered">
    <summary>Installation Options</summary>
    <p>
      Install via npm with <code>npm install graffiti-css</code>, or include directly
      from a CDN. The library works with any framework or vanilla HTML.
    </p>
  </details>

  <!-- Right-aligned trigger variant -->
  <details class="right">
    <summary>View Source Code</summary>
    <p>
      The right-aligned variant places the toggle indicator on the opposite side,
      useful for "show code" toggles or secondary actions.
    </p>
  </details>

  <!-- Minimal variant with +/− toggle -->
  <details class="minimal">
    <summary>Frequently Asked Questions</summary>
    <p>
      The minimal variant removes extra padding and uses a simple +/− indicator,
      perfect for compact FAQ sections or nested accordions.
    </p>
  </details>
</div>

Breadcrumbs

Simple breadcrumb navigation with slash separators. Uses semantic HTML with proper ARIA attributes for accessibility.

Breadcrumbs

Code
<div class="stack">
	<!-- Basic breadcrumb trail -->
	<nav class="breadcrumbs" aria-label="Breadcrumb">
		<ul class="no-list">
			<li><a href="/">Home</a></li>
			<li><a href="/products">Products</a></li>
			<li><a href="/products/electronics">Electronics</a></li>
			<li aria-current="page">Wireless Headphones</li>
		</ul>
	</nav>

	<!-- Custom separator -->
	<nav class="breadcrumbs" style="--separator: '›'" aria-label="Breadcrumb">
		<ul class="no-list">
			<li><a href="/">Home</a></li>
			<li><a href="/docs">Docs</a></li>
			<li aria-current="page">Getting Started</li>
		</ul>
	</nav>
</div>

Dropdown Menu

Native dropdown menu using HTML popover API and CSS anchor positioning. No JavaScript required for open/close.

Dropdown Menu

Code
<div class="cluster">
  <!-- Basic dropdown with header, items, and dividers -->
  <div class="dropdown">
    <button popovertarget="dropdown-basic">Options</button>
    <div id="dropdown-basic" popover class="dropdown-menu">
      <div class="dropdown-header">Account</div>
      <hr>
      <a href="#profile">Profile</a>
      <a href="#settings">Settings</a>
      <hr>
      <button>Sign Out</button>
    </div>
  </div>

  <!-- End-aligned dropdown -->
  <div class="dropdown end">
    <button popovertarget="dropdown-end">Actions</button>
    <div id="dropdown-end" popover class="dropdown-menu">
      <div class="dropdown-header">Quick Actions</div>
      <hr>
      <a href="#edit">Edit</a>
      <a href="#duplicate">Duplicate</a>
      <a href="#archive">Archive</a>
      <hr>
      <button>Delete</button>
    </div>
  </div>
</div>

.swipe

Interactive swipe component

You can swipe me side to side, no JavaScript. (although you do need JS for events)

.swipe.stop

Swiper that stays in it's "open" state.

You can swipe me side to side, minor JavaScript needed for Safari. (although you do need JS for events)

.swipe.stop.full-bleed

Swiper that stays in it's "open" state.

You can swipe me side to side, no JavaScript. (although you do need JS for events)

You can have multiple buttons of various styles too.

You can swipe me side to side, no JavaScript. (although you do need JS for events)

Blocks

Complete UI patterns combining multiple elements and components.

.header

Full-width header with navigation

Your Logo

.header.border

Header with subtle border on bottom

Your Logo

.header.sticky

Header that sticks to the top when scrolling

Sticky Header

Utilities

Modifier and helper classes for common adjustments.

.no-list

Remove list styling (margin, padding, list-style)

Regular List

  • Item 1
  • Item 2
  • Item 3

With .no-list

  • Item 1
  • Item 2
  • Item 3

.circle

Circular element (default --size: 40px)

.row

Add vertical margin (--vs-m)

No .row class
With .row class - has margin-block
No .row class

.visually-hidden

Hide element visually but keep accessible to screen readers

There is hidden text after this colon: This text is hidden visually but available to screen readers!

You can't see it, but it's there for accessibility.

.fc (Fluid Container)

Makes typography responsive to container width instead of viewport

Regular (viewport-based)

This heading scales with viewport

Text scales with viewport width

With .fc (container-based)

This heading scales with container

Text scales with this box's width

.h1 - .h6

Apply heading sizes to any element without semantic heading tags

.h1 - Largest heading size

.h2 - Second level

.h3 - Third level

.h4 - Fourth level

.h5 - Fifth level

.h6 - Sixth level

.fs-* (Font Size)

Fluid font size utilities using the --fl (fluid level) system

.fs-xs - Extra small (--fl: -1)

.fs-base - Base size (--fl: 0)

.fs-s - Small heading (--fl: 1)

.fs-m - Medium (--fl: 2)

.fs-l - Large (--fl: 3)

.fs-xl - Extra large (--fl: 4)

.fs-xxl - Double extra large (--fl: 5)

.fs-xxxl - Triple extra large (--fl: 6)

.auto-color

Automatically sets text color (light or dark) based on background luminosity

Blue background
Yellow background
Dark red background
Green background
Purple background

Set --bg-color and the text color adjusts automatically

Aspect Ratio Utilities

Maintain specific aspect ratios for containers (useful for images, videos, cards)

.aspect-square
1:1
.aspect-video
16:9
.aspect-4-3
4:3
.aspect-21-9
21:9

Custom: Use aspect-ratio: 2 / 1; or aspect-ratio: var(--aspect-ratio);

The website footer. I always hate doing footers for some reason. Just ignore this.