React chessboard component with drag & drop, animation, and theming. Bundled cburnett piece set, zero external dependencies beyond React.
npm install @echecs/react-board
# or
pnpm add @echecs/react-boardPeer dependencies: React ≥18, @echecs/position ≥3.
import{Board}from'@echecs/react-board';exportfunctionApp(){return<Board/>;}import{useState}from'react';import{Board}from'@echecs/react-board';importtype{MoveEvent}from'@echecs/react-board';constSTARTING_FEN='rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';exportfunctionChessGame(){const[position,setPosition]=useState(STARTING_FEN);const[orientation,setOrientation]=useState<'white'|'black'>('white');functionhandleMove(event: MoveEvent): boolean{// validate and apply move, then update position// return false to reject the movereturntrue;}return(<divstyle={{width: 480}}><Boardanimatecoordinatesorientation={orientation}position={position}onMove={handleMove}/><buttononClick={()=>setOrientation((o)=>(o==='white' ? 'black' : 'white'))}>
Flip board
</button></div>);}| Prop | Type | Default | Description |
|---|---|---|---|
animate | boolean | true | Enable CSS transition animation on piece moves |
arrows | Arrow[] | — | Arrows to render on the board |
children | React.ReactNode | — | Content rendered inside the board grid |
coordinates | boolean | true | Show rank/file coordinate labels |
highlight | Square[] | [] | Squares to highlight with an overlay |
interactive | boolean | true | Enable drag & drop and click-to-move |
legalMoves | Map<Square, Square[]> | — | Legal move map — restricts user interaction |
onMove | (move: MoveEvent) => boolean | — | Called on every attempted move; return false to reject |
onSquareClick | (square: Square) => void | — | Called when a square is clicked |
orientation | 'white' | 'black' | 'white' | Which side is at the bottom |
pieces | PieceSet | DEFAULT_PIECES | Custom piece component record |
position | string | Map<Square, Piece> | starting position | FEN string or position map |
turn | 'white' | 'black' | — | Restrict interaction to one colour's pieces |
All visual styling is controlled via CSS custom properties. Set them on a parent element or directly on the board container to override defaults.
.my-board {
--board-dark-square:#b58863;
--board-light-square:#f0d9b5;
--board-highlight:rgba(20,85,30,0.5);
--board-legal-dot:rgba(0,0,0,0.3);
}| Variable | Default | Description |
|---|---|---|
--board-dark-square | #779952 | Dark square colour |
--board-light-square | #edeed1 | Light square colour |
--board-highlight | rgba(255, 255, 0, 0.4) | Highlight overlay colour |
--board-legal-dot | rgba(0, 0, 0, 0.2) | Legal move dot colour |
--board-coordinate-on-light | #779952 | Coordinate text on light squares |
--board-coordinate-on-dark | #edeed1 | Coordinate text on dark squares |
--board-coordinate-weight | 600 | Coordinate font weight |
--board-promotion-background | rgba(0, 0, 0, 0.6) | Promotion dialog background |
--board-drag-shadow | drop-shadow(0 4px 8px rgba(0,0,0,0.4)) | Drag ghost filter |
--board-piece-transition | transform 200ms ease | Piece move animation transition |
Supply a PieceSet record mapping piece keys to image URLs (any format the
browser can render as a CSS background-image — data URIs, SVG files, PNGs):
import{DEFAULT_PIECES}from'@echecs/react-board';importtype{PieceSet}from'@echecs/react-board';constmyPieces: PieceSet={
...DEFAULT_PIECES,wP: '/assets/pieces/white-pawn.svg',};<Boardpieces={myPieces}/>;Piece key format: 'b' | 'w' + 'B' | 'K' | 'N' | 'P' | 'Q' | 'R' (e.g. 'wK'
= white king, 'bP' = black pawn).
Bundled move sounds (Lichess standard set, MIT licensed). Import via subpath:
importmoveSoundfrom'@echecs/react-board/sounds/move.mp3';importcaptureSoundfrom'@echecs/react-board/sounds/capture.mp3';importcastleSoundfrom'@echecs/react-board/sounds/castle.mp3';importcheckSoundfrom'@echecs/react-board/sounds/check.mp3';importgameEndSoundfrom'@echecs/react-board/sounds/game-end.mp3';| Subpath export | Description |
|---|---|
@echecs/react-board/sounds/move.mp3 | Standard piece move |
@echecs/react-board/sounds/capture.mp3 | Piece capture |
@echecs/react-board/sounds/castle.mp3 | Castling move |
@echecs/react-board/sounds/check.mp3 | Check |
@echecs/react-board/sounds/game-end.mp3 | Game over |
PromotionDialog is exported separately for cases where you manage promotion
state yourself:
import{PromotionDialog}from'@echecs/react-board';<PromotionDialogcolor="white"squareSize={60}onSelect={(piece)=>console.log(piece)}// 'queen' | 'rook' | 'bishop' | 'knight'onCancel={()=>console.log('cancelled')}/>;| Prop | Type | Default | Description |
|---|---|---|---|
color | 'white' | 'black' | — | Which colour is promoting |
onCancel | () => void | — | Optional. Called when dismissed |
onSelect | (piece: PromotionPiece) => void | — | Called when a piece is clicked |
pieces | PieceSet | DEFAULT_PIECES | Piece component set |
squareSize | number | — | Square size in pixels |
Returns { col, row } — 1-based CSS grid coordinates for square given the
board orientation.
import{squareCoords}from'@echecs/react-board';squareCoords('e4','white');// { col: 5, row: 5 }squareCoords('e4','black');// { col: 4, row: 4 }| Type | Description |
|---|---|
Annotations | { arrows: Arrow[]; circles: Circle[] } — drawable annotation state |
Arrow | { from: Square; to: Square; kind: ArrowKind } — arrow descriptor |
ArrowKind | 'alternative' | 'capture' | 'danger' | 'move' — annotation colour |
BoardProps | All props accepted by <Board /> |
Circle | { square: Square; kind: ArrowKind } — circle annotation descriptor |
Color | 'black' | 'white' — piece colour (from @echecs/position) |
File | 'a' | 'b' | … | 'h' — board file (from @echecs/position) |
MoveEvent | { from, to, capture, promotion? } — passed to onMove |
Piece | { color: Color; type: PieceType } — piece on a square |
PieceKey | Union of all 12 piece keys ('wK', 'bP', …) |
PieceSet | Record<PieceKey, string> — maps piece keys to image URLs |
PieceType | 'bishop' | 'king' | … | 'rook' — piece type (from @echecs/position) |
PromotionDialogProps | All props accepted by <PromotionDialog /> |
PromotionPiece | 'bishop' | 'knight' | 'queen' | 'rook' — promotable piece |
Rank | '1' | '2' | … | '8' — board rank (from @echecs/position) |
Square | `${File}${Rank}` — board square (from @echecs/position) |
SquareCoords | { col: number; row: number } — return type of squareCoords |
MIT