emily.config.json → emily.css

One config.
Your complete CSS system.

Define your brand colours, fonts, and spacing once. Emily generates every utility you need and gives you production-ready components to copy straight into any project.

How it works

1

Define your brand

Add your brand colours to emily.config.json. Fonts, spacing, and breakpoints too. One file, everything in one place.

{
  "colours": {
    "primary": "#DB2777",
    "secondary": "#2563EB"
  }
}
2

Build your stylesheet

Run the build script. Emily generates a 10-shade scale per colour, plus every utility you need. Purge unused classes to get down to 10–50 KB.

node src/index.js --purge .

# Before: 1.1 MB
# After:  ~39 KB
3

Copy and ship

Link the stylesheet. Browse the components below. Copy the HTML, paste into your project. Works in Drupal, static HTML, Power Pages — anything that loads a CSS file.

<link rel="stylesheet"
  href="dist/emily.purged.css">

Get started

From zero to a working design system in under 30 minutes.

1

Clone or download the repo

git clone https://github.com/yourusername/emilyui.git
cd emilyui
2

Edit emily.config.json

Set your brand colours. Shade 80 is always your input hex — the rest of the scale is generated automatically.

{
  "colours": {
    "primary":   "#DB2777",
    "secondary": "#2563EB",
    "success":   "#059669",
    "warning":   "#D97706",
    "error":     "#DC2626",
    "neutral":   "#57534E"
  },
  "fontFamily": "inter"
}
3

Build and purge

Point --purge at any directory. Emily scans your HTML, Twig, Vue, JSX — whatever you use.

node src/index.js --purge .
4

Link the stylesheet

Drop this into your <head>. No JavaScript, no build pipeline, no dependencies.

<link rel="stylesheet" href="dist/emily.purged.css">
5

Use utility classes in your markup

Classes follow a consistent naming pattern. Responsive with md:, lg: prefixes. State variants with hover:, focus:.

<!-- Colour -->
bg-primary-80    text-primary-80    border-primary-80

<!-- Spacing -->
p-4   px-6   py-3   m-2   mt-8   gap-4

<!-- Typography -->
text-xl   font-semibold   text-neutral-60

<!-- Responsive -->
text-base md:text-lg lg:text-xl

<!-- State -->
hover:bg-primary-90   focus-visible:outline-2

Quick reference

The most common utility categories. Every class follows the same pattern — change the value, the result changes.

Colours

bg-primary-80 text-primary-80 border-primary-80 bg-primary-10 bg-{colour}-{10–100}

Spacing

p-4   px-6   py-3 mt-8   mb-4   mx-auto gap-4   gap-6 p-{0–96}   m-{0–96}

Typography

text-xl   text-sm font-semibold   font-bold text-neutral-60 uppercase   tracking-wide text-{xs–4xl}

Layout

flex   flex-col   flex-wrap items-center   items-start justify-between shrink-0   flex-1

Grid

grid   grid-cols-2 grid-cols-3   grid-cols-4 gap-4   gap-6 grid-cols-{1–12}

Borders & Radius

border   border-2   border-4 border-neutral-30 rounded   rounded-md rounded-lg   rounded-full

Shadows

shadow-sm shadow shadow-md shadow-lg

States & Variants

hover:bg-primary-90 focus-visible:outline-2 cursor-not-allowed transition   sr-only md:   lg:   hover:   focus:

Colours

Each config colour generates a 10-shade scale. Shade 80 is your input hex. Use bg-{colour}-{shade}, text-{colour}-{shade}, border-{colour}-{shade}.

primary
10
20
30
40
50
60
70
80
90
100
secondary
10
20
30
40
50
60
70
80
90
100
success
10
20
30
40
50
60
70
80
90
100
warning
10
20
30
40
50
60
70
80
90
100
error
10
20
30
40
50
60
70
80
90
100
neutral
10
20
30
40
50
60
70
80
90
100

Typography

Type scale and font weight utilities. Use text-{size} and font-{weight}.

Type Scale

text-4xl 36px The quick brown fox
text-3xl 30px The quick brown fox
text-2xl 24px The quick brown fox jumps over the lazy dog
text-xl 20px The quick brown fox jumps over the lazy dog
text-lg 18px The quick brown fox jumps over the lazy dog
text-base 16px The quick brown fox jumps over the lazy dog
text-sm 14px The quick brown fox jumps over the lazy dog
text-xs 12px The quick brown fox jumps over the lazy dog

Font Weights

font-light 300 Emily — config-driven design
font-normal 400 Emily — config-driven design
font-medium 500 Emily — config-driven design
font-semibold 600 Emily — config-driven design
font-bold 700 Emily — config-driven design

Spacing

Padding, margin, and gap utilities. Use p-{n}, m-{n}, gap-{n}.

Padding Scale

p-10.25rem
p-20.5rem
p-41rem
p-61.5rem
p-82rem
p-123rem

Gap Scale

gap-10.25rem
gap-20.5rem
gap-41rem
gap-61.5rem
gap-82rem

Shadows & Borders

Use shadow-{size} and rounded-{size}.

Box Shadows

shadow-sm
Small
shadow
Base
shadow-md
Medium
shadow-lg
Large

Border Radius

rounded-none0
rounded-sm4px
rounded8px
rounded-md12px
rounded-lg16px
rounded-full9999px

Border Widths

border-00px
border1px
border-22px
border-44px
border-88px

Components

Production-ready. Copy the HTML, paste into your project. All accessibility attributes included.

Button

<!-- Primary -->
<button class="bg-primary-80 text-white px-5 py-2 rounded font-medium text-sm hover:bg-primary-90 focus-visible:outline-2 focus-visible:outline-primary-80 transition cursor-pointer border-0">
  Primary
</button>

<!-- Outline -->
<button class="bg-white text-primary-80 px-5 py-2 rounded font-medium text-sm border-2 border-primary-80 hover:bg-primary-10 focus-visible:outline-2 focus-visible:outline-primary-80 transition cursor-pointer">
  Outline
</button>

<!-- Disabled -->
<button class="bg-neutral-20 text-neutral-50 px-5 py-2 rounded font-medium text-sm cursor-not-allowed border-0" disabled aria-disabled="true">
  Disabled
</button>

Text Input

Includes focus-visible, error state with aria-invalid, and disabled variant.

Enter a valid email address.
<div class="flex flex-col gap-1">
  <label for="email" class="text-sm font-medium text-neutral-80">Email address</label>
  <input id="email" type="email" placeholder="you@example.com"
    class="w-full px-3 py-2 border-2 border-neutral-30 rounded text-sm text-neutral-90 bg-white focus-visible:outline-2 focus-visible:outline-primary-80 transition" />
</div>

<!-- Error state -->
<div class="flex flex-col gap-1">
  <label for="email-error" class="text-sm font-medium text-neutral-80">Email address</label>
  <input id="email-error" type="email" aria-invalid="true" aria-describedby="email-error-msg"
    class="w-full px-3 py-2 border-2 border-error-80 rounded text-sm text-neutral-90 bg-white focus-visible:outline-2 focus-visible:outline-error-80 transition" />
  <span id="email-error-msg" class="text-xs text-error-80" role="alert">Enter a valid email address.</span>
</div>

Card

Basic card

A simple card with a title, some body text, and an action.

Featured

PRO

Highlighted card for key features or calls to action.

Total projects 142 ↑ 12% this month
<div class="bg-white border-2 border-neutral-20 rounded-lg p-5 shadow-sm flex flex-col gap-3">
  <h2 class="text-base font-semibold text-neutral-90">Card title</h2>
  <p class="text-sm text-neutral-60">Card body text goes here.</p>
  <button class="bg-primary-80 text-white px-4 py-2 rounded text-sm font-medium hover:bg-primary-90 transition cursor-pointer border-0 self-start">
    View details
  </button>
</div>

Alert

Heads up

Scheduled maintenance on Sunday 29 April, 2–4am.

<!-- Success alert -->
<div class="bg-success-10 border-2 border-success-30 rounded p-4 flex gap-3 items-start" role="alert">
  <!-- icon -->
  <div>
    <p class="text-sm font-semibold text-success-90">Changes saved</p>
    <p class="text-sm text-success-80">Your settings have been updated successfully.</p>
  </div>
</div>

<!-- Error alert -->
<div class="bg-error-10 border-2 border-error-30 rounded p-4 flex gap-3 items-start" role="alert">
  <!-- icon -->
  <div>
    <p class="text-sm font-semibold text-error-90">Something went wrong</p>
    <p class="text-sm text-error-80">We couldn&apos;t save your changes. Please try again.</p>
  </div>
</div>