Grailwind CSS

Heraldic blazon for Tailwind CSS

In heraldry and heraldic vexillology, a blazon is a formal description of a coat of arms, flag, or similar emblem, from which the reader can reconstruct an accurate image.
— Wikipedia, “Blazon”

Grailwind is a plugin for Tailwind CSS that lets you render coats of arms on your webpages using the ancient language of the heralds.

Note: Grailwind is a light-hearted project at version 0.x, so don't expect perfection. Class names may still change.

Install

Grailwind is a plugin for Tailwind CSS v4.

npm install -D grailwind

Import it after Tailwind in your stylesheet:

@import "tailwindcss";
@import "grailwind";

This adds the heraldic tinctures alongside Tailwind's own colours, so bg-azure and bg-blue-500 both work.

Strict mode

To commit fully to the bit, import grailwind/strict instead. The tinctures then replace Tailwind's colours entirely, and bg-blue-500 no longer exists. This site uses strict mode.

@import "tailwindcss";
@import "grailwind/strict";

Tinctures

Heraldry has two metals and five colours. A tincture on its own sets the background, as it describes the field in blazon: <div class="azure">. Everywhere else, use Tailwind's usual prefixes: text-or, border-sable, and so on.

or
gold, metal
argent
silver, metal
gules
red
azure
blue
vert
green
purpure
purple
sable
black

The rule of tincture

Never put a metal on a metal or a colour on a colour, so the design can be read from a distance. Grailwind doesn't enforce this (yet).

The shield

escutcheon gives an element a shield shape. Size it however you like, e.g. escutcheon w-40.

The top is the chief and the bottom is the base. Left and right are from the point of view of the person holding the shield. Dexter is their right, which is the left as you look at it, and sinister is their left, which to you is the right. It couldn't be simpler.

You'll meet these words in the order of tinctures, in classes like bend-sinister, and in the named points for placing charges.

Dividing the field

One class paints a divided field. Any two different tinctures work. The first tincture named goes on the dexter side or in chief.

Dividing for layout

per-pale, per-fess and quarterly divide an element into equal parts, one child element per part, in blazon order. They're grids, so they also work for laying out a page. The top of this page uses md:per-pale.

Bordure

bordure-or, or any other tincture, adds a border.

Ordinaries

The ordinaries are bold geometric shapes drawn over the field. Add a tincture to name one: fess-or, cross-gules.

Combining

An element can have one ordinary plus a chief. With a chief, the other ordinary and any charges are drawn in the field below it. Ordinaries can go over any field, including a divided one.

Fimbriation

Charges

Charges are child elements inside a charges container, coloured with a tincture class.

Built-in charges

mullet
roundel
annulet
lozenge
billet
crescent
fleur-de-lis

Roundels have their own names by tincture, so these need no tincture class:

bezant
Or
plate
Argent
torteau
Gules
hurt
Azure
pellet
Sable

Arrangement

In a line

in-pale, in-fess and in-bend put two or three charges in a vertical, horizontal or diagonal line.

Between

between places charges around the ordinary on the shield, whichever it is.

On

on places charges along the ordinary on the shield, whichever it is.

At a named point

Heraldry names nine points on the shield. Put one on a charge to place it there, as in in dexter chief a mullet.

  1. in-dexter-chief dexter chief
  2. in-chief middle chief
  3. in-sinister-chief sinister chief
  4. in-honour-point honour point
  5. in-fess-point fess point
  6. in-nombril-point nombril point
  7. in-dexter-base dexter base
  8. in-base middle base
  9. in-sinister-base sinister base

Sizing

Each arrangement picks a sensible size. To change it, use charge-size-* with a percentage of the shield's width: charge-size-15, or any length, like charge-size-[2rem]. On the charges container it sizes every charge. On a single charge, just that one.

Your own charges

Any element inside charges gets placed, so you can bring your own. charge-[url(…)] uses your SVG as a mask, so a tincture class colours it. The URL is resolved relative to your built stylesheet, and the image must come from the same site or be served with CORS headers.

An <img> keeps the image's own colours, like a charge proper.

All together

A divided field, an ordinary, a chief, a bordure, and charges on, between and in chief.

Accessibility

A shield is a picture made of empty elements. Give it a text alternative, ideally its blazon:

<div class="escutcheon azure fess-or" role="img"
     aria-label="Azure, a fess Or"></div>

Grailwind uses :has(), CSS masks and CSS nesting, so it needs a current browser.