๐ Table of Contents
โจ Features
๐ฏ 8x8 Chess Board
Traditional chess board layout with alternating colors and coordinate labels
โ๏ธ Individual Chess Pieces
Separate component for each piece type and color, including fairy pieces
๐ Piece Rotation
Rotate pieces in 45ยฐ increments (0-315ยฐ) with keyboard shortcuts or API
๐จ Fairy Chess Notation
Support for fairy-name and fairy-condition annotations for problem compositions
๐ฑ๏ธ 3-Button Mouse Editing
Main click selects/moves, middle/auxiliary click removes pieces, and context click dispatches a dedicated event
๐งฌ Clone & Invert Editing
Move a selected piece while holding Shift to clone it, or Ctrl to clone and flip
the color
โจ๏ธ Keyboard Navigation
Full keyboard support for piece placement, rotation, and board manipulation
๐ FEN Support
Load and display chess positions using Forsyth-Edwards Notation
โ๏ธ Board Orientation
Flip between white/black perspective with keyboard shortcuts
๐ฑ Responsive Design
Automatically adapts to container size with CSS Container Queries
โ๏ธ Programmatic API
Complete TypeScript API for adding, removing, and rotating pieces
๐งฉ Cell Decorators
Add a visual overlay layer inside each square above the background and below pieces or notation
๐งช Fully Tested
Comprehensive test suite with Vitest (241 tests passing)
๐ง TypeScript
Full type safety and modern development experience
๐ Web Components
Native custom elements with Shadow DOM for safe integration
๐ผ๏ธ Full html2canvas compatible
Fully compatible with html2canvas for capturing the board as an image
๐ฎ Live Demo
Try the interactive chess board below. Click to select a square, then use keyboard shortcuts to add and manipulate pieces:
๐ก Click on the board and try: Arrow keys (navigate), P/p (add pieces), Alt/Option+Arrow (rotate), Delete (remove)
๐ฆ Installation
pnpm add @dardino/chess-board
๐ Basic Usage
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Chess Board Demo</title>
<!-- Load chess piece font (required) -->
<link rel="stylesheet" href="./assets/ScacchiPainter.css" />
</head>
<body>
<!-- Empty chess board -->
<chess-board></chess-board>
<!-- Board with FEN position -->
<chess-board fen="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"></chess-board>
<script type="module">
import '@dardino/chess-board';
</script>
</body>
</html>
โ๏ธ Programmatic API
The chess board provides a complete TypeScript API for programmatic manipulation:
Adding and Removing Pieces
const board = document.querySelector('chess-board');
// Add a piece
board.addPiece('e4', 'q', 'w'); // White queen on e4
board.addPiece('d4', 'k', 'b', '45'); // Black king on d4, rotated 45ยฐ
// Remove a piece
board.removePiece('e4');
// Check if square has piece
if (board.hasPiece('d4')) {
console.log('Square d4 is occupied');
}
// Get piece information
const piece = board.getPieceAt('d4');
console.log(piece); // { type: 'k', color: 'b', rotation: '45' }
Bulk Operations
// Get all pieces on board
const pieces = board.getAllPieces();
console.log(pieces);
// [{ square: 'd4', type: 'k', color: 'b', rotation: '45' }, ...]
// Set multiple pieces at once (clears board first)
board.setPieces([
{ square: 'e1', type: 'k', color: 'w', rotation: '0' },
{ square: 'e8', type: 'k', color: 'b', rotation: '0' },
{ square: 'd1', type: 'q', color: 'w', rotation: '45' }
]);
Piece Rotation
// Rotate piece by relative amount
board.rotatePiece('e4', 45); // Rotate clockwise by 45ยฐ
board.rotatePiece('e4', -45); // Rotate counter-clockwise
// Set absolute rotation
board.setPieceRotation('e4', '180'); // Set to 180ยฐ
// Get rotation
const rotation = board.getPieceRotation('e4');
console.log(rotation); // '180'
Cell Decorators
// Add a visual decorator layer under pieces but above the square background
board.setCellDecorators({
e4: { backgroundColor: '#ffeb3b', innerBorder: 'solid 2px #d97706' },
d4: { backgroundColor: 'rgba(59, 130, 246, 0.25)', innerBorder: 'solid 1px rgba(37, 99, 235, 0.8)' }
});
// Clear all decorators
board.setCellDecorators({});
Piece Selection & Movement
// Get the currently selected piece square
const selectedSquare = board.getSelectedPieceSquare();
if (selectedSquare) {
console.log(`Piece selected at: ${selectedSquare}`);
console.log(`Piece info:`, board.getPieceAt(selectedSquare));
}
// Select the piece on e4 and make e4 the current square
const wasSelected = board.selectPiece('e4');
console.log(wasSelected); // true when e4 contains a piece
// Mouse workflow:
// 1. Primary click selects/moves pieces
// 2. Auxiliary (middle) click removes any piece on the clicked square
// 3. Hold Shift while moving to clone the piece
// 4. Hold Ctrl while moving to clone and invert the piece color
// 5. Keyboard workflow (Space or Enter):
// a. Press Space or Enter on a square with a piece โ selects it
// b. Navigate with arrow keys to an empty square
// c. Press Space or Enter again โ moves the piece there and clears selection
// d. Press Escape โ cancels selection without moving
// e. Any other key or blur event โ clears selection
Current Square
// Get the current keyboard-navigation square
const currentSquare = board.getCurrentSquare(); // string | null
// Set the current square without selecting a piece
board.selectSquare('e4');
Events
// Preferred event name for the main mouse button
board.addEventListener('cellMainClick', (event) => {
const { square, piece } = event.detail;
console.log('Clicked:', square, piece);
});
// Deprecated compatibility alias for older code
board.addEventListener('cellClick', (event) => {
const { square, piece } = event.detail;
console.log('Legacy click:', square, piece);
});
board.addEventListener('fenChange', (event) => {
console.log('Current FEN/FFEN:', event.detail.fen);
});
Cell Decorators
<chess-board id="sample-board" fen="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"></chess-board>
<script type="module">
const board = document.getElementById('sample-board');
board.addPiece('e4', 'q', 'w');
board.addPiece('d4', 'k', 'b');
board.setCellDecorators({
e4: {
backgroundColor: '#ffeb3b',
innerBorder: 'solid 2px #d97706'
},
d4: {
backgroundColor: 'rgba(59, 130, 246, 0.25)',
innerBorder: 'solid 1px rgba(37, 99, 235, 0.8)'
}
});
board.addEventListener('cellClick', ({ detail }) => {
if (detail.square === 'e4') {
board.setCellDecorators({
e4: { backgroundColor: '#fca5a5', innerBorder: 'solid 2px #dc2626' }
});
}
});
</script>
Board Orientation
// Set orientation
board.setOrientation('white'); // White at bottom
board.setOrientation('black'); // Black at bottom
// Get orientation
const orientation = board.getOrientation(); // 'white' | 'black'
// Toggle orientation
board.toggleOrientation();
Element Attributes
chess-board supports the boolean disabled and auto-select-piece-on-click
attributes, along with fen and the boolean hide-labels attribute. Its
black-to-move attribute is managed by the orientation API and by the active color in FEN.
chess-piece supports piece, color, rotation,
fairy-name, and fairy-condition. Fairy names are limited to three characters.
fen
<chess-board fen="rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"></chess-board>
const board = document.querySelector('chess-board');
board.setFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
const fen = board.getFen();
Use the fen attribute or the setFen() API to control the board position. It accepts
both standard FEN and FFEN values.
hide-labels
<chess-board hide-labels></chess-board>
const board = document.querySelector('chess-board');
board.hideLabels = true;
board.hideLabels = false;
When enabled, the board hides square labels such as file and rank markers for a cleaner visual presentation.
disabled
<chess-board disabled></chess-board>
const board = document.querySelector('chess-board');
board.disabled = true;
board.disabled = false;
When set, the board becomes non-interactive: pointer events and keyboard actions are disabled, and selections cannot change until the attribute is removed or set to false.
auto-select-piece-on-click
<chess-board auto-select-piece-on-click></chess-board>
const board = document.querySelector('chess-board');
board.autoSelectPieceOnClick = true;
board.autoSelectPieceOnClick = false;
When enabled, clicking a piece automatically selects it, which is helpful for one-click move workflows. The
attribute can be toggled through the DOM or through the autoSelectPieceOnClick property.
FEN Support
// Set position from FEN
board.setFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
// Get current FEN
const fen = board.getFen();
// Preset positions
board.setStartingPosition(); // Standard starting position
board.clearBoard(); // Empty board
๐งฉ FFEN support
The board accepts a single fen attribute or setFen() call for either standard FEN or
FFEN. The component automatically detects the format and preserves fairy metadata when it is present.
Supported FFEN features
- Standard FEN parsing and serialization
- FFEN values with optional fairy metadata suffixes
- Neutral pieces with the
-prefix, for example-Kor-b - Rotated pieces with the
*prefix, for example*1Bor*3q - Fairy letters and numbers with the
'prefix, for example'aor''23 - Non-standard board sizes like 4x4 or 11x11 layouts (* work in progress: parsing is OK but not the renderer)
FFEN examples
// Standard FEN
board.setFen('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
// Neutral piece example
board.setFen('8/8/8/8/8/8/8/-K6 w - - 0 1');
// 90ยฐ rotation example
board.setFen('8/8/8/8/4*1B3/8/8/8 w - - 0 1');
// Fairy metadata example
board.setFen('8/8/8/8/8/8/8/4K3 w - - 0 1 e4:gn:Chameleon');
const currentState = board.getFen();
console.log(currentState);
In short, FFEN is handled as the same notation family as FEN: the same fen attribute and the same
setFen() API are used, and the component automatically applies the correct parsing logic based on
the value passed in.
โจ๏ธ Keyboard Navigation
| Keys | Action |
|---|---|
Arrow Keys |
Navigate between squares |
Space / Enter |
Select, deselect, or move the piece on the current square |
Shift + move |
Clone the selected piece while moving it |
Ctrl + move |
Clone the selected piece and invert its color |
P/R/N/B/Q/K |
Add white piece (uppercase) |
p/r/n/b/q/k |
Add black piece (lowercase) |
E/e, T/t, A/a |
Add fairy pieces (Empress, Amazon, Archbishop) |
C/c, S/s, X/x |
Add Circle (C/c) or Square (S/s) or Cross (X/x) |
Alt/Option + โ/โ |
Rotate piece ยฑ45ยฐ |
Alt/Option + โ/โ |
Reset rotation to 0ยฐ / Set to 180ยฐ |
Shift + โ/โ |
Flip board to white/black perspective |
Delete/Backspace |
Remove piece from current square |
Escape |
Clear all pieces |
Shift + Escape |
Reset to starting position |
๐ง TypeScript Support
Full TypeScript support with comprehensive type definitions:
import {
ChessBoard,
type PieceInfo,
type PieceInfoWithSquare,
type ChessPieceType,
type ChessPieceColor,
type ChessPieceRotation
} from '@dardino/chess-board';
// Type-safe piece manipulation
const board = document.querySelector('chess-board') as ChessBoard;
function addPiece(
square: string,
type: ChessPieceType,
color: ChessPieceColor,
rotation?: ChessPieceRotation
): void {
try {
board.addPiece(square, type, color, rotation);
} catch (error) {
console.error(`Failed to add piece: ${error.message}`);
}
}
// Type-safe piece information
const pieces: PieceInfoWithSquare[] = board.getAllPieces();
pieces.forEach(piece => {
console.log(`${piece.color} ${piece.type} on ${piece.square}`);
});
Available Types
| Type | Description |
|---|---|
ChessPieceType |
'k' | 'q' | 'r' | 'b' | 'n' | 'p' | 'e' | 't' | 'a' | 'x' | 's' | 'c' | `${number}` | `'${string}` | `''${string}` |
ChessPieceColor |
'w' | 'b' | 'n' |
ChessPieceRotation |
'0' | '45' | '90' | '135' | '180' | '225' | '270' | '315' |
PieceInfo |
{ type, color, rotation, fairyName, fairyCondition } |
PieceInfoWithSquare |
PieceInfo plus square: string; returned by getAllPieces() |
FenPosition |
{ pieces, activeColor, castlingRights, enPassantTarget, halfmoveClock, fullmoveNumber } |
CellDecorator |
{ backgroundColor: string, innerBorder: string } |
๐ฏ Chess Pieces
Standard Pieces
| Piece | Type | Description |
|---|---|---|
| King | k |
|
| Queen | q |
|
| Rook | r |
|
| Bishop | b |
|
| Knight | n |
|
| Pawn | p |
|
Fairy Pieces
| Piece | Type | Description |
|---|---|---|
| Empress | e |
|
| Amazon | t |
|
| Angel/Archbishop | a |
|
Symbolic Pieces
| Piece | Type | Description |
|---|---|---|
| Circle | c |
|
| Square | s |
|
| Cross | x |
|
Characters Pieces
| Piece | Type | Description |
|---|---|---|
| Fairy letter or number | Examples: 'A with color w, 'B with color b, or
'7
|
Writes the character Writes the character |
| Two-character fairy number | Example: ''23 |
Writes |
| Notes: Using letters or numbers in FFEN results in black fairy pieces by default. FFEN cannot distinguish white and black numbers, so use the Programmatic API when a character piece needs a different color. | ||
โ๏ธ Other available APIs
This library exposes several APIs for interacting with the chess board programmatically. This list is not exhaustive, and more APIs may be available.
parseFen
Function to parse a FEN or FFEN string into a FenPosition object
import { parseFen } from '@dardino/chess-board'
function parseFen(fen: string): FenPosition | null
// example usage:
const fenString = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
const parsedPosition = parseFen(fenString);
positionToFen
Converts a FenPosition to FFEN, preserving fairy metadata and normalizing metadata values.
Piece-placement utilities
import {
parsePiecePlacement,
piecesToFenString,
parseFfenPieceChar,
type PieceInfo,
type PiecesOnBoard,
type ChessPieceType,
type ChessPieceColor
} from '@dardino/chess-board';
function parsePiecePlacement(piecePlacement: string): {
pieces: PiecesOnBoard;
boardSize: { width: number; height: number };
} | null
function piecesToFenString(
pieces: PiecesOnBoard,
isFfen?: boolean,
boardSize?: { width: number; height: number }
): string
function parseFfenPieceChar(piece: string): {
type: ChessPieceType;
color: ChessPieceColor | 'n';
isNeutral: boolean;
rotation?: number;
fairyName?: string;
} | null
๐งช Testing
Comprehensive test suite with 241 tests passing
pnpm test
๐ License
MIT License - See LICENSE file for details
๐ Links
- Interactive Demo - Try all features interactively
- Programmatic API Demo - Test the TypeScript API
- GitHub Repository