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-playoff

v0.3.0

Published

A flexible and customizable React component library for rendering playoff brackets.

Readme

React Playoff

Deploy Demo Coverage

A React component library for rendering playoff brackets. It provides a flexible and customizable way to display tournament structures, allowing you to create visually appealing and interactive playoff brackets for various sports and competitions.

Demo: alicompiler.github.io/react-playoff

Tree Layout Modern Tree Layout

Wings Layout Standard Wings Layout

Features

  • Performant: Built with React and optimized for smooth interactions.
  • Dual Layouts: Supports both traditional Tree (vertical) and Wings (center-converging) layouts.
  • Interactive: Built-in support for Zooming (mouse wheel) and Panning (click and drag).
  • Fully Customizable: Override default match rendering with your own components.
  • Dynamic Styling: Easy to theme using CSS variables.
  • TypeScript Support: Full type safety for your tournament data.

Installation

npm install react-playoff
# or
yarn add react-playoff

Quick Start

import { PlayOff, Rounds } from 'react-playoff';
import 'react-playoff/dist/index.css';

const rounds: Rounds = [
    [
        { id: '1', home: { name: 'Italy' }, away: { name: 'Germany' }, nextMatchId: '3', score: [{ home: '2', away: '1' }] },
        { id: '2', home: { name: 'France' }, away: { name: 'Spain' }, nextMatchId: '3', score: [{ home: '1', away: '0' }] }
    ],
    [
        { id: '3', home : { name: 'Italy' }, away: { name: 'France' }, nextMatchId: '__final__' }
    ]
];

const App = () => (
    <div style={{ width: '100vw', height: '100vh' }}>
        <PlayOff 
            rounds={rounds} 
            layout="tree" 
            initialZoom={1.25}
        />
    </div>
);

Data Structure

The library relies on a simple hierarchical structure defined by the Rounds type.

Rounds

Rounds is an array of rounds, where each round is an array of matches. top rounds is the first round, and bottom rounds is the last round.

for example, if you have 32 teams, you will have 5 rounds: round of 32, round of 16, quarter finals, semi finals, and final.

the order of the rounds is from top to bottom.

Match Object

| Property | Type | Description | | :--- | :--- | :--- | | id | string | Unique identifier for the match. | | home | Participant | The "home" team/player object. | | away | Participant | The "away" team/player object. | | nextMatchId | string | The ID of the match where the winner moves. Use __final__ for the championship match. | | score | Array | (Optional) Array of scores (e.g., for sets or series). Format: { home: string, away: string }[]. | | metadata | Record | (Optional) Any extra data you want to pass to your custom match renderer. |

Participant Object

| Property | Type | Description | | :--- | :--- | :--- | | name | string | The name displayed for the team or player. |

Component Props

| Prop | Type | Default | Description | | :--- | :--- | :--- | :--- | | rounds | Rounds | Required | The array of rounds and matches. | | layout | 'tree' \| 'wings' | Required | The layout style of the bracket. | | renderMatch | RenderMatchFunc | DefaultMatch | Custom function to render each match component. | | renderPaths | boolean | true | Whether to draw the SVG lines connecting matches. | | initialZoom | number | 1 | Initial zoom level when the bracket first renders. |

Customization

1. Custom Match Rendering

You can completely take over how each match is displayed.

const customRender: RenderMatchFunc = (match, { selectedTeam, setSelectedTeamName }) => (
    <div className="custom-match">
        <div onClick={() => setSelectedTeamName(match.home.name)}>
            {match.home.name} - {match.score?.[0].home}
        </div>
        <div onClick={() => setSelectedTeamName(match.away.name)}>
            {match.away.name} - {match.score?.[0].away}
        </div>
    </div>
);

<PlayOff rounds={rounds} layout="wings" renderMatch={customRender} initialZoom={1.1} />

2. Styling with CSS

you can override the default styles by adding your own styles to the component.

/* class added to the root element */
.__playoff-root { }

/* classes added to the root element based on the layout */
.__playoff-layout-tree { }
.__playoff-layout-wings { }

/* class added to the root element when dragging */
.__playoff-dragging { }

/* ------------------ */

/* class added to the content element */
.__playoff-content {}


/* ------------------ */

/* class added to the svg element of the connectors */
.__playoff-connectors {}


/* ------------------ */

/* class added to the default match element */
.__playoff-default-match {}

/* class added to the home team element in the default match */
.__playoff-default-match-home {}

/* class added to the away team element in the default match */
.__playoff-default-match-away {}

/* class added to the team element when selected in the default match */
.__playoff-team-selected {}


/* ------------------ */


/* class added to the match container element */
.__playoff-match-container {}


/* ------------------ */

/* class added to the path element */
.__playoff-path {}

/* class added to the path element when highlighted */
.__playoff-path-highlighted {}


/* ------------------ */


/* class added to the round column element */
.__playoff-round-column {}

you may need to add !important to the styles to override the default styles.

Interaction

  • Zoom: Use your mouse wheel or trackpad pinch-to-zoom over the bracket area.
  • Pan: Click and drag anywhere in the empty space of the bracket to move it around.
  • Highlighting: Clicking a team name (in the default renderer) will highlight their entire path through the tournament.

Contributing

Contributions are welcome! Whether you're reporting a bug, suggesting a feature, or submitting a pull request, we appreciate your help.

Development Setup

  1. Clone the repository:
    git clone https://github.com/alicompiler/react-playoff.git
    cd react-playoff
  2. Install dependencies:
    npm install
  3. Run the development server:
    npm run dev

Testing

We use Vitest for testing. Please ensure all tests pass before submitting a PR.

npm test

Submitting a PR

  1. Fork the repository.
  2. Create a new branch: git checkout -b feature/your-feature-name.
  3. Make your changes and commit them: git commit -m 'Add some feature'.
  4. Push to the branch: git push origin feature/your-feature-name.
  5. Open a pull request.

License

MIT © [Ali]