Button Group
Combine multiple buttons into a unified component for toggle controls, view switchers, and option selection
Overview
Button Groups combine multiple buttons into a single unified component with connected borders. They're perfect for creating toggle controls, view switchers, text formatting toolbars, and any interface where users select from a set of related options.
Key Features
- Single Mode - Radio button behaviour (only one active)
- Multiple Mode - Checkbox behaviour (multiple active)
- Horizontal & Vertical - Layout orientation options
- Size Variants - Small, default, and large sizes
- Programmatic Control - setValue, toggle, selectAll, deselectAll
- Change Callbacks - React to selection changes
When to Use Button Groups
- View Toggles - Day/Week/Month views, grid/list layouts
- Text Formatting - Bold/Italic/Underline toolbars
- Filter Controls - Single or multi-select filters
- Segmented Controls - iOS-style segment pickers
Basic Usage
<!-- HTML Structure -->
<div class="btn-group" id="my-group">
<button class="btn btn-outline active">Option 1</button>
<button class="btn btn-outline">Option 2</button>
<button class="btn btn-outline">Option 3</button>
</div>
<!-- JavaScript Initialisation -->
<script>
const group = Domma.elements.buttonGroup('#my-group', {
mode: 'single',
onChange: (value) => {
console.log('Selected index:', value);
}
});
</script>
Quick Start
Get started with Button Groups in seconds. Here's the simplest implementation:
CSS-Only Button Group (No JavaScript)
For visual grouping without interactivity:
<div class="btn-group">
<button type="button" class="btn btn-primary">Left</button>
<button type="button" class="btn btn-primary">Middle</button>
<button type="button" class="btn btn-primary">Right</button>
</div><div class="btn-group">
<button class="btn btn-primary">Left</button>
<button class="btn btn-primary">Middle</button>
<button class="btn btn-primary">Right</button>
</div>
Interactive Toggle Group (Single Selection)
With JavaScript for radio button behaviour:
Selected: Day
<div class="btn-group" id="quick-start-group">
<button type="button" class="btn btn-outline active">Day</button>
<button type="button" class="btn btn-outline">Week</button>
<button type="button" class="btn btn-outline">Month</button>
</div>
<p class="text-sm text-muted mt-2">Selected: <strong id="quick-start-value">Day</strong></p>/**
* Interactive Toggle Group (Single Selection) - from public/showcase/elements/button-group.
*/
export function mount(root) {
const quickStartLabels = ['Day', 'Week', 'Month'];
E.buttonGroup(root.querySelector('#quick-start-group'), {
mode: 'single',
onChange: (value) => {
$(root).find('#quick-start-value').text(quickStartLabels[value]);
}
});
}<div class="btn-group" id="view-toggle">
<button class="btn btn-outline active">Day</button>
<button class="btn btn-outline">Week</button>
<button class="btn btn-outline">Month</button>
</div>
<script>
const viewToggle = Domma.elements.buttonGroup('#view-toggle', {
mode: 'single',
onChange: (value) => {
const labels = ['Day', 'Week', 'Month'];
console.log('Selected:', labels[value]);
}
});
</script>
Step-by-Step Tutorial
Let's build a text formatting toolbar with bold, italic, and underline controls (multiple selection mode).
Step 1: Create the HTML Structure
Start with a container and buttons. Add the .btn-group class:
<div class="btn-group" id="format-toolbar">
<button class="btn btn-outline">Bold</button>
<button class="btn btn-outline">Italic</button>
<button class="btn btn-outline">Underline</button>
</div>
<div id="format-result" class="mt-4"></div>
Step 2: Initialise with Multiple Mode
Enable checkbox behaviour by setting mode: 'multiple':
const toolbar = Domma.elements.buttonGroup('#format-toolbar', {
mode: 'multiple'
});
Step 3: Add Change Callback
React to selection changes. The callback receives an array of active indices:
const toolbar = Domma.elements.buttonGroup('#format-toolbar', {
mode: 'multiple',
onChange: (values) => {
const labels = ['Bold', 'Italic', 'Underline'];
const active = values.map(i => labels[i]).join(', ');
$('#format-result').text(
active || 'No formatting selected';
}
});
Step 4: Add Control Buttons
Provide programmatic control with select all and clear all:
<button id="select-all" class="btn btn-sm btn-secondary">Select All</button>
<button id="clear-all" class="btn btn-sm btn-secondary">Clear All</button>
<script>
$('#select-all').on('click', () => {
toolbar.selectAll();
});
$('#clear-all').on('click', () => {
toolbar.deselectAll();
});
</script>
Step 5: Add Visual Feedback
Apply styles based on the selected formatting:
const toolbar = Domma.elements.buttonGroup('#format-toolbar', {
mode: 'multiple',
onChange: (values) => {
const result = $('#format-result');
const labels = ['Bold', 'Italic', 'Underline'];
// Update text
const active = values.map(i => labels[i]).join(', ');
result.textContent = active || 'No formatting selected';
// Apply CSS styles
result.style.fontWeight = values.includes(0) ? 'bold' : 'normal';
result.style.fontStyle = values.includes(1) ? 'italic' : 'normal';
result.style.textDecoration = values.includes(2) ? 'underline' : 'none';
}
});
Step 6: Complete Working Demo
Try the complete formatting toolbar:
<div class="btn-group" id="tutorial-toolbar">
<button type="button" class="btn btn-outline">Bold</button>
<button type="button" class="btn btn-outline">Italic</button>
<button type="button" class="btn btn-outline">Underline</button>
</div>
<div class="flex gap-2 mt-3">
<button type="button" id="tutorial-select-all" class="btn btn-sm btn-secondary">Select All</button>
<button type="button" id="tutorial-clear-all" class="btn btn-sm btn-secondary">Clear All</button>
</div>
<div id="tutorial-result" class="mt-4 p-4 bg-surface rounded border button-group-min-h-40">
Select formatting options above
</div>/**
* Step 6: Complete Working Demo - from public/showcase/elements/button-group.
*/
export function mount(root) {
// Tutorial Demo
const tutorialLabels = ['Bold', 'Italic', 'Underline'];
const tutorialToolbar = E.buttonGroup(root.querySelector('#tutorial-toolbar'), {
mode: 'multiple',
onChange: (values) => {
const result = $(root).find('#tutorial-result');
const active = values.map(i => tutorialLabels[i]).join(', ');
result.text(active || 'No formatting selected');
// Apply visual styles
result.css({
'font-weight': values.includes(0) ? 'bold' : 'normal',
'font-style': values.includes(1) ? 'italic' : 'normal',
'text-decoration': values.includes(2) ? 'underline' : 'none'
});
}
});
$(root).find('#tutorial-select-all').on('click', () => {
tutorialToolbar.selectAll();
});
$(root).find('#tutorial-clear-all').on('click', () => {
tutorialToolbar.deselectAll();
});
}Examples & Variations
View Toggle (Single Selection)
Radio button behaviour - only one option active at a time:
Selected: Day
<div class="btn-group" id="view-toggle">
<button type="button" class="btn btn-outline active">Day</button>
<button type="button" class="btn btn-outline">Week</button>
<button type="button" class="btn btn-outline">Month</button>
</div>
<p class="text-sm text-muted mt-2">Selected: <strong id="view-value">Day</strong></p>/**
* View Toggle (Single Selection) - from public/showcase/elements/button-group.
*/
export function mount(root) {
// Examples: View Toggle
const viewLabels = ['Day', 'Week', 'Month'];
E.buttonGroup(root.querySelector('#view-toggle'), {
mode: 'single',
onChange: (value) => {
$(root).find('#view-value').text(viewLabels[value]);
}
});
}const viewToggle = Domma.elements.buttonGroup('#view-toggle', {
mode: 'single',
onChange: (value) => {
const labels = ['Day', 'Week', 'Month'];
$('#view-value').text(labels[value]);
}
});
Format Toolbar (Multiple Selection)
Checkbox behaviour - multiple options can be active:
Active: None
<div class="btn-group" id="format-toggle">
<button type="button" class="btn btn-outline">Bold</button>
<button type="button" class="btn btn-outline">Italic</button>
<button type="button" class="btn btn-outline">Underline</button>
</div>
<p class="text-sm text-muted mt-2">Active: <strong id="format-value">None</strong></p>/**
* Format Toolbar (Multiple Selection) - from public/showcase/elements/button-group.
*/
export function mount(root) {
// Examples: Format Toolbar
const formatLabels = ['Bold', 'Italic', 'Underline'];
E.buttonGroup(root.querySelector('#format-toggle'), {
mode: 'multiple',
onChange: (values) => {
const active = values.map(i => formatLabels[i]).join(', ');
$(root).find('#format-value').text(active || 'None');
}
});
}const formatToggle = Domma.elements.buttonGroup('#format-toggle', {
mode: 'multiple',
onChange: (values) => {
const labels = ['Bold', 'Italic', 'Underline'];
const active = values.map(i => labels[i]).join(', ');
$('#format-value').text(active || 'None');
}
});
Vertical Button Group
Stack buttons vertically with .btn-group-vertical:
<div class="btn-group-vertical" id="vertical-group">
<button type="button" class="btn btn-secondary active">Top</button>
<button type="button" class="btn btn-secondary">Middle</button>
<button type="button" class="btn btn-secondary">Bottom</button>
</div>/**
* Vertical Button Group - from public/showcase/elements/button-group.
*/
export function mount(root) {
// Examples: Vertical Group
E.buttonGroup(root.querySelector('#vertical-group'), {
mode: 'single'
});
}<div class="btn-group-vertical" id="vertical-group">
<button class="btn btn-secondary active">Top</button>
<button class="btn btn-secondary">Middle</button>
<button class="btn btn-secondary">Bottom</button>
</div>
<script>
Domma.elements.buttonGroup('#vertical-group', {
mode: 'single'
});
</script>
Size Variants
Small, default, and large button groups:
<div class="flex flex-col gap-4">
<div class="btn-group">
<button type="button" class="btn btn-primary btn-sm active">Small</button>
<button type="button" class="btn btn-primary btn-sm">Group</button>
</div>
<div class="btn-group">
<button type="button" class="btn btn-primary active">Default</button>
<button type="button" class="btn btn-primary">Group</button>
</div>
<div class="btn-group">
<button type="button" class="btn btn-primary btn-lg active">Large</button>
<button type="button" class="btn btn-primary btn-lg">Group</button>
</div>
</div><!-- Small -->
<div class="btn-group">
<button class="btn btn-primary btn-sm">Small</button>
<button class="btn btn-primary btn-sm">Group</button>
</div>
<!-- Default -->
<div class="btn-group">
<button class="btn btn-primary">Default</button>
<button class="btn btn-primary">Group</button>
</div>
<!-- Large -->
<div class="btn-group">
<button class="btn btn-primary btn-lg">Large</button>
<button class="btn btn-primary btn-lg">Group</button>
</div>
Allow Empty Selection
In single mode, allow deselecting all buttons:
Selected: None
<div class="btn-group" id="optional-group">
<button type="button" class="btn btn-outline">Option A</button>
<button type="button" class="btn btn-outline">Option B</button>
<button type="button" class="btn btn-outline">Option C</button>
</div>
<p class="text-sm text-muted mt-2">Selected: <strong id="optional-value">None</strong></p>/**
* Allow Empty Selection - from public/showcase/elements/button-group.
*/
export function mount(root) {
// Examples: Allow Empty
const optionalLabels = ['Option A', 'Option B', 'Option C'];
E.buttonGroup(root.querySelector('#optional-group'), {
mode: 'single',
allowEmpty: true,
onChange: (value) => {
$(root).find('#optional-value').text(value !== null ? optionalLabels[value] : 'None');
}
});
}const optionalGroup = Domma.elements.buttonGroup('#optional-group', {
mode: 'single',
allowEmpty: true, // Allow no selection
onChange: (value) => {
const labels = ['Option A', 'Option B', 'Option C'];
$('#optional-value').text(
value !== null ? labels[value] : 'None';
}
});
Programmatic Control
Control selections via JavaScript methods:
Current value: []
<div class="btn-group" id="programmatic-group">
<button type="button" class="btn btn-outline">Feature A</button>
<button type="button" class="btn btn-outline">Feature B</button>
<button type="button" class="btn btn-outline">Feature C</button>
</div>
<div class="flex gap-2 mt-3">
<button type="button" id="prog-set-0" class="btn btn-sm btn-secondary">Select First</button>
<button type="button" id="prog-set-1" class="btn btn-sm btn-secondary">Select Second</button>
<button type="button" id="prog-toggle-2" class="btn btn-sm btn-secondary">Toggle Third</button>
<button type="button" id="prog-clear" class="btn btn-sm btn-secondary">Clear</button>
</div>
<p class="text-sm text-muted mt-2">Current value: <strong id="prog-value">[]</strong></p>/**
* Programmatic Control - from public/showcase/elements/button-group.
*/
export function mount(root) {
// Examples: Programmatic Control
const progGroup = E.buttonGroup(root.querySelector('#programmatic-group'), {
mode: 'multiple',
onChange: (values) => {
$(root).find('#prog-value').text(JSON.stringify(values));
}
});
$(root).find('#prog-set-0').on('click', () => progGroup.setValue([0]));
$(root).find('#prog-set-1').on('click', () => progGroup.setValue([1]));
$(root).find('#prog-toggle-2').on('click', () => progGroup.toggle(2));
$(root).find('#prog-clear').on('click', () => progGroup.deselectAll());
}const group = Domma.elements.buttonGroup('#programmatic-group', {
mode: 'multiple',
onChange: (values) => {
$('#prog-value').text(JSON.stringify(values));
}
});
// Programmatic methods
$('#prog-set-0').on('click', () => {
group.setValue([0]); // Set active buttons by index
});
$('#prog-set-1').on('click', () => {
group.setValue([1]);
});
$('#prog-toggle-2').on('click', () => {
group.toggle(2); // Toggle specific button
});
$('#prog-clear').on('click', () => {
group.deselectAll(); // Clear all selections
});
Icon Button Group
Use icons for compact visual controls:
<div class="btn-group" id="icon-group">
<button type="button" class="btn btn-outline active" title="Left Align">
<svg width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path d="M2 12.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm0-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"></path>
</svg>
</button>
<button type="button" class="btn btn-outline" title="Centre Align">
<svg width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path d="M4 12.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"></path>
</svg>
</button>
<button type="button" class="btn btn-outline" title="Right Align">
<svg width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path d="M6 12.5a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-4-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5zm4-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-4-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"></path>
</svg>
</button>
</div>/**
* Icon Button Group - from public/showcase/elements/button-group.
*/
export function mount(root) {
// Examples: Icon Group
E.buttonGroup(root.querySelector('#icon-group'), {
mode: 'single'
});
}<div class="btn-group" id="icon-group">
<button class="btn btn-outline active" title="Left Align">
<svg width="16" height="16">...</svg>
</button>
<button class="btn btn-outline" title="Centre Align">
<svg width="16" height="16">...</svg>
</button>
<button class="btn btn-outline" title="Right Align">
<svg width="16" height="16">...</svg>
</button>
</div>
<script>
Domma.elements.buttonGroup('#icon-group', {
mode: 'single'
});
</script>
Real-World Example: Filter Panel
Build a product filter with category and price range controls:
<div class="mb-4">
<label class="text-sm font-semibold mb-2 block-button-group">Category:</label>
<div class="btn-group" id="category-filter">
<button type="button" class="btn btn-outline btn-sm">All</button>
<button type="button" class="btn btn-outline btn-sm">Electronics</button>
<button type="button" class="btn btn-outline btn-sm">Clothing</button>
<button type="button" class="btn btn-outline btn-sm">Books</button>
</div>
</div>
<div class="mb-4">
<label class="text-sm font-semibold mb-2 block-button-group">Price Range:</label>
<div class="btn-group" id="price-filter">
<button type="button" class="btn btn-outline btn-sm">Under £20</button>
<button type="button" class="btn btn-outline btn-sm">£20-£50</button>
<button type="button" class="btn btn-outline btn-sm">£50-£100</button>
<button type="button" class="btn btn-outline btn-sm">Over £100</button>
</div>
</div>
<div class="p-3 bg-surface rounded border">
<strong>Active Filters:</strong>
<div id="filter-summary" class="text-sm text-muted mt-1">None selected</div>
</div>/**
* Real-World Example: Filter Panel - from public/showcase/elements/button-group.
*/
export function mount(root) {
// Examples: Filter Panel
const categoryLabels = ['All', 'Electronics', 'Clothing', 'Books'];
const priceLabels = ['Under £20', '£20-£50', '£50-£100', 'Over £100'];
const categoryFilter = E.buttonGroup(root.querySelector('#category-filter'), {
mode: 'single',
allowEmpty: true,
onChange: updateFilters
});
const priceFilter = E.buttonGroup(root.querySelector('#price-filter'), {
mode: 'single',
allowEmpty: true,
onChange: updateFilters
});
function updateFilters() {
const category = categoryFilter.getValue();
const price = priceFilter.getValue();
const filters = [];
if (category !== null) filters.push(categoryLabels[category]);
if (price !== null) filters.push(priceLabels[price]);
$(root).find('#filter-summary').text(filters.length ? filters.join(', ') : 'None selected');
}
}// Category filter (single selection, allow empty)
const categoryFilter = Domma.elements.buttonGroup('#category-filter', {
mode: 'single',
allowEmpty: true,
onChange: updateFilters
});
// Price filter (single selection, allow empty)
const priceFilter = Domma.elements.buttonGroup('#price-filter', {
mode: 'single',
allowEmpty: true,
onChange: updateFilters
});
function updateFilters() {
const categories = ['All', 'Electronics', 'Clothing', 'Books'];
const prices = ['Under £20', '£20-£50', '£50-£100', 'Over £100'];
const category = categoryFilter.getValue();
const price = priceFilter.getValue();
const filters = [];
if (category !== null) filters.push(categories[category]);
if (price !== null) filters.push(prices[price]);
$('#filter-summary').text(
filters.length ? filters.join(', ') : 'None selected';
}
Best Practices
Accessibility
- Use Semantic Buttons - Always use
elements, notor ``tags
Performance
- Single Initialisation - Initialise once, use programmatic methods for changes
- Event Delegation - Component uses event delegation internally - no need to rebind after updates
- Destroy When Removed - Call
.destroy()when removing from DOM to clean up listeners - Throttle onChange - If onChange triggers expensive operations, use
_.throttle()or_.debounce() - Cache DOM Queries - Store component instance instead of re-selecting:
const group = Domma.elements.buttonGroup(...) - Get Button Elements - Use
getActive()to access actual button elements, not just indices
Common Gotchas
- Issue: onChange callback not firing
Solution: Ensure buttons have class.btn- component only tracks elements with this class
Example:Click - Issue: getValue() returns null in single mode
Solution: No button is active. Either set initial active button in HTML or useallowEmpty: false
Example: Default
- Issue: selectAll() doesn't work
Solution: selectAll() only works inmode: 'multiple', not single mode
Example:{ mode: 'multiple' } - Issue: Buttons visually separate instead of connected
Solution: Missing.btn-groupclass on container
Example: ```` - Issue: Active class not changing
Solution: Using custom activeClass? Ensure CSS styles it correctly
Example:{ activeClass: 'selected' }requires.selected { ... }CSS
Tips & Tricks
- Default Selection - Add
.activeclass in HTML to pre-select buttons - Mixed Sizes - All buttons in a group should use the same size class for visual consistency
- Outline Style - Use
.btn-outlinefor toggle groups,.btn-primaryfor static groups - Vertical on Mobile - Switch to
.btn-group-verticalon small screens for better touch targets - Store Instance - Save returned instance to call methods later:
const group = Domma.elements.buttonGroup(...) - Get Button Elements - Use
getActive()to access actual button elements, not just indices
<!-- Accessible Button Group -->
<div class="btn-group" role="group" aria-label="Text alignment">
<button class="btn btn-outline" aria-pressed="false" aria-label="Align left">
<svg>...</svg>
</button>
<button class="btn btn-outline active" aria-pressed="true" aria-label="Align centre">
<svg>...</svg>
</button>
<button class="btn btn-outline" aria-pressed="false" aria-label="Align right">
<svg>...</svg>
</button>
</div>
<script>
const group = Domma.elements.buttonGroup('.btn-group', {
mode: 'single',
onChange: (value, index, button) => {
// Update ARIA states
group.buttons.forEach((btn, i) => {
btn.setAttribute('aria-pressed', i === value);
});
}
});
</script>
API Reference
Constructor Options
| Option | Type | Default | Description |
|---|---|---|---|
mode |
String | 'single' |
Selection mode. 'single' = radio (one active), 'multiple' = checkbox (many active) |
activeClass |
String | 'active' |
CSS class applied to active/selected buttons |
allowEmpty |
Boolean | false |
In single mode, allow deselecting all buttons (clicking active button deselects it) |
onChange |
Function | null |
Callback fired when selection changes. Receives (value, index, button). Value is index (single) or array (multiple) |
Methods
| Method | Parameters | Returns | Description |
|---|---|---|---|
getValue() |
- | Number | Number[] | null | Get active button index (single mode) or array of indices (multiple mode). Returns null if none active |
getActive() |
- | HTMLElement | HTMLElement[] | null | Get active button element (single) or array of elements (multiple). Returns null if none active |
setValue(value) |
Number | Number[] | this | Set active button(s) by index. Pass single index (single mode) or array of indices (multiple). Chainable |
toggle(index) |
Number | this | Toggle a specific button by index. In single mode, selects it. In multiple mode, toggles it. Chainable |
selectAll() |
- | this | Select all buttons. Only works in mode: 'multiple'. Chainable |
deselectAll() |
- | this | Deselect all buttons. Works in both single and multiple modes. Chainable |
destroy() |
- | void | Remove event listeners and clean up. Call before removing from DOM |
Events / Callbacks
| Event | Parameters | Description |
|---|---|---|
onChange |
(value, index, button) |
Fired when selection changes (button clicked or programmatic change). |
| value: Active index (single) or array of indices (multiple) | ||
| index: Index of button that triggered change (-1 for selectAll/deselectAll) | ||
| button: Button element that triggered change (null for selectAll/deselectAll) |
CSS Classes
| Class | Description |
|---|---|
.btn-group |
Container class for horizontal button groups. Connects borders and removes gaps between buttons |
.btn-group-vertical |
Container class for vertical button groups. Stacks buttons vertically with connected borders |
.btn |
Required base class for all buttons within the group. Component only tracks elements with this class |
.active |
Default class applied to selected/active buttons. Can be customised via activeClass option |
.btn-primary |
Primary button style (filled blue). Good for static groups |
.btn-secondary |
Secondary button style (filled grey) |
.btn-outline |
Outline button style (transparent with border). Recommended for toggle groups |
.btn-sm |
Small button size |
.btn-lg |
Large button size |
// Complete API Example
const group = Domma.elements.buttonGroup('#my-group', {
mode: 'multiple',
activeClass: 'selected',
allowEmpty: true,
onChange: (value, index, button) => {
console.log('Selection changed:', value);
console.log('Triggered by button at index:', index);
}
});
// Methods
group.setValue([0, 2]); // Select first and third buttons
const active = group.getValue(); // Get active indices: [0, 2]
const buttons = group.getActive(); // Get button elements
group.toggle(1); // Toggle second button
group.selectAll(); // Select all (multiple mode only)
group.deselectAll(); // Clear all selections
group.destroy(); // Clean up when done
Config Engine Integration
Use Domma's declarative $.setup() system to configure Button Groups without manual initialisation.
Basic Setup
$.setup({
'#view-toggle': {
component: 'buttonGroup',
options: {
mode: 'single',
onChange: (value) => {
console.log('Selected:', value);
}
}
}
});
Multiple Button Groups
$.setup({
// View selector (single mode)
'#view-selector': {
component: 'buttonGroup',
options: {
mode: 'single',
allowEmpty: false,
onChange: (value) => {
updateView(['day', 'week', 'month'][value]);
}
}
},
// Format toolbar (multiple mode)
'#format-toolbar': {
component: 'buttonGroup',
options: {
mode: 'multiple',
onChange: (values) => {
applyFormatting(values);
}
}
},
// Category filter
'#category-filter': {
component: 'buttonGroup',
options: {
mode: 'single',
allowEmpty: true,
activeClass: 'selected'
}
}
});
Live Demo
Button Group configured via Config Engine:
Selected: Option 1
<div class="btn-group" id="config-demo-group">
<button type="button" class="btn btn-outline active">Option 1</button>
<button type="button" class="btn btn-outline">Option 2</button>
<button type="button" class="btn btn-outline">Option 3</button>
</div>
<p class="text-sm text-muted mt-2">Selected: <strong id="config-demo-value">Option 1</strong></p>/**
* Live Demo - from public/showcase/elements/button-group.
*/
export function mount(root) {
// Config Engine Demo
$.setup({
'#config-demo-group': {
component: 'buttonGroup',
options: {
mode: 'single',
onChange: (value) => {
const labels = ['Option 1', 'Option 2', 'Option 3'];
$(root).find('#config-demo-value').text(labels[value]);
}
}
}
});
}// Configuration
$.setup({
'#config-demo-group': {
component: 'buttonGroup',
options: {
mode: 'single',
onChange: (value) => {
const labels = ['Option 1', 'Option 2', 'Option 3'];
$('#config-demo-value').text(labels[value]);
}
}
}
});
// Access instance later
const group = Domma.elements.get('#config-demo-group');
group.setValue(1); // Programmatic control still works
CSS Customisation
Override these CSS variables to customise Button Group appearance and match your design system.
| Variable | Default | Controls |
|---|---|---|
--dm-primary |
var(--dm-blue-600) |
Active button colour |
--dm-primary-hover |
var(--dm-blue-700) |
Active button hover |
--dm-border |
var(--dm-slate-300) |
Button border colour |
--dm-radius-md |
0.375rem |
Button corner radius |
Example Override
:root {
/* Flat button group */
--dm-border: transparent;
}
Full CSS Customisation Cheat-Sheet →
Related Elements
Tabs
Organise content into tabbed panels. Button Groups work great as custom tab controls with manual tab switching.
Forms
Form components including checkboxes, radios, and input groups. Button Groups provide a more visual alternative to radio/checkbox inputs.
Dropdown
Toggleable dropdown menus. Combine with Button Groups to create split button dropdowns or segmented controls.
Navbar
Responsive navigation bars. Button Groups can be embedded in navbars for view toggles and action groups.
List Group
Selectable list items for single or multi-select scenarios where a list layout suits better than a button row.
<div class="grid grid-cols-1 gap-4 grid-auto-fit-250"><a href="/showcase/elements/tabs" class="card card-hover">
<div class="card-body">
<h3 class="card-title">Tabs</h3>
<p class="card-text">Organise content into tabbed panels. Button Groups work great as custom tab
controls with manual tab switching.</p>
</div>
</a>
<a href="/showcase/elements/forms" class="card card-hover">
<div class="card-body">
<h3 class="card-title">Forms</h3>
<p class="card-text">Form components including checkboxes, radios, and input groups. Button Groups
provide a more visual alternative to radio/checkbox inputs.</p>
</div>
</a>
<a href="/showcase/elements/dropdown" class="card card-hover">
<div class="card-body">
<h3 class="card-title">Dropdown</h3>
<p class="card-text">Toggleable dropdown menus. Combine with Button Groups to create split button
dropdowns or segmented controls.</p>
</div>
</a>
<a href="/showcase/elements/navbar" class="card card-hover">
<div class="card-body">
<h3 class="card-title">Navbar</h3>
<p class="card-text">Responsive navigation bars. Button Groups can be embedded in navbars for view
toggles and action groups.</p>
</div>
</a>
<a href="/showcase/elements/list-group" class="card card-hover">
<div class="card-body">
<h3 class="card-title">List Group</h3>
<p class="card-text">Selectable list items for single or multi-select scenarios where a list layout suits better than a button row.</p>
</div>
</a>
</div>