Brackets.js is a gorgeous, responsive, single-elimination match bracket generator for net purposes.
It’s the next-generation successor to the unique jQuery Brackets.js plugin and now helps Vanilla JavaScript, jQuery, React, and Angular by means of one shared core.
The library means that you can render read-only brackets out of your software knowledge, together with winners, scores, match statuses, byes, spherical titles, and optionally available third-place matches.
Notice that it doesn’t calculate outcomes or present an editor. Your software provides the present match state.
Options:
- Nested match arrays drive read-only single-elimination bracket layouts.
- Computerized first-round padding and winner development for match byes.
- Single-result scores, multi-set scores, and superscript tie-break values.
- Scheduled, in-progress, last, retired, and walkover standing badges.
- Non-obligatory third-place matches pull rivals from semifinal losers.
- Clickable spherical navigation for specializing in later match levels.
- Constructed-in default and darkish themes with CSS customized properties.
- Stay bracket updates by means of a secure API occasion.
- TypeScript sorts for choices, gamers, matches, state, and the occasion API.
- Decreased-motion dealing with for entrance results and active-match pulses.
How To Use It
Set up
Set up the package deal from npm. The primary package deal accommodates the Vanilla JavaScript ESM construct, stylesheet, TypeScript declarations, jQuery adapter, React part, and Angular part
npm set up @ali.camargo/tournament-brackets
Fundamental Utilization
Create an empty DIV container on your match bracket:
<div id="tournament-bracket"></div>
Import the JavaScript core and stylesheet, outline the match rounds, and create the bracket:
import { Brackets } from '@ali.camargo/tournament-brackets';
import '@ali.camargo/tournament-brackets/type.css';
const rounds = [
[
{
player1: {
id: 'falcons',
name: 'Falcons',
winner: true
},
player2: {
id: 'comets',
name: 'Comets'
},
score: [3, 1],
standing: 'last'
},
{
player1: {
id: 'wolves',
identify: 'Wolves'
},
player2: {
id: 'titans',
identify: 'Titans',
winner: true
},
rating: [0, 2],
standing: 'last'
}
],
[
{
player1: {
id: 'falcons',
name: 'Falcons'
},
player2: {
id: 'titans',
name: 'Titans',
winner: true
},
score: [1, 2],
standing: 'last'
}
]
];
const bracketElement = doc.querySelector('#tournament-bracket');
const bracket = Brackets.create(bracketElement, {
rounds: rounds,
titles: true,
showScores: 'auto',
roundNav: true,
theme: 'default'
});
Event Information
Gamers
Every match accepts player1 and player2 objects. A participant can comprise these fields:
id(String | Quantity): Steady competitor identifier. Brackets.js converts it to a string internally.identify(String): Textual content displayed within the participant row.winner(Boolean): Marks this participant because the match winner whenwinnerIdis just not set on the match.url(String): Non-obligatory HTTP URL or relative path utilized to the participant identify.picture(String): Non-obligatory participant or staff picture. The picture column seems when a minimum of one participant has a picture.rating(Quantity): Non-obligatory per-player rating for a single-result match.
The primary spherical doesn’t want a power-of-two variety of populated rivals. Brackets.js pads the spherical with byes and advances unopposed gamers.
Matches
A match can comprise these fields:
player1(Participant | null): Competitor within the first slot.player2(Participant | null): Competitor within the second slot.winnerId(String | Quantity): Winner identifier. This takes priority over every participant’swinnerflag.rating(Array): Single-result, set-based, or tie-break rating knowledge.scoreType(String): Useunitsfor multi-period scores.standing(String): Match standing badge worth.
Rating Codecs
Use a two-item array for a soccer rating or one other single-result match:
const finalMatch = {
player1: { id: 'harbor', identify: 'Harbor FC', winner: true },
player2: { id: 'union', identify: 'Union FC' },
rating: [2, 1]
};
Use one rating pair per set for tennis and different multi-period codecs:
const tennisMatch = {
player1: { id: 'lee', identify: 'M. Lee', winner: true },
player2: { id: 'ortiz', identify: 'R. Ortiz' },
rating: [
[6, 4],
[3, 6],
[7, 5]
],
scoreType: 'units'
};
Nested rating pairs add superscript tie-break values:
const tieBreakMatch = {
player1: { id: 'chen', identify: 'L. Chen', winner: true },
player2: { id: 'patel', identify: 'A. Patel' },
rating: [
[[6, 7], [7, 9]],
[[7, 6], [7, 2]],
[6, 3],
[6, 4]
],
scoreType: 'units'
};
The participant rows show the primary rating and the nested additional worth as a superscript. A single-result match can even place rating instantly on each participant objects.
Match Statuses
Set standing to certainly one of these values:
scheduled: The match has not began.in_progress: The match is at present energetic.last: The result’s full.retired: A competitor retired.walkover: A competitor superior by means of a walkover.
Brackets.js infers the standing when standing is absent. A match with a winner turns into last, a match with a rating turns into in_progress, and a match with neither turns into scheduled.
All Configuration Choices
rounds(Match[][], required): Nested arrays that outline each match spherical and match.titles(Boolean | String[], defaultfalse): Settruefor computerized spherical labels or move customized labels in spherical order.thirdPlace(Boolean | Match, defaultfalse): Provides a third-place match from the semifinal losers. Move a match object to seed its gamers, rating, standing, or winner.radius(Quantity | String, default8): Units the cardboard nook radius. Numbers use pixels.0creates sq. corners.matchWidth(Quantity | String | null, defaultnull): Units the match card column width. Numbers use pixels. The stylesheet makes use of 168 pixels by default or 200 pixels when scores seem.showScores(Boolean | 'auto', default'auto'): Exhibits scores at all times, hides them, or shows them when a minimum of one match accommodates rating knowledge.roundNav(Boolean, defaultfalse): Provides clickable spherical controls. Late rounds collapse right into a mixed “Semifinals & Championship” stage.viewFromRound(Quantity, default0): Selects the primary seen spherical when spherical navigation is energetic.theme('default' | 'darkish', default'default'): Selects the built-in visible theme.labels(Object): Replaces computerized spherical, champion, third-place, late-stage, and standing textual content.onChange(Perform | null, defaultnull): Receives the serialized bracket state after spherical knowledge modifications.onRoundChange(Perform | null, defaultnull): Receives the chosen spherical index after navigation modifications.
HTML Information Attributes
4 choices can even come from attributes on the mount factor:
<div id="tournament-bracket" data-third-place="true" data-radius="12" data-match-width="220" data-round-nav="true"> </div>
Updating A Bracket
Use setRounds() after polling an API, receiving a WebSocket message, or saving an administrator replace:
async operate refreshBracket() {
const response = await fetch('/api/tournaments/summer-cup');
const knowledge = await response.json();
bracket.setRounds(knowledge.rounds, knowledge.thirdPlace);
}
The replace reuses the prevailing .jb-root factor and replaces its contents. The chosen beginning spherical stays contained in the out there spherical vary.
API Strategies
// Create a bracket and return its API occasion. const bracket = Brackets.create(factor, choices); // Substitute all match rounds. // The optionally available second argument controls the third-place match. bracket.setRounds(nextRounds, thirdPlace); // Return a serializable copy of the present state. const state = bracket.getState(); // Change the primary seen stage utilized by spherical navigation. bracket.setViewFromRound(2); // Take away occasion listeners, clear the mount factor, and launch the occasion. bracket.destroy();
Calling Brackets.create() once more on the identical factor destroys the earlier occasion earlier than mounting the substitute.
Change Callbacks
Use onChange to obtain the present serialized state after knowledge updates:
const bracket = Brackets.create(bracketElement, {
rounds: rounds,
onChange: operate (state) {
console.log(state.rounds);
}
});
Use onRoundChange to synchronize one other management with the chosen stage:
const bracket = Brackets.create(bracketElement, {
rounds: rounds,
roundNav: true,
onRoundChange: operate (roundIndex) {
doc.querySelector('#current-stage').textContent="Seen spherical: " + (roundIndex + 1);
}
});
These callbacks are option-based integration hooks. The core doesn’t dispatch customized DOM occasions.
Superior Utility Exports
The primary entry additionally exports pure knowledge and formatting helpers for purposes that handle bracket state exterior the renderer:
create(factor, choices): Standalone manufacturing facility equal toBrackets.create().normalizePlayer(participant): Normalizes a participant identifier, identify, URL, and picture.normalizeRounds(rounds, choices): Builds normalized rounds, pads byes, and returns the optionally available third-place match.setWinner(state, roundIndex, matchIndex, playerId): Returns new state with the chosen winner superior by means of later rounds.getSerializableState(state): Returns a plain state object appropriate for software storage or transport.getSemifinalRoundIndex(rounds): Returns the index of the two-match semifinal spherical.getFinalRoundIndex(rounds): Returns the ultimate spherical index.normalizeScore(rating, scoreType): Converts supported rating enter into the interior single-result or set format.resolveMatchScore(match, player1, player2): Reads rating knowledge from the match or participant objects.formatScoreForSlot(rating, slotIndex): Returns show textual content for one participant slot.appendScoreForSlot(factor, rating, slotIndex): Appends rating nodes to a goal factor.resolveMatchStatus(match): Normalizes an specific standing or infers one from the winner and rating.formatStatusLabel(standing, labels): Returns the show label for a standing worth.sanitizeUrl(worth): Accepts HTTP URLs and relative paths whereas rejecting unsupported URL schemes.formatRadius(worth): Converts numeric radii into pixel values and preserves legitimate CSS lengths.MATCH_STATUSES: Comprises the 5 accepted standing strings.
jQuery Integration
The jQuery adapter retains the plugin-style setup utilized by the unique challenge:
import $ from 'jquery';
import '@ali.camargo/tournament-brackets/jquery';
import '@ali.camargo/tournament-brackets/type.css';
$('.tournament-bracket').brackets({
rounds: rounds,
titles: true,
thirdPlace: true,
theme: 'default'
});
const bracket = $('.tournament-bracket').knowledge('brackets');
bracket.setViewFromRound(1);
React Integration
The React adapter requires react and react-dom model 17 or newer:
import { useMemo, useRef } from 'react';
import { Brackets } from '@ali.camargo/tournament-brackets/react';
import kind { BracketsApi } from '@ali.camargo/tournament-brackets';
import '@ali.camargo/tournament-brackets/type.css';
operate PlayoffBracket({ match }) {
const bracketRef = useRef<BracketsApi>(null);
const rounds = useMemo(operate () {
return match.rounds;
}, [tournament.rounds]);
return (
<Brackets
ref={bracketRef}
rounds={rounds}
titles
thirdPlace
roundNav
theme="darkish"
onChange={(state) => console.log(state)}
/>
);
}
The part props mirror the Vanilla JavaScript choices and add className and type for the host factor. Its ref exposes getState, setRounds, setViewFromRound, and destroy.
Maintain the rounds reference secure when onChange updates mum or dad state. A brand new array id triggers a dwell setRounds() replace. The viewFromRound prop units and imperatively synchronizes the beginning stage, however spherical navigation can change the interior stage till the applying passes a brand new worth or calls setViewFromRound().
Angular Integration
The Angular adapter requires @angular/core model 17 or newer and targets standalone purposes:
import { Element, ViewChild } from '@angular/core';
import { BracketsComponent } from '@ali.camargo/tournament-brackets/angular';
import kind { BracketsState } from '@ali.camargo/tournament-brackets';
import '@ali.camargo/tournament-brackets/type.css';
import { tournamentRounds } from './tournament-data';
@Element({
standalone: true,
imports: [BracketsComponent],
template: `
<tb-brackets
[rounds]="rounds"
theme="darkish"
[titles]="true"
[thirdPlace]="true"
[roundNav]="true"
(change)="handleChange($occasion)"
(roundChange)="handleRoundChange($occasion)"
/>
`
})
export class PlayoffPage {
@ViewChild(BracketsComponent) brackets!: BracketsComponent;
rounds = tournamentRounds;
handleChange(state: BracketsState) {
console.log(state);
}
handleRoundChange(roundIndex: quantity) {
console.log(roundIndex);
}
}
The part inputs mirror the core choices and add class and type on the host wrapper. The change and roundChange outputs expose the 2 core callbacks. @ViewChild gives the identical 4 occasion strategies because the React ref.
Styling And Customization
Choose the built-in darkish theme by means of the theme possibility:
const bracket = Brackets.create(bracketElement, {
rounds: rounds,
theme: 'darkish'
});
Override the documented CSS customized properties on .jb-root for a project-specific theme:
.jb-root {
--jb-bg: #f3f5f7;
--jb-surface: #ffffff;
--jb-border: #bcc7d1;
--jb-text: #17212b;
--jb-accent: #2457d6;
--jb-winner: #147a4b;
--jb-radius: 10px;
}
radius and matchWidth additionally set instance-level sizing values. Match playing cards with scores use a wider default column.
The renderer provides a brief left-to-right entrance impact after every paint. Matches with in_progress standing use a delicate badge pulse. Each results cease below prefers-reduced-motion: cut back.
Options:
FAQs:
Q: Can customers click on on a match to advance a winner?
A: No. Brackets.js is a learn‑solely show part. To replace the bracket, modify your spherical knowledge and name api.setRounds(newRounds). The bracket re‑renders with the brand new winners and scores.
Q: How do I present dwell in‑progress matches?
A: Set standing: 'in_progress' on a match object. In the event you solely present a rating with out a winner, the standing is robotically inferred as in_progress. The badge pulses subtly to point dwell play.
Q: Does Brackets.js help double‑elimination or spherical‑robin?
A: No. The library is designed completely for single‑elimination tournaments. Double‑elimination and group levels aren’t supported within the present model.
Q: Is there a Vue adapter?
A: A Vue adapter is on the challenge highwaymap however not but launched. For now, you should use the vanilla core instantly in a Vue part by mounting it within the mounted hook and calling destroy in beforeUnmount.
Q: What occurs when the primary spherical doesn’t comprise a power-of-two subject?
A: Brackets.js pads the primary spherical with byes. A participant with no opponent advances to the subsequent spherical robotically.
Q: Why did content material contained in the bracket container disappear after an replace?
A: The renderer replaces the mount factor’s kids throughout every paint. Maintain captions, buttons, and different interface parts exterior the mount factor.
Changelog:
2026-07-31
2015-06-27
2015-06-09
This superior jQuery plugin is developed by aliCamargoM. For extra Superior Usages, please test the demo web page or go to the official web site.

