Skip to main content
Version: 1.0.3

Button Group

Overview

The ButtonGroup component groups multiple buttons together with consistent spacing, active state highlighting, and responsive wrapping capabilities. It's perfect for creating filter buttons, toggle groups, size selectors, and other scenarios where you need related buttons grouped together.

Preview

Active: option1

Installation

ignix add component button-group

Usage

Import the component:

import { ButtonGroup } from './components/ui';

Basic Usage

import { ButtonGroup } from './components/ui';
import { useState } from 'react';

function BasicButtonGroup() {
const [activeValue, setActiveValue] = useState('save');

return (
<ButtonGroup
items={[
{ value: 'save', children: 'Save' },
{ value: 'cancel', children: 'Cancel' },
{ value: 'delete', children: 'Delete' }
]}
activeValue={activeValue}
onChange={(value) => setActiveValue(value)}
/>
);
}

Props

PropTypeDefaultDescription
itemsButtonGroupItem[]requiredArray of button items to display in the group
activeValuestringundefinedCurrently active button value (controlled mode)
defaultValuestringundefinedDefault active button value (uncontrolled mode)
onChange(value: string) => voidundefinedCallback fired when a button is clicked
wrapbooleantrueWhether buttons should wrap to multiple lines
spacingstring'gap-2'Spacing between buttons (Tailwind spacing class)
orientation'horizontal' | 'vertical''horizontal'Orientation of the button group
activeVariantButtonProps['variant']undefinedVariant to apply to active buttons
multiplebooleanfalseAllow multiple buttons to be active simultaneously
activeValuesstring[]undefinedArray of active values when multiple selection is enabled

ButtonGroupItem

PropTypeDescription
valuestringrequired - Unique identifier for the button
childrenReact.ReactNodeButton text content
variantstringVisual variant of the button
sizestringSize of the button
onClick(value: string, event: MouseEvent) => voidClick handler for the button
All other ButtonProps-All other props from the base Button component

Examples

Controlled Mode

Use activeValue and onChange to control the active state from a parent component.

import { useState } from 'react';
import { ButtonGroup } from './components/ui';

function ControlledButtonGroup() {
const [activeValue, setActiveValue] = useState('all');

return (
<ButtonGroup
items={[
{ value: 'all', children: 'All' },
{ value: 'active', children: 'Active' },
{ value: 'inactive', children: 'Inactive' }
]}
activeValue={activeValue}
onChange={(value) => {
setActiveValue(value);
console.log(`Filter changed to: ${value}`);
}}
/>
);
}

Uncontrolled Mode

Use defaultValue to set an initial active value without controlling it.

import { ButtonGroup } from './components/ui';

function UncontrolledButtonGroup() {
return (
<ButtonGroup
items={[
{ value: 'option1', children: 'Option 1' },
{ value: 'option2', children: 'Option 2' },
{ value: 'option3', children: 'Option 3' }
]}
defaultValue="option1"
/>
);
}

Multiple Selection

Enable multiple selection by setting multiple={true} and using activeValues.

import { useState } from 'react';
import { ButtonGroup } from './components/ui';

function MultipleSelectionButtonGroup() {
const [activeValues, setActiveValues] = useState<string[]>(['bold']);

return (
<ButtonGroup
items={[
{ value: 'bold', children: 'Bold' },
{ value: 'italic', children: 'Italic' },
{ value: 'underline', children: 'Underline' }
]}
multiple
activeValues={activeValues}
onChange={(value) => {
setActiveValues(prev =>
prev.includes(value)
? prev.filter(v => v !== value)
: [...prev, value]
);
}}
/>
);
}

Filter Buttons

Perfect for filtering content by status or category.

import { useState } from 'react';
import { ButtonGroup } from './components/ui';

function FilterButtons() {
const [filter, setFilter] = useState('all');

return (
<div>
<p className="text-sm font-medium mb-2">Filter by status:</p>
<ButtonGroup
items={[
{ value: 'all', children: 'All Items' },
{ value: 'published', children: 'Published' },
{ value: 'draft', children: 'Draft' },
{ value: 'archived', children: 'Archived' }
]}
activeValue={filter}
onChange={(value) => setFilter(value)}
/>
</div>
);
}

Size Selector

Use ButtonGroup for selecting sizes or other options.

import { useState } from 'react';
import { ButtonGroup } from './components/ui';

function SizeSelector() {
const [size, setSize] = useState('md');

return (
<div>
<p className="text-sm font-medium mb-2">Select size:</p>
<ButtonGroup
items={[
{ value: 'xs', children: 'XS' },
{ value: 'sm', children: 'SM' },
{ value: 'md', children: 'MD' },
{ value: 'lg', children: 'LG' },
{ value: 'xl', children: 'XL' }
]}
activeValue={size}
onChange={(value) => setSize(value)}
/>
</div>
);
}

Vertical Orientation

Display buttons vertically instead of horizontally.

import { ButtonGroup } from './components/ui';

function VerticalButtonGroup() {
return (
<ButtonGroup
items={[
{ value: 'top', children: 'Top' },
{ value: 'middle', children: 'Middle' },
{ value: 'bottom', children: 'Bottom' }
]}
orientation="vertical"
defaultValue="middle"
/>
);
}

Custom Spacing

Adjust spacing between buttons using Tailwind spacing classes.

import { ButtonGroup } from './components/ui';

function CustomSpacingButtonGroup() {
return (
<>
<ButtonGroup
items={[
{ value: '1', children: 'Tight' },
{ value: '2', children: 'Spacing' }
]}
spacing="gap-1"
/>

<ButtonGroup
items={[
{ value: '1', children: 'Wide' },
{ value: '2', children: 'Spacing' }
]}
spacing="gap-4"
/>
</>
);
}

Custom Active Variant

Apply a specific variant to active buttons.

import { useState } from 'react';
import { ButtonGroup } from './components/ui';

function CustomActiveVariantButtonGroup() {
const [activeValue, setActiveValue] = useState('option1');

return (
<ButtonGroup
items={[
{ value: 'option1', children: 'Option 1', variant: 'outline' },
{ value: 'option2', children: 'Option 2', variant: 'outline' },
{ value: 'option3', children: 'Option 3', variant: 'outline' }
]}
activeValue={activeValue}
onChange={setActiveValue}
activeVariant="success"
/>
);
}

Responsive Wrapping

Buttons automatically wrap to multiple lines on smaller screens when wrap={true}.

import { ButtonGroup } from './components/ui';

function ResponsiveButtonGroup() {
return (
<ButtonGroup
items={[
{ value: '1', children: 'Button 1' },
{ value: '2', children: 'Button 2' },
{ value: '3', children: 'Button 3' },
{ value: '4', children: 'Button 4' },
{ value: '5', children: 'Button 5' },
{ value: '6', children: 'Button 6' }
]}
wrap={true}
spacing="gap-2"
/>
);
}

Accessibility

The ButtonGroup component includes proper ARIA attributes:

  • role="group" - Identifies the container as a group
  • aria-label="Button group" - Provides a label for screen readers
  • aria-pressed - Indicates the active state of each button

Best Practices

  1. Use consistent spacing: Use the spacing prop to maintain consistent gaps between buttons
  2. Clear active states: Ensure active buttons are visually distinct from inactive ones
  3. Responsive design: Enable wrapping for button groups that may overflow on smaller screens
  4. Accessible labels: Provide clear labels for button groups using aria-label if needed
  5. Controlled vs Uncontrolled: Use controlled mode when you need to sync state with external data, uncontrolled for simple internal state