ButtonGroup
A button group consists of a set of two or more normal buttons. Buttons in such a group signal a number of equally important actions that will occur when the user taps on them.
Guidelines
When to use button groups
Each button within the button group must have a label. For icon-only buttons, the label will be visually hidden and available only to users of assistive technology.
Use the ButtonGroup component when you want users to choose actions from a set of actions, with the restriction that only one can be active at a time. If you want to enable users to select one or multiple options from a set of options, use ToggleButtonGroup instead.
Specifications
A button group consists of a minimum of two normal (framed) buttons, which may include the following elements:
- Icon (optional)
Icons simplify user recognition and provide the ability to shorten button labels to a minimum. - Label
Button labels should be as short as possible, with text that clearly states what action will be taken once the button is pressed (e.g. download, submit form, search).
Component limitations
There is no maximum limit on the number of buttons per group. The width of the button group will adjust to accommodate the expanding text within each button. If the total width of the button group surpasses the maximum width of @max-width-button
(equivalent to 448px
in the default Codex theme), the buttons will be wrapped into the next line.
Refer to the ButtonGroup component in Codex Figma.
Interaction states
Button groups have the following visually separate states:
- Default buttons
- Hover on one button
- Active button
- Focus on one button
- Disabled button
- Disabled button group
Best practices
Consider the following recommendations when working with button groups.
Buttons within the group
- Only neutral normal Buttons can be used within the ButtonGroup component.
- Use other flavors or weights of a Button within the ButtonGroup component.
Button’s content
- Customize the content of each button, allowing for superscript, subscript, or special characters.
- Use numbers instead of text if needed.
- Mix text-only and icon-only buttons exclusively when using the ‘ellipsis‘ icon to indicate additional actions.
- In order to ensure consistency, avoid mixing different types of button contents within the same ButtonGroup.
Icon-only buttons
- Icon-only buttons may be used to form a ButtonGroup but only if the icons used are universally understood and do not require accompanying text.
- Use icon-only buttons if the icons are not easy to understand or do not clearly communicate their purpose.
Keyboard navigation
Key | Function |
---|---|
Tab | It moves the focus to the next Button within the group or to the next interactive element in tab order when the focus is placed on the last Button of the group. |
Shift + Tab | It moves the focus to the previous Button within the group or to the previous interactive element when the focus is placed on the first Button of the group. |
Enter / Space | If the focus is placed on one of the buttons, it activates that Button. |
Demos
Open up the browser console to see events emitted on click.
Basic usage
Describe the buttons in the group with an array of ButtonGroupItem
objects. The text in the label
property will be displayed in the buttons. When a button is clicked, a click
event will be emitted with the value
property of the clicked button. Values must be unique within a button group.
If the label
property is omitted, the value
property will be used as the label. This allows using { value: 'Foo' }
as a shorthand for { label: 'Foo', value: 'Foo' }
.
<template>
<cdx-button-group
:buttons="buttons"
@click="onClick"
/>
</template>
<script>
import { defineComponent } from 'vue';
import { CdxButtonGroup } from '@wikimedia/codex';
export default defineComponent( {
name: 'BasicButtonGroup',
components: {
CdxButtonGroup
},
setup() {
const buttons = [
{ value: 1, label: 'One' },
{ value: 2, label: 'Two' },
{ value: 3, label: 'Three' },
{ value: 4, label: 'Four' },
{ value: 5, label: 'Five' }
];
function onClick( value ) {
// eslint-disable-next-line no-console
console.log( 'click event emitted with value:', value );
}
return {
buttons,
onClick
};
}
} );
</script>
<template>
<cdx-button-group
:buttons="buttons"
@click="onClick"
></cdx-button-group>
</template>
<script>
const { defineComponent } = require( 'vue' );
const { CdxButtonGroup } = require( '@wikimedia/codex' );
module.exports = defineComponent( {
name: 'BasicButtonGroup',
components: {
CdxButtonGroup
},
setup() {
const buttons = [
{ value: 1, label: 'One' },
{ value: 2, label: 'Two' },
{ value: 3, label: 'Three' },
{ value: 4, label: 'Four' },
{ value: 5, label: 'Five' }
];
function onClick( value ) {
// eslint-disable-next-line no-console
console.log( 'click event emitted with value:', value );
}
return {
buttons,
onClick
};
}
} );
</script>
Name | Value |
---|---|
View | |
Reading direction |
With icons
Use the icon
property to add an icon before the text of a button. Use the disabled
property to disable individual buttons.
<template>
<cdx-button-group
:buttons="buttons"
@click="onClick"
/>
</template>
<script>
import { defineComponent } from 'vue';
import { CdxButtonGroup } from '@wikimedia/codex';
import { cdxIconEdit, cdxIconSpeechBubble, cdxIconCheck, cdxIconDownload, cdxIconTrash } from '@wikimedia/codex-icons';
export default defineComponent( {
name: 'ButtonGroupWithIcons',
components: {
CdxButtonGroup
},
setup() {
const buttons = [
{ value: 'edit', label: 'Edit', icon: cdxIconEdit },
{ value: 'talk', label: 'Discuss', icon: cdxIconSpeechBubble },
{ value: 'save', label: 'Done', icon: cdxIconCheck, disabled: true },
{ value: 'download', label: 'Download', icon: cdxIconDownload, disabled: true },
{ value: 'delete', label: 'Delete', icon: cdxIconTrash }
];
function onClick( value ) {
// eslint-disable-next-line no-console
console.log( 'click event emitted with value:', value );
}
return {
buttons,
onClick
};
}
} );
</script>
<template>
<cdx-button-group
:buttons="buttons"
@click="onClick"
></cdx-button-group>
</template>
<script>
const { defineComponent } = require( 'vue' );
const { CdxButtonGroup } = require( '@wikimedia/codex' );
const { cdxIconEdit, cdxIconSpeechBubble, cdxIconCheck, cdxIconDownload, cdxIconTrash } = require( './icons.json' );
module.exports = defineComponent( {
name: 'ButtonGroupWithIcons',
components: {
CdxButtonGroup
},
setup() {
const buttons = [
{ value: 'edit', label: 'Edit', icon: cdxIconEdit },
{ value: 'talk', label: 'Discuss', icon: cdxIconSpeechBubble },
{ value: 'save', label: 'Done', icon: cdxIconCheck, disabled: true },
{ value: 'download', label: 'Download', icon: cdxIconDownload, disabled: true },
{ value: 'delete', label: 'Delete', icon: cdxIconTrash }
];
function onClick( value ) {
// eslint-disable-next-line no-console
console.log( 'click event emitted with value:', value );
}
return {
buttons,
onClick
};
}
} );
</script>
Icon-only buttons
To display an icon as the only content of a button, use the icon
property to specify an icon, and set the label
property to null
.
<template>
<cdx-button-group
:buttons="buttons"
@click="onClick"
/>
</template>
<script>
import { defineComponent } from 'vue';
import { CdxButtonGroup } from '@wikimedia/codex';
import { cdxIconEdit, cdxIconSpeechBubble, cdxIconCheck, cdxIconDownload, cdxIconTrash } from '@wikimedia/codex-icons';
export default defineComponent( {
name: 'IconOnlyButtonGroup',
components: {
CdxButtonGroup
},
setup() {
const buttons = [
{ value: 'edit', label: null, icon: cdxIconEdit, ariaLabel: 'Edit' },
{ value: 'talk', label: null, icon: cdxIconSpeechBubble, ariaLabel: 'Discuss' },
{ value: 'save', label: null, icon: cdxIconCheck, ariaLabel: 'Done', disabled: true },
{ value: 'download', label: null, icon: cdxIconDownload, ariaLabel: 'Download', disabled: true },
{ value: 'delete', label: null, icon: cdxIconTrash, ariaLabel: 'Delete' }
];
function onClick( value ) {
// eslint-disable-next-line no-console
console.log( 'click event emitted with value:', value );
}
return {
buttons,
onClick
};
}
} );
</script>
<template>
<cdx-button-group
:buttons="buttons"
@click="onClick"
></cdx-button-group>
</template>
<script>
const { defineComponent } = require( 'vue' );
const { CdxButtonGroup } = require( '@wikimedia/codex' );
const { cdxIconEdit, cdxIconSpeechBubble, cdxIconCheck, cdxIconDownload, cdxIconTrash } = require( './icons.json' );
module.exports = defineComponent( {
name: 'IconOnlyButtonGroup',
components: {
CdxButtonGroup
},
setup() {
const buttons = [
{ value: 'edit', label: null, icon: cdxIconEdit, ariaLabel: 'Edit' },
{ value: 'talk', label: null, icon: cdxIconSpeechBubble, ariaLabel: 'Discuss' },
{ value: 'save', label: null, icon: cdxIconCheck, ariaLabel: 'Done', disabled: true },
{ value: 'download', label: null, icon: cdxIconDownload, ariaLabel: 'Download', disabled: true },
{ value: 'delete', label: null, icon: cdxIconTrash, ariaLabel: 'Delete' }
];
function onClick( value ) {
// eslint-disable-next-line no-console
console.log( 'click event emitted with value:', value );
}
return {
buttons,
onClick
};
}
} );
</script>
Disabled
The entire component can be disabled by setting the disabled
prop. Individual buttons can be disabled by setting their .disabled
property. Clicking a disabled button does not emit a click
event.
<template>
<cdx-button-group
:buttons="buttons"
:disabled="true"
@click="onClick"
/>
</template>
<script>
import { defineComponent } from 'vue';
import { CdxButtonGroup } from '@wikimedia/codex';
export default defineComponent( {
name: 'DisabledButtonGroup',
components: {
CdxButtonGroup
},
setup() {
const buttons = [
{ value: 1, label: 'One' },
{ value: 2, label: 'Two' },
{ value: 3, label: 'Three' },
{ value: 4, label: 'Four', disabled: true },
{ value: 5, label: 'Five' }
];
function onClick( value ) {
// eslint-disable-next-line no-console
console.log( 'click event emitted with value:', value );
}
return {
buttons,
onClick
};
}
} );
</script>
<template>
<cdx-button-group
:buttons="buttons"
:disabled="true"
@click="onClick"
></cdx-button-group>
</template>
<script>
const { defineComponent } = require( 'vue' );
const { CdxButtonGroup } = require( '@wikimedia/codex' );
module.exports = defineComponent( {
name: 'DisabledButtonGroup',
components: {
CdxButtonGroup
},
setup() {
const buttons = [
{ value: 1, label: 'One' },
{ value: 2, label: 'Two' },
{ value: 3, label: 'Three' },
{ value: 4, label: 'Four', disabled: true },
{ value: 5, label: 'Five' }
];
function onClick( value ) {
// eslint-disable-next-line no-console
console.log( 'click event emitted with value:', value );
}
return {
buttons,
onClick
};
}
} );
</script>
Overflowing buttons
When the button group is too large to fit on one line, the buttons overflow to the next line.
<template>
<cdx-button-group
:buttons="buttons"
@click="onClick"
/>
</template>
<script>
import { defineComponent } from 'vue';
import { CdxButtonGroup } from '@wikimedia/codex';
export default defineComponent( {
name: 'MaximumButtonGroup',
components: {
CdxButtonGroup
},
setup() {
const buttons = [
{ value: 1, label: 'First button' },
{ value: 2, label: 'Second button' },
{ value: 3, label: 'Third button with a long label' },
{ value: 4, label: 'Fourth button with a long label' },
{ value: 5, label: 'Fifth button' }
];
function onClick( value ) {
// eslint-disable-next-line no-console
console.log( 'click event emitted with value:', value );
}
return {
buttons,
onClick
};
}
} );
</script>
<template>
<cdx-button-group
:buttons="buttons"
@click="onClick"
></cdx-button-group>
</template>
<script>
const { defineComponent } = require( 'vue' );
const { CdxButtonGroup } = require( '@wikimedia/codex' );
module.exports = defineComponent( {
name: 'MaximumButtonGroup',
components: {
CdxButtonGroup
},
setup() {
const buttons = [
{ value: 1, label: 'First button' },
{ value: 2, label: 'Second button' },
{ value: 3, label: 'Third button with a long label' },
{ value: 4, label: 'Fourth button with a long label' },
{ value: 5, label: 'Fifth button' }
];
function onClick( value ) {
// eslint-disable-next-line no-console
console.log( 'click event emitted with value:', value );
}
return {
buttons,
onClick
};
}
} );
</script>
Custom button display
The contents of the buttons can be customized using the default slot. The ButtonGroupItem
object for each button is available through the button
binding. In this example, the value of the button is displayed in superscript after its label.
<template>
<cdx-button-group
:buttons="buttons"
@click="onClick"
>
<template #default="{ button }">
{{ button.label }}
<sup>
({{ button.value }})
</sup>
</template>
</cdx-button-group>
</template>
<script>
import { defineComponent } from 'vue';
import { CdxButtonGroup } from '@wikimedia/codex';
export default defineComponent( {
name: 'ButtonGroupWithSlot',
components: {
CdxButtonGroup
},
setup() {
const buttons = [
{ value: 1, label: 'One' },
{ value: 2, label: 'Two' }
];
function onClick( value ) {
// eslint-disable-next-line no-console
console.log( 'click event emitted with value:', value );
}
return {
buttons,
onClick
};
}
} );
</script>
<template>
<cdx-button-group
:buttons="buttons"
@click="onClick"
>
<template #default="{ button }">
{{ button.label }}
<sup>
({{ button.value }})
</sup>
</template>
</cdx-button-group>
</template>
<script>
const { defineComponent } = require( 'vue' );
const { CdxButtonGroup } = require( '@wikimedia/codex' );
module.exports = defineComponent( {
name: 'ButtonGroupWithSlot',
components: {
CdxButtonGroup
},
setup() {
const buttons = [
{ value: 1, label: 'One' },
{ value: 2, label: 'Two' }
];
function onClick( value ) {
// eslint-disable-next-line no-console
console.log( 'click event emitted with value:', value );
}
return {
buttons,
onClick
};
}
} );
</script>
Vue usage
Props
Prop name | Description | Type | Default |
---|---|---|---|
buttons (required) | Objects describing the buttons in the group. See the ButtonGroupItem type. | ButtonGroupItem[] | |
disabled | Whether the entire group is disabled. If this is set to true, all buttons in the group are disabled. Buttons can also be disabled individually by setting their disabled property to true. | boolean | false |
Events
Event name | Properties | Description |
---|---|---|
click | value string|number - The value property of the button that was clicked | Emitted when a button is clicked |
Slots
Name | Description | Bindings |
---|---|---|
default | Content of an individual button | button ButtonGroupItem - Object describing the button to display |