Cluster
Horizontal inline grouping of related items that wraps responsively.
Overview
Cluster arranges related items — tags, badges, filter chips, action buttons, and metadata labels — in a horizontal flow with consistent gaps and optional wrapping. It keeps small UI elements visually grouped without forcing a grid layout or a vertical stack. Cluster is a pure Tailwind utility pattern (flex flex-wrap items-center gap-*), not a JavaScript component.
Why this exists
Without a shared Cluster pattern, every dashboard filter bar, card metadata row, or tag list uses an ad-hoc combination of flex, gap-*, flex-wrap, and items-center — often with inconsistent values across pages. Cluster gives every team a documented, consistent pattern for inline horizontal groups that wrap responsively. It is the horizontal counterpart to Stack (vertical flow) and sits between Container (page width) and Grid (two-dimensional layout) in Byteion's layout primitive family.
Mental model
- Stack is for vertical rhythm — forms, card content, settings sections.
- Grid is for two-dimensional layout — dashboards, card grids, multi-column forms.
- Container is for page width — max-width and horizontal padding.
- Cluster is for inline groups of related items that may wrap — tags, badges, filter chips, action buttons, metadata.
Think of Cluster as a smart horizontal row: items sit side by side with even spacing, and when the row runs out of room, items flow to the next line. No item is forced to a specific width — each child is as wide as its content.
When to use
- Tag lists — topic tags, status labels, skill badges on profiles or products
- Filter chips — active filter indicators in a dashboard filter bar that wrap on mobile
- Action groups — compact button rows inside Card headers, PageHeader actions, toolbar areas
- Badge groups — feature badges, plan tier labels, role indicators grouped together
- Page header controls — breadcrumb, title, and action buttons arranged in a horizontal cluster
- Card metadata — date, author, read time, and category labels in a compact row
- Compact form helper actions — "Forgot password?", "Show password", and "Remember me" inline helpers
- Dashboard status indicators — online/offline dots, version labels, environment tags
- Ecommerce product labels — sale, new, limited edition, and stock badges clustered together
- ERP / POS quick actions — print, save, cancel, and duplicate buttons in a compact horizontal tray
When not to use
- Do not use Cluster for full page layout — use Grid for page-level arrangement or Container for page width
- Do not use Cluster when items must align in columns — Grid is required for column alignment
- Do not use Cluster for long readable text — paragraphs, descriptions, and body content belong in semantic text elements
- Do not use Cluster without a semantic wrapper when appropriate — use
<ul>for lists of tags,<nav>for navigation groups,role="toolbar"only when implementing real toolbar keyboard expectations - Do not use Cluster when a semantic list, nav, or toolbar pattern is required without adding the correct semantic wrapper
Basic example
A simple cluster of tag badges that wrap when the container narrows:
<div class="flex flex-wrap items-center gap-2">
<span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">documentation</span>
<span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">api</span>
<span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">design-system</span>
<span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">react</span>
<span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">vue</span>
<span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">tailwind</span>
</div>
Variants
Cluster has no visual variants — it is a single layout pattern. Items flow horizontally and wrap. Visual variation comes from the children: tags, badges, buttons, chips, or any other inline element placed inside the cluster. Spacing and alignment are controlled through Tailwind utility classes as described in the next section.
Sizes / spacing
The gap between cluster items is controlled by Tailwind's gap-* scale. Choose a gap that matches the density of your content:
| Gap | Class | Use case |
|---|---|---|
| 1 | gap-1 | Tight icon + label pairs, dense badge rows |
| 2 | gap-2 | Default tag and badge clusters, filter chips |
| 3 | gap-3 | Larger items, action button groups, metadata rows |
| 4 | gap-4 | Page header control groups, spacious toolbar clusters |
Alignment is controlled with items-center (default), items-start, or items-end. Wrapping is enabled by flex-wrap — the key behavior that makes Cluster responsive.
States
Cluster itself has no interaction states — it is a layout wrapper. Child elements (buttons, tags, chips, links) may have their own states such as hover, active, selected, disabled, or loading. Do not remove focus styles on interactive children inside a cluster.
Anatomy
- Wrapper element — a
<div>,<ul>,<nav>, or other container withflex flex-wrap items-center gap-* - Child items — tags, badges, buttons, chips, links, or any inline element that should flow horizontally
- Gap — consistent spacing between children via
gap-* - Wrap behavior —
flex-wrapensures items flow to the next line when the container is too narrow
Usage guidelines
- Keep related items together — group tags, badges, and actions that belong to the same context
- Allow wrapping on small screens —
flex-wrapis essential for responsive clusters - Choose gap based on density — use
gap-1orgap-2for compact tag groups,gap-3orgap-4for action button clusters - Keep action priority clear — place primary actions before secondary ones in left-to-right order
- Avoid mixing unrelated controls in one cluster — a settings form should not mix filter tags with navigation links in the same cluster
- Use semantic wrappers when the content has meaning —
<ul>for lists of tags,<nav>for navigation groups - Align children vertically with
items-centerwhen items have different heights (e.g. icon buttons next to text labels)
Do and Don't
Do
- Use Cluster for short related inline items
- Let items wrap on small screens with
flex-wrap - Use semantic wrappers when content is a list or navigation group
- Keep spacing token-based with
gap-* - Use
items-centerfor vertical alignment of mixed-height items
Don't
- Use Cluster for grid or table layouts
- Use Cluster for long paragraphs or readable text
- Put unrelated actions together just because they fit
- Remove child focus styles — interactive children must remain keyboard accessible
- Use Cluster without wrap when items may overflow the viewport
Accessibility
Cluster is a layout pattern — it does not add ARIA roles by default and preserves the semantics of its children.
- Use
<ul>/<li>for lists of tags or filters when the items form a list semantically. The<ul>gets the flex cluster classes; each<li>wraps a child element. - Use
<nav>with an accessible label for navigation link groups inside a cluster. - Use
role="toolbar"only when implementing real toolbar keyboard expectations — arrow key navigation between items, roving tabindex, and focus management. Do not addrole="toolbar"purely for styling. - Do not add ARIA roles only for styling — a plain
<div>with flex classes is sufficient for visual grouping. Add semantics only when the content structure demands it. - Ensure interactive children are keyboard accessible — buttons, links, and clickable tags must have visible focus indicators and be reachable by Tab.
Customization
Cluster is a pure Tailwind utility pattern — spacing, wrapping, alignment, and child styles all use standard Byteion tokens and Tailwind classes. Adjust the gap with gap-*, alignment with items-*, and child styles with the full Byteion token set (bg-muted, text-foreground, border-border, etc.). Avoid hardcoded pixel gaps and raw color values.
HTML example
<!-- Tag cluster -->
<div class="flex flex-wrap items-center gap-2">
<span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">documentation</span>
<span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">api</span>
<span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">react</span>
<span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">vue</span>
</div>
<!-- Page header action cluster -->
<div class="flex flex-wrap items-center gap-3">
<h1 class="text-2xl font-semibold text-foreground">Orders</h1>
<button class="rounded-lg bg-primary px-4 py-2 text-sm font-medium text-primary-foreground">Create order</button>
<button class="rounded-lg border border-border bg-background px-4 py-2 text-sm font-medium text-foreground">Export</button>
<button class="rounded-lg border border-border bg-background px-4 py-2 text-sm font-medium text-foreground">Filter</button>
</div>
<!-- Filter chip cluster -->
<div class="flex flex-wrap items-center gap-2">
<span class="rounded-lg bg-primary/10 text-primary px-3 py-1.5 text-sm font-medium border border-primary/20">
Status: Active ×
</span>
<span class="rounded-lg bg-muted px-3 py-1.5 text-sm text-foreground border border-border">
Priority: High ×
</span>
<span class="rounded-lg bg-muted px-3 py-1.5 text-sm text-foreground border border-border">
Date: Last 30 days ×
</span>
</div>
<!-- Semantic list-based tag cluster -->
<ul class="flex flex-wrap items-center gap-2 list-none p-0 m-0">
<li><span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">docs</span></li>
<li><span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">api</span></li>
<li><span class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">design</span></li>
</ul>
React example
React uses the same utility classes on standard elements. There is no Cluster component in @byteion/react:
import { Button } from '@byteion/react';
function TagCluster() {
const tags = ['documentation', 'api', 'react', 'vue', 'design-system'];
return (
<div className="flex flex-wrap items-center gap-2">
{tags.map(tag => (
<span key={tag} className="rounded-full bg-muted px-3 py-1 text-sm text-foreground">{tag}</span>
))}
</div>
);
}
function PageHeaderActions() {
return (
<div className="flex flex-wrap items-center gap-3">
<h1 className="text-2xl font-semibold text-foreground">Orders</h1>
<Button>Create order</Button>
<Button variant="outline">Export</Button>
<Button variant="outline">Filter</Button>
</div>
);
}
function FilterChips() {
const filters = [
{ label: 'Status: Active', active: true },
{ label: 'Priority: High' },
{ label: 'Date: Last 30 days' },
];
return (
<div className="flex flex-wrap items-center gap-2">
{filters.map((f, i) => (
<span key={i}
className={f.active
? 'rounded-lg bg-primary/10 text-primary px-3 py-1.5 text-sm font-medium border border-primary/20'
: 'rounded-lg bg-muted px-3 py-1.5 text-sm text-foreground border border-border'}
>
{f.label} ×
</span>
))}
</div>
);
}
Vue example
Vue uses the same utility classes on template elements. There is no Cluster component in @byteion/vue:
<script setup lang="ts">
import { Button } from '@byteion/vue';
const tags = ['documentation', 'api', 'react', 'vue', 'design-system'];
const filters = [
{ label: 'Status: Active', active: true },
{ label: 'Priority: High', active: false },
{ label: 'Date: Last 30 days', active: false },
];
</script>
<template>
<!-- Tag cluster -->
<div class="flex flex-wrap items-center gap-2">
<span v-for="tag in tags" :key="tag"
class="rounded-full bg-muted px-3 py-1 text-sm text-foreground">
{{ tag }}
</span>
</div>
<!-- Page header action cluster -->
<div class="flex flex-wrap items-center gap-3">
<h1 class="text-2xl font-semibold text-foreground">Orders</h1>
<Button>Create order</Button>
<Button variant="outline">Export</Button>
<Button variant="outline">Filter</Button>
</div>
<!-- Filter chip cluster -->
<div class="flex flex-wrap items-center gap-2">
<span v-for="(f, i) in filters" :key="i"
:class="f.active
? 'rounded-lg bg-primary/10 text-primary px-3 py-1.5 text-sm font-medium border border-primary/20'
: 'rounded-lg bg-muted px-3 py-1.5 text-sm text-foreground border border-border'"
>
{{ f.label }} ×
</span>
</div>
</template>
API Reference
Cluster is a pure Tailwind utility pattern — it has no React component, no Vue component, and no JavaScript API. There are no props to configure. The pattern is applied by adding Tailwind utility classes to a container element:
| Class group | Purpose |
|---|---|
| flex | Enables Flexbox layout |
| flex-wrap | Allows items to wrap to the next line when space runs out |
| items-center | Vertically centres items of varying heights |
| gap-{1,2,3,4} | Controls consistent spacing between children |
Developer tips
- Use Cluster inside Card headers, PageHeader actions, filter bars, and product metadata — these are the most common places where a horizontal inline group is needed
- Keep children compact — Cluster works best with small elements like tags, badges, chips, and icon buttons. Large blocks inside a cluster defeat its purpose
- Test wrapping at mobile widths — verify that items flow to the next line gracefully without overlapping or overflowing the viewport
- Do not rely on Cluster to create column alignment — items in a cluster are not forced to equal widths. If you need items to share equal column widths, use Grid
- Combine with Stack for multi-row toolbars — use Stack to stack multiple Cluster rows vertically for complex toolbar arrangements
Common mistakes
- Using Cluster for full layout grids — Cluster is for inline groups, not page-level layout. Use Grid or Stack for overall page structure.
- Mixing destructive and primary actions without hierarchy — placing a "Delete" button next to a "Save" button in the same cluster without visual separation (grouped by gap or divider) can lead to accidental destructive actions.
- Using hardcoded gaps — using
style="gap: 8px"instead ofgap-2breaks the token system and creates inconsistency across pages. - Forgetting semantic list markup for tag or filter lists — a group of tags is semantically a list. Use
<ul>+<li>for screen reader compatibility. - Disabling child focus states — interactive children (buttons, links, clickable chips) must retain visible focus indicators for keyboard accessibility.
- Using Cluster without
flex-wrap— without wrapping, items overflow the viewport on small screens, causing horizontal scroll.
Production usage tips
- Test responsive wrapping — verify Cluster children wrap correctly at common breakpoints (375 px, 768 px, 1024 px). Items should never overflow or be cut off.
- Verify touch target spacing — when cluster children are buttons or clickable chips, ensure each touch target is at least 44x44 px per WCAG guidance. Use
gap-2or larger to prevent accidental taps. - Keep React / Vue examples visually aligned with HTML — the canonical HTML pattern (
flex flex-wrap items-center gap-*) is the source of truth. Ensure all framework examples produce the same visual result. - Validate dark mode and branded themes — Cluster itself uses no colour tokens, but child elements do. Test tags, badges, buttons, and chips inside the cluster under all themes.
- For Laravel / server-rendered apps — use the raw HTML structure shown in the HTML example. Cluster is a zero-JS pattern.
- For React / Vue SPAs — use the same utility classes on a
<div>(or semantic wrapper). No import from@byteionis needed.
Premium examples
Pro patterns available in Byteion Pro:
- Responsive dashboard filter bar — a Cluster of filter chips, date picker, search input, and action buttons that wraps into a multi-row Stack on mobile
- Ecommerce product tag editor — an inline Cluster of editable tags with remove buttons, plus an "Add tag" input that appends to the cluster
- ERP quick-action toolbar — a Cluster of icon buttons (Print, Save, Duplicate, Archive, Delete) with tooltips, wrapped in a semantic toolbar container
- POS payment / action cluster — a compact Cluster of large action buttons (Cash, Card, Mobile, Split Payment) with
gap-4spacing for touch targets - Settings page permission badge group — a Cluster of role badges (Admin, Editor, Viewer, Custom) each with a remove button, wrapped in a
<fieldset>with a legend
Related components
- Stack — one-dimensional vertical or horizontal flow for page sections
- Grid — two-dimensional layout for when items need column alignment
- Container — page-level width and horizontal padding
- Card — surface container where clusters often appear (card header actions, card metadata)
- Button — action triggers commonly placed inside action clusters
- Badge — status and label indicators commonly placed inside tag or badge clusters
API Reference
Related components
Pair this component with adjacent Byteion primitives from the same workflow: form controls for data entry, feedback components for validation, and layout primitives for spacing.
Runtime events
Byteion keeps framework APIs idiomatic: HTML uses DOM custom events, React uses callback props, and Vue uses emitted events / v-model updates.
HTML / JS events
No HTML runtime events are declared by this adapter.
React callbacks
No React callback events are declared by this adapter.
Vue emits
No Vue emitted events are declared by this adapter.
Remote / AJAX
This component does not implement Byteion JS remote loading. Use normal HTML form submission, framework state, or your application data layer around it.
Unlock Premium Patterns
Get access to copy-paste ready Pro blocks, SaaS templates, and advanced component patterns.
Explore Pro Components