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 🙏

© 2025 – Pkg Stats / Ryan Hefner

vueckets

v1.0.6

Published

Customizable Vue component for rendering single elimination tournament brackets.

Readme

Vueckets 🏆

Vueckets is a clean and minimal Vue 3 component for rendering single-elimination brackets, with built‑in support for battle royale style matches (3+ teams per match).

✨ Features

  • Battle royale mode: Auto-switches to a list view when any match has more than two teams
  • Round title controls: Easily customize round title colors, borders, and min width
  • Customizable list view: Tweak tab, table head, and border colors via props
  • Responsive: Works across screen sizes, battle royale list is full width
  • Winner/defeated states: Built-in visual states you can extend with custom classes
  • Flexible data: Rounds-based or flat tree inputs

🚀 Installation

npm install vueckets

📋 Basic Usage

<template>
  <vueckets :rounds="rounds">
    <template #team="{ team }">
      {{ team.name }}
    </template>
  </vueckets>
  </template>

<script>
import Vueckets from 'vueckets';

export default {
  components: {
    Vueckets
  },
  data() {
    return {
      rounds: [
        {
          // Classic 1v1 round
          matches: [
            {
              team1: { id: '1', name: 'Team A', winner: true },
              team2: { id: '2', name: 'Team B', winner: false }
            }
          ]
        }
      ]
    };
  }
};
</script>

🎨 Styling with Props (no themes)

Pass simple props to style everything. No global themes required.

Core layout and colors

| Prop | Type | Default | What it controls | |------|------|---------|------------------| | backgroundColor | String | #ffffff | Match box background (classic 1v1) | | textColor | String | #ffffff | Text color inside match boxes | | winnerColor | String | #501696 | Background for winners (classic 1v1) | | defeatedColor | String | #501696 | Background for defeated (classic 1v1) | | borderColor | String | #501696 | Border color for match boxes and separators | | borderRadius | String | 6px | Radius for match boxes and titles | | spacing | String | 12px | Vertical spacing between items/rounds | | fontSize | String | 14px | Base font size | | playerPadding | String | 8px 12px | Padding inside match boxes | | teamPadding | String | 8px 12px | Padding inside team boxes (overrides playerPadding) |

Bracket connections (classic)

| Prop | Type | Default | What it controls | |------|------|---------|------------------| | connectionColor | String | #85E642 | Color of connection lines between matches | | connectionWidth | String | 24px | Horizontal connection line length | | connectionThickness | String | 1px | Connection line thickness |

Round titles

| Prop | Type | Default | What it controls | |------|------|---------|------------------| | roundTitleColor | String | #64748b | Title text color | | roundTitleBgColor | String | #f8fafc | Title background | | roundTitleBorderColor | String | #e2e8f0 | Title border | | roundTitleMinWidth | String | 177px | Title column min-width |

Team hover effects

| Prop | Type | Default | What it controls | |------|------|---------|------------------| | winnerTeamHover | String | rgba(0, 0, 0, 0.1) | Hover color for winning teams | | defeatedTeamHover | String | rgba(0, 0, 0, 0.1) | Hover color for defeated teams |

Scrollbar customization

| Prop | Type | Default | What it controls | |------|------|---------|------------------| | scrollbarColor | String | #cbd5e1 | Main scrollbar color | | scrollbarTrackColor | String | #f1f5f9 | Scrollbar track background |

Battle royale – tabs (Rounds/Matches)

| Prop | Type | Default | |------|------|---------| | brTabBg | String | #1A1A1A | | brTabTextColor | String | #ffffff | | brTabActiveBg | String | #8200DB | | brTabActiveTextColor | String | #ffffff |

Battle royale – table header

| Prop | Type | Default | |------|------|---------| | brTableHeadBg | String | #1C1C1C | | brTableHeadTextColor | String | #ffffff |

Battle royale – team list

| Prop | Type | Default | What it controls | |------|------|---------|------------------| | brListBg | String | #000000 | List background | | brListTextColor | String | #ffffff | Text color in list | | brListRowBg | String | '' | Individual row background (falls back to brListBg) | | brListRowHoverBg | String | '' | Row hover background (falls back to #2A2A2A) | | brRowDividerColor | String | #1C1C1C | Row divider lines |

Utility

| Prop | Type | Default | Notes | |------|------|---------|------| | rounds | Array | [] | Primary input (supports classic matches with team1/team2, or teams array for battle royale) | | flatTree | Array | [] | Alternative input format (flat) | | wrapperClass | String | '' | Extra classes on root wrapper | | wrapperStyle | Object | {} | Inline styles for root wrapper | | customClasses | Object | {} | { wrapper, item, itemParent, itemChild, player, winner, defeated, team } overrides |

You can pass only what you need; everything has sensible defaults.

📚 API Reference

See the props tables above. Most styles can be changed at runtime by binding reactive values.

Custom Styles Object

{
  backgroundColor: '#999999',           // Player container background
  textColor: 'white',                  // Text color
  winnerColor: 'darkgreen',            // Winner background color
  defeatedColor: 'firebrick',          // Defeated player background color
  winnerTeamHover: 'rgba(0,0,0,0.1)', // Winner hover color
  defeatedTeamHover: 'rgba(0,0,0,0.1)', // Defeated hover color
  connectionColor: 'gray',             // Bracket connection lines color
  borderRadius: '0px',                 // Border radius for player containers
  spacing: '10px',                     // Spacing between elements
  fontSize: '14px',                    // Font size
  teamPadding: '8px 12px',            // Team padding (overrides playerPadding)
  scrollbarColor: '#cbd5e1',          // Scrollbar color
  scrollbarTrackColor: '#f1f5f9'      // Scrollbar track color
}

Custom Classes Object

{
  wrapper: '',        // Wrapper container class
  item: '',          // Bracket item class
  itemParent: '',    // Parent bracket item class
  itemChild: '',     // Child bracket item class
  player: '',        // Player container class
  winner: '',        // Winner player class
  defeated: ''       // Defeated player class
}

Data Structure

Classic 1v1

[
  {
    matches: [
      {
        team1: { id: '1', name: 'Team A', winner: true },
        team2: { id: '2', name: 'Team B', winner: false }
      }
    ]
  }
]

Battle Royale (3+ teams)

[
  {
    name: 'Group Stage',
    matches: [
      {
        teams: [
          { id: 't1', name: 'Team 1', points: 10 },
          { id: 't2', name: 'Team 2', points: 14 },
          { id: 't3', name: 'Team 3', points: 9 }
        ]
      }
    ]
  }
]

Team Object shape

type Team = {
  id: string | number
  name: string
  // optional fields
  winner?: boolean        // true when team won the match
  points?: number         // numeric points shown in battle royale list (also supported in classic)
};

Notes:

  • In classic (1v1), put optional points on team1/team2 if you want to display it in your custom team slot.
  • In battle royale, points is shown in the right column by default.

Battle Royale Mode

Battle royale is enabled automatically when any match within any round contains more than two teams using a teams array. The UI switches to a list view with scrollable round and match buttons.

Data format (battle royale)

const rounds = [
  {
    name: 'Group Stage',
    matches: [
      {
        teams: [
          { id: 'g1-1', name: 'Team 1', points: 10 },
          { id: 'g1-2', name: 'Team 2', points: 14 },
          { id: 'g1-3', name: 'Team 3', points: 9 }
        ]
      }
    ]
  }
];

Slots (battle royale)

  • #team: customize team row rendering.
<template #team="{ team }">
  {{ team.name }}
  <!-- you can include badges, logos, etc. -->
  <span v-if="team.points">{{ team.points }}</span>
  </template>

Customizable props (round titles and battle royale)

  • Round titles: roundTitleColor, roundTitleBgColor, roundTitleBorderColor
  • Battle royale tabs: brTabBg, brTabTextColor, brTabActiveBg, brTabActiveTextColor
  • Battle royale table head: brTableHeadBg, brTableHeadTextColor
  • Battle royale team list: brListBg, brListTextColor, brListRowBg, brListRowHoverBg, brRowDividerColor

Example usage:

<template>
  <vueckets
    :rounds="rounds"
    :round-title-color="'#94a3b8'"
    :round-title-bg-color="'#0f172a'"
    :round-title-border-color="'#1e293b'"
    :winner-team-hover="'rgba(255, 255, 255, 0.1)'"
    :defeated-team-hover="'rgba(255, 0, 0, 0.1)'"
    :br-tab-bg="'#111827'"
    :br-tab-text-color="'#e5e7eb'"
    :br-tab-active-bg="'#374151'"
    :br-tab-active-text-color="'#ffffff'"
    :br-table-head-bg="'#111827'"
    :br-table-head-text-color="'#9ca3af'"
    :br-list-row-bg="'#1f2937'"
    :br-list-row-hover-bg="'#374151'"
    :br-row-divider-color="'#374151'"
  >
    <template #team="{ team }">{{ team.name }}</template>
  </vueckets>
</template>

Slots

  • #team: customize how a team is rendered (used for both classic and battle royale)
  • #team-extension-bottom: content under a two‑team match box

🎯 Advanced Examples

Tournament with Team Logos

<template>
  <vueckets :rounds="rounds" theme="dark">
    <template #player="{ player }">
      <div class="team-player">
        <img :src="player.logo" :alt="player.name" class="team-logo" />
        <div class="team-info">
          <div class="team-name">{{ player.name }}</div>
          <div class="team-score">{{ player.score }}</div>
        </div>
      </div>
    </template>
  </vueckets>
</template>

<style>
.team-player {
  display: flex;
  align-items: center;
  gap: 8px;
}

.team-logo {
  width: 24px;
  height: 24px;
  border-radius: 50%;
}

.team-info {
  flex: 1;
}

.team-name {
  font-weight: bold;
}

.team-score {
  font-size: 0.8em;
  opacity: 0.8;
}
</style>

Responsive Bracket

<template>
  <vueckets 
    :rounds="rounds"
    :custom-styles="responsiveStyles"
    wrapper-class="responsive-bracket"
  >
    <template #player="{ player }">{{ player.name }}</template>
  </vueckets>
</template>

<script>
export default {
  computed: {
    responsiveStyles() {
      return {
        fontSize: window.innerWidth < 768 ? '12px' : '16px',
        spacing: window.innerWidth < 768 ? '8px' : '12px'
      };
    }
  }
};
</script>

<style>
.responsive-bracket {
  max-width: 100%;
  overflow-x: auto;
}

@media (max-width: 768px) {
  .responsive-bracket {
    font-size: 0.875rem;
  }
}
</style>

🛠️ Development

# Install dependencies
npm install

# Serve development app
npm run serve

# Build library
npm run build

# Run tests
npm test

# Lint code
npm run lint

📄 Migration from vue-tournament-bracket

Vueckets is designed to be backward compatible with vue-tournament-bracket. Simply replace your import and add customization props as needed:

// Before
import Bracket from 'vue-tournament-bracket';

// After
import Vueckets from 'vueckets';

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📜 License

MIT License - see LICENSE file for details.

🙏 Acknowledgments

  • Built upon the foundation of vue-tournament-bracket
  • Inspired by modern tournament bracket designs
  • Thanks to the Vue.js community for their amazing ecosystem

Made with ❤️ for the Vue.js community