## Description

`sp-action-group` delivers a set of action buttons in horizontal or vertical orientation while ensuring the appropriate spacing between those buttons. The `compact` attribute merges these buttons so that they are visually joined to clarify their relationship to each other and their distance from other buttons/groups.

### Usage

[![See it on NPM!](https://img.shields.io/npm/v/@spectrum-web-components/action-group?style=for-the-badge)](https://www.npmjs.com/package/@spectrum-web-components/action-group)
[![How big is this package in your project?](https://img.shields.io/bundlephobia/minzip/@spectrum-web-components/action-group?style=for-the-badge)](https://bundlephobia.com/result?p=@spectrum-web-components/action-group)
[![Try it on Stackblitz](https://img.shields.io/badge/Try%20it%20on-Stackblitz-blue?style=for-the-badge)](https://stackblitz.com/edit/vitejs-vite-xskzaswz)

```
yarn add @spectrum-web-components/action-group
```

Import the side effectful registration of `<sp-action-group>` via:

```
import '@spectrum-web-components/action-group/sp-action-group.js';
```

When looking to leverage the `ActionGroup` base class as a type and/or for extension purposes, do so via:

```
import { ActionGroup } from '@spectrum-web-components/action-group';
```

## Sizes

<sp-tabs selected="m" auto label="Size Attribute Options">
<sp-tab value="xs">Extra Small</sp-tab>
<sp-tab-panel value="xs">

```html demo
<sp-action-group size="xs">
    <sp-action-button>Extra Small 1</sp-action-button>
    <sp-action-button>Extra Small 2</sp-action-button>
</sp-action-group>
```

</sp-tab-panel>
<sp-tab value="s">Small</sp-tab>
<sp-tab-panel value="s">

```html demo
<sp-action-group size="s">
    <sp-action-button>Small 1</sp-action-button>
    <sp-action-button>Small 2</sp-action-button>
</sp-action-group>
```

</sp-tab-panel>
<sp-tab value="m">Medium</sp-tab>
<sp-tab-panel value="m">

```html demo
<sp-action-group size="m">
    <sp-action-button>Medium 1</sp-action-button>
    <sp-action-button>Medium 2</sp-action-button>
</sp-action-group>
```

</sp-tab-panel>
<sp-tab value="l">Large</sp-tab>
<sp-tab-panel value="l">

```html demo
<sp-action-group size="l">
    <sp-action-button>Large 1</sp-action-button>
    <sp-action-button>Large 2</sp-action-button>
</sp-action-group>
```

</sp-tab-panel>
<sp-tab value="xl">Extra Large</sp-tab>
<sp-tab-panel value="xl">

```html demo
<sp-action-group size="xl">
    <sp-action-button>Extra Large 1</sp-action-button>
    <sp-action-button>Extra Large 2</sp-action-button>
</sp-action-group>
```

</sp-tab-panel>
</sp-tabs>

## Selects

An `<sp-action-group selects="single|multiple">` will manage a `selected` property that consists on an array of the `<sp-action-button>` children that are currently selected. A `change` event is dispatched from the `<sp-action-group>` element when the value of `selected` is updated. This event can be canceled via `event.preventDefault()`, after which the value of `selected` will be returned to what it was previously.

When a selection can be made, it is a good idea to supply the group of options with accessible text that names the group of buttons. This can be done in a non-visual way via the `label` attribute of the `<sp-action-group>` element. You can also associate the `<sp-action-group>` to a second, visible DOM element via the `aria-labelledby` attribute or, when available, via the `for` attribute on the second element to make the association in the other direction.

### Single

An `<sp-action-group selects="single">` will manage its `<sp-action-button>` children as "radio buttons" allowing the user to select a _single_ one of the buttons presented. The `<sp-action-button>` children will only be able to turn their `selected` value on while maintaining a single selection after an initial selection is made.

```html
<sp-action-group
    selects="single"
    emphasized
    label="Single Selection Demo Group"
>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Button 1
    </sp-action-button>
    <sp-action-button selected>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Longer Button 2
    </sp-action-button>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Short 3
    </sp-action-button>
</sp-action-group>
```

### Multiple

An `<sp-action-group selects="multiple">` will manage its `<sp-action-button>` children as "checkboxes" allowing the user to select a _multiple_ of the buttons presented. The `<sp-action-button>` children will toggle their `selected` value on and off when clicked successively.

```html
<sp-action-group
    selects="multiple"
    emphasized
    label="Multiple Selection Demo Group"
>
    <sp-action-button selected>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Button 1
    </sp-action-button>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Longer Button 2
    </sp-action-button>
    <sp-action-button selected>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Short 3
    </sp-action-button>
</sp-action-group>
```

## Selected

The `selected` property represents the selection state within a button group. This property can be managed either by the component or by the user. Passing in an array of button values will make `<sp-action-group>` a controllable component. Though `selected` would more commonly be set via Javascript expressions (i.e. `<sp-action-group .selected=${["first"]}>`), it is also possible to set `selected` as a JSON string.

```html
<sp-action-group selects="single" selected='["first"]'>
    <sp-action-button value="first">First</sp-action-button>
    <sp-action-button value="second">Second</sp-action-button>
</sp-action-group>
```

By default, an `<sp-action-group>` will select any button passed into `selected`. Afterwards, `.selects` controls how button values are added to the selection state. For example, if `.selects` is not specified when `selected` is set, any further interaction will result in no change to the selection.

```html
<sp-action-group selected='["first", "second"]'>
    <sp-action-button value="first">First</sp-action-button>
    <sp-action-button value="second">Second</sp-action-button>
    <sp-action-button value="third">Third</sp-action-button>
</sp-action-group>
```

Similarly, if `selected` contains more than one button value, but `selects = "single"`, then those initial buttons will be highlighted, but further interaction will result in radio-button functionality.

```html
<sp-action-group selects="single" selected='["first", "second"]'>
    <sp-action-button value="first">First</sp-action-button>
    <sp-action-button value="second">Second</sp-action-button>
    <sp-action-button value="third">Third</sp-action-button>
</sp-action-group>
```

## Horizontal

By default, an `<sp-action-group>` will organize its child buttons horizontally and the delivery of those buttons can be modified with the `compact`, `emphasized`, or `quiet` attributes.

```html
<sp-action-group>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Button 1
    </sp-action-button>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Longer Button 2
    </sp-action-button>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Short 3
    </sp-action-button>
</sp-action-group>
<br />
<sp-action-group compact>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Button 1
    </sp-action-button>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Longer Button 2
    </sp-action-button>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Short 3
    </sp-action-button>
</sp-action-group>
<br />
<sp-action-group quiet>
    <sp-action-button label="Zoom in">
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
    </sp-action-button>
    <sp-action-button label="Zoom in">
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
    </sp-action-button>
    <sp-action-button label="Zoom in">
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
    </sp-action-button>
</sp-action-group>
<br />
<sp-action-group compact emphasized>
    <sp-action-button label="Zoom in">
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
    </sp-action-button>
    <sp-action-button label="Zoom in">
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
    </sp-action-button>
    <sp-action-button label="Zoom in">
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
    </sp-action-button>
</sp-action-group>
```

## Vertical

The use of the `vertical` attribute instructs the `<sp-action-group>` element to organize its child buttons vertically, while accepting the same `compact`, `emphasized`, and `quiet` attributes as modifiers.

```html
<div style="display: flex; justify-content: space-around;">
    <sp-action-group vertical>
        <sp-action-button>
            <sp-icon-magnify slot="icon"></sp-icon-magnify>
            Button 1
        </sp-action-button>
        <sp-action-button>
            <sp-icon-magnify slot="icon"></sp-icon-magnify>
            Longer Button 2
        </sp-action-button>
        <sp-action-button>
            <sp-icon-magnify slot="icon"></sp-icon-magnify>
            Short 3
        </sp-action-button>
    </sp-action-group>
    <sp-action-group vertical compact>
        <sp-action-button>
            <sp-icon-magnify slot="icon"></sp-icon-magnify>
            Button 1
        </sp-action-button>
        <sp-action-button>
            <sp-icon-magnify slot="icon"></sp-icon-magnify>
            Longer Button 2
        </sp-action-button>
        <sp-action-button>
            <sp-icon-magnify slot="icon"></sp-icon-magnify>
            Short 3
        </sp-action-button>
    </sp-action-group>
    <sp-action-group vertical quiet>
        <sp-action-button label="Zoom in">
            <sp-icon-magnify slot="icon"></sp-icon-magnify>
        </sp-action-button>
        <sp-action-button label="Zoom in">
            <sp-icon-magnify slot="icon"></sp-icon-magnify>
        </sp-action-button>
        <sp-action-button label="Zoom in">
            <sp-icon-magnify slot="icon"></sp-icon-magnify>
        </sp-action-button>
    </sp-action-group>
    <sp-action-group compact vertical>
        <sp-action-button label="Zoom in">
            <sp-icon-magnify slot="icon"></sp-icon-magnify>
        </sp-action-button>
        <sp-action-button label="Zoom in">
            <sp-icon-magnify slot="icon"></sp-icon-magnify>
        </sp-action-button>
        <sp-action-button label="Zoom in">
            <sp-icon-magnify slot="icon"></sp-icon-magnify>
        </sp-action-button>
    </sp-action-group>
</div>
```

## Justified

The `justified` attribute will cause the `<sp-action-group>` element to fill the available horizontal space and evenly distribute that space across its child button elements.

```html
<sp-action-group justified>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Button 1
    </sp-action-button>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Longer Button 2
    </sp-action-button>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Short 3
    </sp-action-button>
</sp-action-group>
<br />
<sp-action-group justified compact>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Button 1
    </sp-action-button>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Longer Button 2
    </sp-action-button>
    <sp-action-button>
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
        Short 3
    </sp-action-button>
</sp-action-group>
<br />
<sp-action-group justified quiet>
    <sp-action-button label="Zoom in">
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
    </sp-action-button>
    <sp-action-button label="Zoom in">
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
    </sp-action-button>
    <sp-action-button label="Zoom in">
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
    </sp-action-button>
</sp-action-group>
<br />
<sp-action-group compact justified>
    <sp-action-button label="Zoom in">
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
    </sp-action-button>
    <sp-action-button label="Zoom in">
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
    </sp-action-button>
    <sp-action-button label="Zoom in">
        <sp-icon-magnify slot="icon"></sp-icon-magnify>
    </sp-action-button>
</sp-action-group>
```

## Accessibility

The accessibility `role` for an `<sp-action-group>` element depends on the manner in which items are selected. By default, `<sp-action-group selects="single">` will have `role="radiogroup"`, because it manages its children as a "radio group", while `<sp-action-group>` or `<sp-action-group selects="multiple">` will have `role="toolbar"`, which makes sense for a group of buttons or checkboxes between which one can navigate using the arrow keys.

When more than one `<sp-action-group>` elements are combined together with in a toolbar, the `role` attribute for `<sp-action-group>` or `<sp-action-group selects="multiple">` should be overwritten using `role="group"` or `role="presentation"`, so that toolbars are not nested, as demonstrated in the following example of a hypothetical toolbar for formatting text within a rich text editor:

<script type="module">
    import '@spectrum-web-components/divider/sp-divider.js';
    import '@spectrum-web-components/icons-workflow/icons/sp-icon-text-bold.js';
    import '@spectrum-web-components/icons-workflow/icons/sp-icon-text-italic.js';
    import '@spectrum-web-components/icons-workflow/icons/sp-icon-text-underline.js';
    import '@spectrum-web-components/icons-workflow/icons/sp-icon-text-align-left.js';
    import '@spectrum-web-components/icons-workflow/icons/sp-icon-text-align-center.js';
    import '@spectrum-web-components/icons-workflow/icons/sp-icon-text-align-justify.js';
    import '@spectrum-web-components/icons-workflow/icons/sp-icon-text-align-right.js';
    import '@spectrum-web-components/icons-workflow/icons/sp-icon-text-bulleted.js';
    import '@spectrum-web-components/icons-workflow/icons/sp-icon-text-numbered.js';
    import '@spectrum-web-components/icons-workflow/icons/sp-icon-copy.js';
    import '@spectrum-web-components/icons-workflow/icons/sp-icon-paste.js';
    import '@spectrum-web-components/icons-workflow/icons/sp-icon-cut.js';
</script>

```html
<div
    aria-label="Text Formatting"
    role="toolbar"
    style="height: 32px; display: flex; gap: 6px"
>
    <sp-action-group
        aria-label="Text Style"
        selects="multiple"
        role="group"
        compact
        emphasized
    >
        <sp-action-button label="Bold" value="bold">
            <sp-icon-text-bold slot="icon"></sp-icon-text-bold>
        </sp-action-button>
        <sp-action-button label="Italic" value="italic">
            <sp-icon-text-italic slot="icon"></sp-icon-text-italic>
        </sp-action-button>
        <sp-action-button label="Underline" value="underline">
            <sp-icon-text-underline slot="icon"></sp-icon-text-underline>
        </sp-action-button>
    </sp-action-group>
    <sp-divider
        size="s"
        style="align-self: stretch; height: auto;"
        vertical
    ></sp-divider>
    <sp-action-group
        aria-label="Text Align"
        selects="single"
        compact
        emphasized
    >
        <sp-action-button label="Left" value="left" selected>
            <sp-icon-text-align-left slot="icon"></sp-icon-text-align-left>
        </sp-action-button>
        <sp-action-button label="Center" value="center">
            <sp-icon-text-align-center slot="icon"></sp-icon-text-align-center>
        </sp-action-button>
        <sp-action-button label="Right" value="right">
            <sp-icon-text-align-right slot="icon"></sp-icon-text-align-right>
        </sp-action-button>
        <sp-action-button label="Justify" value="justify">
            <sp-icon-text-align-justify
                slot="icon"
            ></sp-icon-text-align-justify>
        </sp-action-button>
    </sp-action-group>
    <sp-divider
        size="s"
        style="align-self: stretch; height: auto;"
        vertical
    ></sp-divider>
    <sp-action-group
        aria-label="List Style"
        selects="multiple"
        role="group"
        compact
        emphasized
    >
        <sp-action-button
            label="Bulleted"
            value="bulleted"
            onclick="
                /* makes mutually exclusive checkbox */
                this.selected &&
                    requestAnimationFrame(() => this.parentElement.selected = []);
                this.parentElement.selected = [];
            "
        >
            <sp-icon-text-bulleted slot="icon"></sp-icon-text-bulleted>
        </sp-action-button>
        <sp-action-button
            label="Numbering"
            value="numbering"
            onclick="
                /* makes mutually exclusive checkbox */
                this.selected && 
                    requestAnimationFrame(() => this.parentElement.selected = []);
                this.parentElement.selected = [];
            "
        >
            <sp-icon-text-numbered slot="icon"></sp-icon-text-numbered>
        </sp-action-button>
    </sp-action-group>
    <sp-divider
        size="s"
        style="align-self: stretch; height: auto;"
        vertical
    ></sp-divider>
    <sp-action-group role="presentation" compact>
        <sp-action-button disabled label="Copy" value="copy">
            <sp-icon-copy slot="icon"></sp-icon-copy>
        </sp-action-button>
        <sp-action-button disabled label="Paste" value="paste">
            <sp-icon-paste slot="icon"></sp-icon-paste>
        </sp-action-button>
        <sp-action-button disabled label="Cut" value="cut">
            <sp-icon-cut slot="icon"></sp-icon-cut>
        </sp-action-button>
    </sp-action-group>
</div>
```
