npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@react-chess-tools/react-chess-clock

v1.0.2

Published

A standalone chess clock component for React with support for multiple timing methods (Fischer, delay, Bronstein) and seamless integration with react-chess-game.

Downloads

166

Readme

npm version npm downloads License: MIT TypeScript

Table of Contents

Overview

@react-chess-tools/react-chess-clock is a React component for creating chess clocks with support for multiple timing methods (Fischer increment, simple delay, Bronstein delay), multi-period tournament controls, and various clock start modes.

Built using a compound component pattern (similar to Radix UI), it provides an unstyled, fully customizable clock with sensible defaults.

Features

  • Multiple Timing Methods - Fischer increment, simple delay, and Bronstein delay
  • Tournament Controls - Multi-period time controls with move counts (FIDE/USCF style)
  • Clock Start Modes - Delayed (Lichess-style), immediate (Chess.com-style), or manual
  • Time Odds - Support for different starting times per player
  • Flexible Time Control - String notation ("5+3"), object config, or multi-period array
  • Server Sync - Built-in methods for syncing clock state with a server
  • TypeScript - Full TypeScript support with comprehensive type definitions
  • Unstyled - Zero runtime CSS with data attributes for easy styling

Installation

npm install @react-chess-tools/react-chess-clock
yarn add @react-chess-tools/react-chess-clock
pnpm add @react-chess-tools/react-chess-clock

Quick Start

import { ChessClock } from "@react-chess-tools/react-chess-clock";

function App() {
  return (
    <ChessClock.Root timeControl={{ time: "5+3" }}>
      <ChessClock.Display color="white" />
      <ChessClock.Display color="black" />
      <ChessClock.Switch>Switch</ChessClock.Switch>
      <ChessClock.PlayPause />
      <ChessClock.Reset>Reset</ChessClock.Reset>
    </ChessClock.Root>
  );
}

Demo

Visit the live demo to see the component in action.

API Reference

ChessClock.Root

The root component that provides ChessClockContext to all child components.

Note: This is a logic-only component (Context Provider). It does not render any DOM elements.

Props

| Name | Type | Default | Description | | ------------- | ------------------- | ------- | ------------------------------------- | | timeControl | TimeControlConfig | - | Time control configuration (required) | | children | ReactNode | - | Child components |

TimeControlConfig

| Property | Type | Default | Description | | -------------- | --------------------------------------------------- | ----------- | --------------------------------------------------------- | | time | TimeControlInput | - | Time specification (string, object, or array) | | timingMethod | "fischer" \| "delay" \| "bronstein" | "fischer" | How time is added/removed after each move | | clockStart | "delayed" \| "immediate" \| "manual" | "delayed" | When the clock starts running | | whiteTime | number | - | Override White's starting time in seconds (for time odds) | | blackTime | number | - | Override Black's starting time in seconds (for time odds) | | onTimeout | (loser: ClockColor) => void | - | Callback when a player's time runs out | | onSwitch | (activePlayer: ClockColor) => void | - | Callback when active player switches | | onTimeUpdate | (times: { white: number; black: number }) => void | - | Callback on each time update |

Example

<ChessClock.Root
  timeControl={{
    time: "5+3",
    timingMethod: "fischer",
    clockStart: "delayed",
    onTimeout: (loser) => console.log(`${loser} loses on time`),
  }}
>
  <ChessClock.Display color="white" />
  <ChessClock.Display color="black" />
</ChessClock.Root>

ChessClock.Display

Displays the current time for a player. Renders an unstyled div with data attributes for styling.

Supports ref forwarding and all standard HTML div attributes (className, style, id, data-, aria-, etc.).

Props

| Name | Type | Description | | ------------ | ------------------------------------------- | -------------------------------------------------- | | color | "white" \| "black" | Player color to display (required) | | format | "auto" \| "mm:ss" \| "ss.d" \| "hh:mm:ss" | Time format (default: "auto") | | formatTime | (milliseconds: number) => string | Custom time formatting function (overrides format) | | ref | Ref<HTMLDivElement> | Forwarded ref to the wrapper div element | | className | string | Custom CSS class names | | style | CSSProperties | Custom inline styles | | ... | HTMLAttributes<HTMLDivElement> | All standard HTML div attributes |

Data Attributes

| Attribute | Value | Description | | -------------------- | ---------------------- | ------------------------------------------------ | | data-clock-color | "white" or "black" | Which player's time is shown | | data-clock-active | "true" or "false" | Whether this player's clock is currently running | | data-clock-paused | "true" or "false" | Whether the clock is paused | | data-clock-timeout | "true" or "false" | Whether this player has run out of time | | data-clock-status | Clock status string | Current clock status |

Example

<ChessClock.Display
  color="white"
  format="auto"
  className="clock-display"
  style={{ fontFamily: "monospace", fontSize: "24px" }}
/>

ChessClock.Switch

A button that manually switches the active player's clock.

Supports ref forwarding, asChild pattern, and all standard HTML button attributes (className, style, disabled, etc.).

Props

| Name | Type | Description | | ----------- | ----------------------------------------- | -------------------------------------- | | asChild | boolean | Render as child element (slot pattern) | | ref | Ref<HTMLButtonElement> | Forwarded ref to the button element | | className | string | Custom CSS class names | | ... | ButtonHTMLAttributes<HTMLButtonElement> | All standard HTML button attributes |

Note: The button is disabled when the clock status is "idle" or "finished".

Example

<ChessClock.Switch>Switch Turn</ChessClock.Switch>

Using asChild Pattern

<ChessClock.Switch asChild>
  <div className="custom-switch">Switch</div>
</ChessClock.Switch>

ChessClock.PlayPause

A button to start, pause, and resume the clock. Content changes based on clock state.

Supports ref forwarding, asChild pattern, and all standard HTML button attributes (className, style, disabled, etc.).

Props

| Name | Type | Default | Description | | ----------------- | ----------------------------------------- | ----------------------------------- | ------------------------------------------- | | startContent | ReactNode | "Start" | Content shown when clock is idle | | pauseContent | ReactNode | "Pause" | Content shown when clock is running | | resumeContent | ReactNode | "Resume" | Content shown when clock is paused | | delayedContent | ReactNode | "Start" | Content shown when clock is in delayed mode | | finishedContent | ReactNode | "Game Over" | Content shown when clock is finished | | asChild | boolean | false | Render as child element (slot pattern) | | ref | Ref<HTMLButtonElement> | Forwarded ref to the button element | | className | string | Custom CSS class names | | ... | ButtonHTMLAttributes<HTMLButtonElement> | All standard HTML button attributes |

Note: The button is disabled when the clock status is "finished" or "delayed".

Example

<ChessClock.PlayPause
  startContent="Start Game"
  pauseContent="Pause"
  resumeContent="Resume"
  finishedContent="Game Over"
/>

Using asChild Pattern

<ChessClock.PlayPause asChild>
  <button className="custom-play-pause">Toggle</button>
</ChessClock.PlayPause>

ChessClock.Reset

A button that resets the clock. Optionally accepts a new time control.

Supports ref forwarding, asChild pattern, and all standard HTML button attributes (className, style, disabled, etc.).

Props

| Name | Type | Description | | ------------- | ----------------------------------------- | --------------------------------------------- | | timeControl | TimeControlInput | New time control to apply on reset (optional) | | asChild | boolean | Render as child element (slot pattern) | | ref | Ref<HTMLButtonElement> | Forwarded ref to the button element | | className | string | Custom CSS class names | | ... | ButtonHTMLAttributes<HTMLButtonElement> | All standard HTML button attributes |

Note: The button is disabled when the clock status is "idle".

Example

// Reset with same time control
<ChessClock.Reset>Reset</ChessClock.Reset>

// Reset with new time control
<ChessClock.Reset timeControl="10+5">Change to 10+5</ChessClock.Reset>

Using asChild Pattern

<ChessClock.Reset asChild>
  <div className="custom-reset">Reset</div>
</ChessClock.Reset>

Hooks

useChessClock

Create clock state without the Root component (for custom integrations).

import { useChessClock } from "@react-chess-tools/react-chess-clock";

function MyClock() {
  const clock = useChessClock({
    time: "5+3",
    onTimeout: (loser) => console.log(`${loser} loses`),
  });

  return (
    <div>
      <div>White: {clock.times.white}ms</div>
      <div>Black: {clock.times.black}ms</div>
      <button onClick={clock.methods.switch}>Switch</button>
    </div>
  );
}

Return Values

| Property | Type | Description | | -------------------- | ------------------------------------------------------ | ----------------------------------- | | times | { white: number; black: number } | Current times in milliseconds | | initialTimes | { white: number; black: number } | Initial times in milliseconds | | status | ClockStatus | Current clock status | | activePlayer | "white" \| "black" \| null | Currently active player | | timeout | "white" \| "black" \| null | Which player timed out | | timingMethod | TimingMethod | Configured timing method | | info | ClockInfo | Computed clock information | | currentPeriodIndex | { white: number; black: number } | Current period index (multi-period) | | totalPeriods | number | Total number of periods | | currentPeriod | { white: TimeControlPhase; black: TimeControlPhase } | Current periods | | periodMoves | { white: number; black: number } | Moves in current period | | methods | ClockMethods | Methods to control the clock |

Methods

| Method | Type | Description | | --------- | ---------------------------------------------------- | -------------------------------------------------- | | start | () => void | Start the clock | | pause | () => void | Pause the clock | | resume | () => void | Resume the clock | | switch | () => void | Switch active player | | reset | (timeControl?: TimeControlInput) => void | Reset the clock (optionally with new time control) | | addTime | (player: ClockColor, milliseconds: number) => void | Add time to a player | | setTime | (player: ClockColor, milliseconds: number) => void | Set a player's time |

useChessClockContext

Access the clock state from any child component within a ChessClock.Root.

import { useChessClockContext } from "@react-chess-tools/react-chess-clock";

function ClockInfo() {
  const { times, activePlayer, status, methods } = useChessClockContext();

  return (
    <div>
      <p>Active: {activePlayer}</p>
      <p>Status: {status}</p>
      <button onClick={() => methods.pause()}>Pause</button>
    </div>
  );
}

useOptionalChessClock

Safely access clock context when the component may be used outside ChessClock.Root.

import { useOptionalChessClock } from "@react-chess-tools/react-chess-clock";

function MaybeInsideClock() {
  const clock = useOptionalChessClock();

  if (!clock) {
    return <div>No clock context</div>;
  }

  return <div>White time: {clock.times.white}</div>;
}

Time Control Formats

String Notation

Compact string format for simple time controls:

// "minutes+seconds" format
timeControl={{ time: "5+3" }}   // 5 minutes, 3 second increment
timeControl={{ time: "10" }}    // 10 minutes, no increment
timeControl={{ time: "3+2" }}   // 3 minutes, 2 second increment

Object Configuration

Full control over timing parameters:

timeControl={{
  time: {
    baseTime: 300,    // Base time in seconds
    increment: 3,     // Increment in seconds (Fischer/Bronstein)
    delay: 5,         // Delay in seconds (delay/Bronstein methods)
  },
}}

Multi-Period Tournament Controls

FIDE/USCF style tournament time controls with move counts:

timeControl={{
  time: [
    { baseTime: 5400, increment: 30, moves: 40 },  // 90min + 30sec/move for 40 moves
    { baseTime: 1800, increment: 30, moves: 20 },  // 30min + 30sec/move for 20 moves
    { baseTime: 900, increment: 30 },              // 15min + 30sec/move sudden death
  ],
  clockStart: "manual",
}}

Presets

Common time control presets are available:

import { presets } from "@react-chess-tools/react-chess-clock";

timeControl={{ time: presets.blitz5_3 }}
timeControl={{ time: presets.fideClassical }}

Available presets:

  • Bullet: bullet1_0, bullet1_1, bullet2_1
  • Blitz: blitz3_0, blitz3_2, blitz5_0, blitz5_3
  • Rapid: rapid10_0, rapid10_5, rapid15_10
  • Classical: classical30_0, classical90_30
  • Tournament: fideClassical, uscfClassical

Timing Methods

Fischer (Default)

Standard increment - time is added after each move completes.

timeControl={{
  time: { baseTime: 300, increment: 3 },
  timingMethod: "fischer",
}}

Simple Delay

Countdown waits for the delay period before decrementing. If you move within the delay, no time is used.

timeControl={{
  time: { baseTime: 300, delay: 5 },
  timingMethod: "delay",
}}

Bronstein Delay

Adds back the actual time used, up to the delay amount. Like delay but you always get at least the delay amount back.

timeControl={{
  time: { baseTime: 300, delay: 3 },
  timingMethod: "bronstein",
}}

Clock Start Modes

Delayed (Default - Lichess style)

Clock doesn't start until after Black's first move.

timeControl={{ time: "5+3", clockStart: "delayed" }}

Sequence: White moves → Black moves → Clock starts for White

Immediate (Chess.com style)

White's clock starts immediately on the first switch.

timeControl={{ time: "5+3", clockStart: "immediate" }}

Manual

Clock starts only when user explicitly calls start().

timeControl={{ time: "5+3", clockStart: "manual" }}

Examples

Basic Clock

import { ChessClock } from "@react-chess-tools/react-chess-clock";

function BasicClock() {
  return (
    <ChessClock.Root timeControl={{ time: "5+3" }}>
      <ChessClock.Display color="white" />
      <ChessClock.Display color="black" />
      <ChessClock.PlayPause />
      <ChessClock.Reset>Reset</ChessClock.Reset>
    </ChessClock.Root>
  );
}

Time Odds

Give one player less time:

function TimeOddsClock() {
  return (
    <ChessClock.Root
      timeControl={{
        time: "5+3",
        whiteTime: 180, // White gets 3 minutes
        blackTime: 300, // Black gets 5 minutes
      }}
    >
      <ChessClock.Display color="white" />
      <ChessClock.Display color="black" />
      <ChessClock.PlayPause />
    </ChessClock.Root>
  );
}

Tournament Control

FIDE Classical time control:

function TournamentClock() {
  return (
    <ChessClock.Root
      timeControl={{
        time: [
          { baseTime: 5400, increment: 30, moves: 40 },
          { baseTime: 1800, increment: 30, moves: 20 },
          { baseTime: 900, increment: 30 },
        ],
        clockStart: "manual",
      }}
    >
      <ChessClock.Display color="white" />
      <ChessClock.Display color="black" />
      <ChessClock.PlayPause />
      <ChessClock.Reset>Reset</ChessClock.Reset>
    </ChessClock.Root>
  );
}

Styled Clock

Using data attributes for styling:

function StyledClock() {
  return (
    <ChessClock.Root timeControl={{ time: "5+3" }}>
      <ChessClock.Display
        color="white"
        className="clock-display"
        style={{ padding: "10px 20px", fontSize: "24px" }}
      />
      <ChessClock.Display
        color="black"
        className="clock-display"
        style={{ padding: "10px 20px", fontSize: "24px" }}
      />
      <ChessClock.PlayPause />
    </ChessClock.Root>
  );
}
/* CSS */
.clock-display {
  font-family: monospace;
  border: 2px solid #333;
  border-radius: 4px;
}

[data-clock-color="white"] {
  background: white;
  color: black;
}

[data-clock-color="black"] {
  background: black;
  color: white;
}

[data-clock-active="true"] {
  border-color: gold;
  box-shadow: 0 0 10px gold;
}

[data-clock-timeout="true"] {
  background: red;
  color: white;
}

Server Synchronization

For online play, sync clock state with server times:

function ServerSyncedClock() {
  const { times, methods } = useChessClockContext();
  const [serverTime, setServerTime] = useState({
    white: 300000,
    black: 300000,
  });

  // Sync time from server
  useEffect(() => {
    const interval = setInterval(() => {
      // Fetch from server...
      methods.setTime("white", serverTime.white);
      methods.setTime("black", serverTime.black);
    }, 1000);
    return () => clearInterval(interval);
  }, [serverTime, methods]);

  return (
    <>
      <ChessClock.Display color="white" />
      <ChessClock.Display color="black" />
    </>
  );
}

Custom Status Display

import { useChessClockContext } from "@react-chess-tools/react-chess-clock";

function ClockStatus() {
  const { status, activePlayer, times } = useChessClockContext();

  const formatTime = (ms: number) => {
    const seconds = Math.floor(ms / 1000);
    const minutes = Math.floor(seconds / 60);
    const secs = seconds % 60;
    return `${minutes}:${secs.toString().padStart(2, "0")}`;
  };

  if (status === "finished") {
    return <div className="status">Game Over - Time forfeit</div>;
  }

  return (
    <div className="status">
      <p>Active: {activePlayer === "white" ? "White" : "Black"}</p>
      <p>White: {formatTime(times.white)}</p>
      <p>Black: {formatTime(times.black)}</p>
    </div>
  );
}

function ClockWithStatus() {
  return (
    <ChessClock.Root timeControl={{ time: "5+3" }}>
      <ClockStatus />
      <ChessClock.Display color="white" />
      <ChessClock.Display color="black" />
      <ChessClock.PlayPause />
      <ChessClock.Reset>Reset</ChessClock.Reset>
    </ChessClock.Root>
  );
}

License

This project is MIT licensed.

Show Your Support

Give a star if this project helped you!