Button Group

Demo

Animal

				
					
<div id="csp-button-group">
<!-- We give this <div> a role of "group". Typically, screen readers 
     will let users know when they enter and leave a group, which helps 
     users understand when controls are related.
-->
<!-- What do these attributes mean?
     - role: provides an accessible role to the element. "group" sigifies 
             a grouping related content or user controls.
     - aria-labelledby: provides an accessible name for this element. In 
             regards to elements with a "group" role, the accessible name 
             will typically be read by AT when a user enters and leaves the 
             group.
     - data-btn-group: this is used to signify that this is a button group 
             component, used in the javascript.
     - aria-pressed: this is a state. When true the element is "pressed". 
             Similar to a radio button's checked state.
-->
    <div role="group" 
         aria-labelledby="group-legend-animal">
        <h2 id="group-legend-animal">Animal</h2>
        <div class="inner-group">
            <button aria-pressed="false">Cat</button>
            <button aria-pressed="false">Dog</button>
            <button aria-pressed="false">Frog</button>
            <button aria-pressed="false">Rat</button>
            <button aria-pressed="false">Hamster</button>
        </div>
    </div>
</div>
				
			
				
					
#csp-button-group {
    button {
        /* Set the pressed button visual styling.
         * 1.4.11 Non-text Content and 1.4.1 Use of Color are 
         * relvant success criteria.
         * Essentially, we need to make sure that the different
         * states (pressed versus not pressed) are visually
         * perceptible. This state is programmatically perceptible
         * by adding the aria-pressed attribute as noted in the HTML.
         */
        &[aria-pressed="true"] {
            color: white;
            background-color: #333;
            text-decoration: underline;
        }

        /* We override the default focus indicator by setting our
         * own outline.
         */
         &:focus {
            outline: 0.2rem solid black;
            outline-offset: 0.15rem;
        }

        /* visual styling */
        padding: 0.5rem 0.7rem;
        cursor: pointer;
        color: black;
        background-color: buttonface;
        border: 1px solid;
        border-radius: 2px;

        &:hover {
            color: black;
            background-color: white;
        }
    }

    /* Flex with flex-wrap allows the button group to wrap 
     * if the viewport is small. The 1.4.4 Text Resizing 
     * 1.4.10 Reflow Success Criteria are relevant here.
     *
     * Gap provides spacing between each button. Without it the
     * focus indicator may overlap with other buttons.
     */
    .inner-group {
        display: flex;
        flex-wrap: wrap;
        gap: 0.9rem;
    }

    /* Provides visual styling */
    [role="group"] {
        border: 1px solid #555;
        padding: 0.5rem;
        width: fit-content;
    }

    [role="group"] :is(h1, h2, h3, h4, h5, h6) {
        background-color: white;
        margin: 0;
        margin-bottom: 1rem;
        font-size: 1.4rem;
    }
}
				
			
				
					
(() => {
    main();

    function main() {
        let context = document.getElementById('csp-button-group');
        // we get all buttons in the widget
        let buttons = context.querySelectorAll('button');
        for (let button of buttons) {
            button.addEventListener('click', togglePressed);
        }
    }

    function togglePressed(e) {
        let button = e.currentTarget;
        let buttons = 
            e.currentTarget
             .closest('[role="group"]')
             .querySelectorAll('button');
        // remove any other buttons pressed state
        for (let otherButton of buttons) {
            otherButton.setAttribute('aria-pressed', 'false');
        }
        // set the current button pressed state to true
        button.setAttribute('aria-pressed', 'true');
    }
})();

				
			

Why use a button group?

Button groups offer a visually cohesive and organized way to present a set of related actions or options. By grouping buttons together, they provide a clear visual hierarchy that guides users to select from a defined set of choices, making the interface more user-friendly and intuitive. Button groups are especially useful when dealing with tasks like filtering content, navigating between views, or selecting preferences. They promote consistency in design and layout, enhance user engagement by making options readily accessible, and contribute to a more efficient and streamlined user experience. Additionally, button groups can be responsive, adapting to different screen sizes, and they are customizable, allowing designers to tailor their appearance to align with the overall aesthetics of the website or application.

What are some accessibility concerns?

  • Keyboard Navigation:
    • Ensure that all buttons within the group are keyboard accessible. Users should be able to navigate and select buttons using the Tab key, and the currently focused button should be visually distinguishable.
  • Focus Management:
    • When a button is selected, manage focus appropriately within the button group. Set focus to the selected button or its associated content, ensuring that users can easily navigate through the group.
  • Semantic Markup:
    • Use semantic HTML elements (e.g., <button> or <a>) to provide meaning to the buttons within the group. This helps screen readers understand the purpose and action associated with each button.
  • Button Labels:
    • Ensure that button labels are descriptive and convey the purpose of each button. Avoid vague labels like “click here” and provide clear, concise text that explains the action.
  • Color and Contrast:
    • Be mindful of color choices and contrast within the button group. Ensure that text and button backgrounds have sufficient contrast for users with low vision or color blindness.
  • Active and Disabled States:
    • Clearly indicate when a button is active, selected, or disabled, using visual cues and ARIA roles/attributes, to help users understand the state of each button within the group.
  • Alternative Content:
    • If the button group interacts with dynamic content changes or filters, provide alternative ways for users to access and understand these changes, especially for those who rely on screen readers.
Tested using
Chrome
with NVDA
Firefox
with NVDA
  • W3C SVG
    1.4.1
    Use of Color ( level A ) :
    Color is not used as the only visual means of conveying information, indicating an action, prompting a response, or distinguishing a visual element.
  • W3C SVG
    2.4.3
    Focus Order ( level A ) :
    If a Web page can be navigated sequentially and the navigation sequences affect meaning or operation, focusable components receive focus in an order that preserves meaning and operability.
  • W3C SVG
    2.4.6
    Headings and Labels ( level AA ) :
    Headings and labels describe topic or purpose.
  • W3C SVG
    4.1.2
    Name, Role, Value ( level A ) :
    For all user interface components (including but not limited to: form elements, links and components generated by scripts), the name and role can be programmatically determined; states, properties, and values that can be set by the user can be programmatically set; and notification of changes to these items is available to user agents, including assistive technologies.