Skip to main content

ChessBoard

Every example on this page is live, drawn by the library's Storybook, where you can also change its props and see the result.

A chess position, drawn from its FEN record in the frame's two colors. White's pieces are outlined and Black's are solid, and the dark squares are hatched, so the board stays sharp on e-ink and follows dark mode without swapping the two armies.

Use it instead of a board image from a chess API: an image is soft on e-ink, always shows White at the bottom, and breaks when its website is down.

Import​

import { ChessBoard, materialOf } from "~lib/data-display/chess-board";

Props​

NameTypeRequiredDefaultDescription
fenstringYesN/AThe position, as a whole FEN record or just its piece placement
sizenumberNoN/AWidth and height in pixels, for a thumbnail. Leave it out to fill the box it sits in
orientation"white" | "black"NoThe side to moveWhich side is at the bottom (White when the record doesn't say)
coordinatesbooleanNotrueLetter the files and number the ranks along the edges
highlightstring[]NoN/ASquares to frame, such as ["e2", "e4"] for the last move
labelstringNo"Chess position"What screen readers announce

The file letters and rank numbers are left out when the board is too small for them to fit, including in previews shown at a smaller size.

Examples​

Starting Position​

Open Starting Position in Storybook

A Puzzle​

Frame squares with highlight, such as the last move or a hint.

Open Puzzle in Storybook

Black to Move​

When the record says Black is to move, Black is at the bottom. Set orientation to choose.

Open Black To Move in Storybook

Filling Its Box​

Leave out size and the board is as large a square as the box it sits in holds, centered in it. In a box with no height of its own, the board is as tall as it is wide. Previews of the widget at other sizes keep the board square too, as large as each box allows.

Open Fills Its Box in Storybook

In a widget, give the board its box in CSS rather than a size worked out from the measured box. A preview is a saved render with its scripts removed, laid out again in boxes of other sizes, so a pixel size is frozen at whatever the box measured when it was saved, and in a smaller box the last ranks are cut off. A box in CSS shrinks with it instead:

// Down a column: as wide as the column, and the first block to give up height.
<div className="aspect-square w-full min-h-0 shrink">
<ChessBoard fen={fen} />
</div>

// Across a row: as tall as the row, leaving the panel beside it its least width.
<div className="aspect-square h-full shrink-0" style={{ maxWidth: "calc(100% - 312px)" }}>
<ChessBoard fen={fen} />
</div>

Use size only for a thumbnail that should be the same pixels wherever it is shown.

Thumbnail​

Open Thumbnail in Storybook

Who Is Ahead​

materialOf counts each side's pieces and their worth in points (a pawn 1, a knight or bishop 3, a rook 5, a queen 9), and the balance between them, above zero when White is ahead.

import { ChessBoard, materialOf } from "~lib/data-display/chess-board";
import { Stat } from "~lib/data-display/stat";

const Position = ({ fen }: { fen: string }) => {
const { balance } = materialOf(fen);
return (
<div className="flex items-center gap-4">
<ChessBoard fen={fen} size={240} />
<Stat
label="Material"
value={
balance === 0
? "Even"
: `${balance > 0 ? "White" : "Black"} +${Math.abs(balance)}`
}
/>
</div>
);
};

To draw the pieces themselves beside the board, use MaterialStrip.

See Also​

  • MaterialStrip - Each side's pieces and points, drawn beside the board
  • QRCode - A code to play the puzzle on a phone
  • Stat - A labelled figure