Skip to Content
react-brackets

Building from parts

Compose every part of the bracket yourself, and read its state with hooks.

<Bracket> renders a default set of parts. Write them out yourself to change the structure, wrap parts in your own elements, or leave some out:

<Bracket.Root stage={stage} onMatchClick={open}>
  <Bracket.GroupTitle />
  <Bracket.Viewport mode="pan-zoom">
    <Bracket.Rounds>
      {(column) => (
        <Bracket.Round>
          <Bracket.RoundTitle />
          <Bracket.Matches>{(match) => <MyMatch match={match} />}</Bracket.Matches>
        </Bracket.Round>
      )}
    </Bracket.Rounds>
    <Bracket.Connectors radius={8}>
      {() => <Bracket.Connector strokeDasharray="4 4" />}
    </Bracket.Connectors>
  </Bracket.Viewport>
  <Bracket.Pagination />
</Bracket.Root>

This is what <Bracket> renders, written out. The shortcut props map onto it:

<Bracket> propComposed equivalent
renderMatchchildren of Bracket.Matches
connectorRadiusradius on Bracket.Connectors
renderConnectorchildren of Bracket.Connectors
connectorDefsdefs on Bracket.Connectors
modemode on Bracket.Viewport
everything elsethe same prop on Bracket.Root

The parts

PartRendersChildren
Bracket.Rootthe bracket and its stateanything
Bracket.GroupTitlethe group's namereplace the name
Bracket.Viewportthe scrolling, scaled or paged windowthe rounds and connectors
Bracket.Roundsevery columna function of the column
Bracket.Roundone columnthe title and matches
Bracket.RoundTitlethe round's namereplace the name
Bracket.Matchesthe matches in a columna function of the match
Bracket.Matchone match cardanything, usually two participants
Bracket.Participantone side of a matcha function of its state, or anything
Bracket.Connectorsthe SVG with every linea function of the line
Bracket.Connectorone linenone
Bracket.Paginationround navigation on narrow containersnone

Each one's props are in the parts reference.

Rules of thumb

  • Keep Bracket.Rounds and Bracket.Connectors inside Bracket.Viewport. Lines are measured within it.
  • Keep Bracket.Match around each card. Lines attach to it, and paging and clicks go through it.
  • Anything else can go anywhere inside Bracket.Root: a header above the viewport, a legend below it, a sidebar beside it.
  • Bracket.Root draws one group. For a stage with several, like double elimination, render one root per group with group="main.lb", or several on one grid, like the winners bracket and its grand final with group={['main.wb', 'main.gf']}. <Bracket> does this for you.

Hooks

Inside the root, hooks give your own components the same state the parts use:

HookWhereReturns
useBracket()anywhere inside Bracket.Rootthe stage, group, rounds, participants, page, highlighted participant and more
useBracketCell()inside Bracket.Matchesthe match being rendered and its place on the grid
useConnector()inside Bracket.Connectorsthe line being rendered

A legend that names the highlighted team, for example:

function Following() {
  const { highlighted, participants, highlight } = useBracket();
  const team = highlighted ? participants.get(highlighted) : undefined;
  if (!team) return null;
  return (
    <p>
      Following {team.name} <button onClick={() => highlight(null)}>Clear</button>
    </p>
  );
}

See hooks and types for everything they return.

On this page