Skip to content

docs(swatchgroup): refactor docs, add a11y section #5699

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 144 additions & 27 deletions packages/swatch/swatch-group.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
## Description
## Overview

An `<sp-swatch-group>` group is a grouping of `<sp-swatch>` elements that are related to each other.

Expand All @@ -7,23 +7,27 @@ An `<sp-swatch-group>` group is a grouping of `<sp-swatch>` elements that are re
[![See it on NPM!](https://img.shields.io/npm/v/@spectrum-web-components/swatch?style=for-the-badge)](https://www.npmjs.com/package/@spectrum-web-components/swatch)
[![How big is this package in your project?](https://img.shields.io/bundlephobia/minzip/@spectrum-web-components/swatch?style=for-the-badge)](https://bundlephobia.com/result?p=@spectrum-web-components/swatch)

```
```bash
yarn add @spectrum-web-components/swatch
```

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

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

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

```
```js
import { SwatchGroup } from '@spectrum-web-components/swatch';
```

## Sizes
### Options

#### Sizes

Just like swatches, swatch groups come in four different sizes: extra-small, small, medium, and large. The medium size is the default option. This only affects the size of each individual swatch, not the spacing between them.

<sp-tabs selected="m" auto label="Size Attribute Options">
<sp-tab value="xs">Extra Small</sp-tab>
Expand Down Expand Up @@ -116,11 +120,27 @@ import { SwatchGroup } from '@spectrum-web-components/swatch';
</sp-tab-panel>
</sp-tabs>

## Density
#### Density

The `density` attribute/property is not required and when applied accepts the values of `compact` or `spacious`.
Swatch groups come in 3 densities: regular (default), compact, and spacious. The `density` attribute/property is not required and when applied accepts the values of `compact` or `spacious`. When not applied or undefined, the density of the group is set to regular (default).

### Compact
<sp-tabs selected="compact" auto label="Density Attribute Options">
<sp-tab value="regular">Regular</sp-tab>
<sp-tab-panel value="regular">

```html
<sp-swatch-group>
<sp-swatch color="var(--spectrum-blue-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-indigo-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-purple-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-fuchsia-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-magenta-500)"></sp-swatch>
</sp-swatch-group>
```

</sp-tab-panel>
<sp-tab value="compact">Compact</sp-tab>
<sp-tab-panel value="compact">

```html
<sp-swatch-group density="compact">
Expand All @@ -132,7 +152,9 @@ The `density` attribute/property is not required and when applied accepts the va
</sp-swatch-group>
```

### Spacious
</sp-tab-panel>
<sp-tab value="spacious">Spacious</sp-tab>
<sp-tab-panel value="spacious">

```html
<sp-swatch-group density="spacious">
Expand All @@ -144,17 +166,24 @@ The `density` attribute/property is not required and when applied accepts the va
</sp-swatch-group>
```

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

#### Selection mode

An `<sp-swatch-group>` element has two selection modes. The `selects` property can be set to either `single`, indicating a user can choose up to one swatch, or `multiple`, indicating a user can choose more than one swatch.

An `<sp-swatch-group>` element can carry a selection of a `single` swatch or of `multiple` swatches. Then the `selects` property is set to one of these values, the `selected` property will surface an array the represents the string values that have been selected in the UI.
When the `selects` property is set to one of these values, the `selected` property of `<sp-swatch-group>` will surface an array the represents the string values that have been selected in the UI. This `selected` property can be populated in two ways: through user input, or directly from `<sp-swatch>` children.

When the value of `selected` is updated via user input, the `change` event will be dispatched on the `<sp-swatch-group>` element to announce that interaction. Calling `preventDefault()` on the `chagne` event will prevent both the `<sp-swatch-group>` and the `<sp-swatch>` that initiated the `change` interaction from updating their `selected` values.
When the value of `selected` is updated via user input, the `change` event will be dispatched on the `<sp-swatch-group>` element to announce that interaction. Calling `preventDefault()` on the `change` event will prevent both the `<sp-swatch-group>` and the `<sp-swatch>` that initiated the `change` interaction from updating their `selected` values.

The value of `selected` can also be provided directly from the `<sp-swatch>` children. Child `<sp-swatch>` elements with their own `selected` attribute will be gathered and merged with any other selection data on the `<sp-swatch-group>` parent to populate `selected`.
The value of the `selected` property also can be provided directly from the `<sp-swatch>` children. Child `<sp-swatch>` elements with their own `selected` attribute will be gathered and merged with any other selection data on the `<sp-swatch-group>` parent to populate `selected`.

### Single
The `selected` property is always an array, so applications can programmatically set multiple selections regardless of the value of `selects`. However, user interactions will respect the `selects` property and enforce either single or multiple selection behavior accordingly.

The `selected` property is always represented as an array, and as such an application leveraging an `<sp-swatch-group>` element can apply more than one selection, regardless of the vaue of `selects`, however all future interactions will force the interace to a single selection.
<sp-tabs selected="single" auto label="Selection Attribute Options">
<sp-tab value="single">Single</sp-tab>
<sp-tab-panel value="single">

```html
<sp-swatch-group
Expand All @@ -163,36 +192,41 @@ The `selected` property is always represented as an array, and as such an applic
>
<sp-swatch color="var(--spectrum-blue-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-indigo-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-purple-500)" selected></sp-swatch>
<sp-swatch color="var(--spectrum-purple-500)"></sp-swatch>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see. I guess we had multiple selecteds on the swatches in this group to illustrate that, at least initially if it's programmatically set that way, the array can still have multiple elements even in single select mode, even though you can only actually select one swatch.

I'm on board with removing this nuance in the example. It really doesn't feel much like a feature to me. Plus the selected array switches from two elements back to just one once you select a different swatch.

<sp-swatch color="var(--spectrum-fuchsia-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-magenta-500)" selected></sp-swatch>
</sp-swatch-group>
<div>
Selected: [ "var(--spectrum-purple-500)", "var(--spectrum-magenta-500)" ]
</div>
<div>Selected: [ "var(--spectrum-magenta-500)" ]</div>
```

### Multiple
</sp-tab-panel>
<sp-tab value="multiple">Multiple</sp-tab>
<sp-tab-panel value="multiple">

`<sp-swatch>` children of an `<sp-swatch-group selects="mutiple">` parent will toggle their selection.
`<sp-swatch>` children of an `<sp-swatch-group selects="multiple">` parent will toggle their selection.

```html
<sp-swatch-group
selects="multiple"
onchange="this.nextElementSibling.textContent = `Selected: ${JSON.stringify(this.selected, null, ' ')}`"
>
<sp-swatch color="var(--spectrum-blue-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-blue-500)" selected></sp-swatch>
<sp-swatch color="var(--spectrum-indigo-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-purple-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-purple-500)" selected></sp-swatch>
<sp-swatch color="var(--spectrum-fuchsia-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-magenta-500)"></sp-swatch>
</sp-swatch-group>
<div>Selected: [ ]</div>
<div>
Selected: [ "var(--spectrum-blue-500)", "var(--spectrum-purple-500)" ]
</div>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would these arrays look better with code formatting? I'm on the fence; not sure I have a huge preference either way.

```

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

### Value

When available, the value of `selected` will be constructed from the `value` attributes/properties of the child `<sp-swatch>` elements. This can be useful when you would like the swatch data needs to correlate to a hash rather than the raw color string.
When available, the `selected` property will be populated with the `value` attributes/properties of the child `<sp-swatch>` elements. This is useful when you need the swatch data to correlate to a hash or identifier rather than the raw color string.

```html
<sp-swatch-group
Expand All @@ -217,6 +251,89 @@ When available, the value of `selected` will be constructed from the `value` att
<div>Selected: [ "color-2", "color-1", "color-3" ]</div>
```

## Swatch modifying attributes
### Swatch modifying attributes

An `<sp-swatch-group>` element can be modified by the following attributes/properties to customize its delivery as desired for your use case: `border`, `density`, `rounding`, `shape`, and `size`. Use these in concert with each other for a variety of final visual deliveries. Applying a value for one of these attributes/properties to an `<sp-swatch-group>` element will have it forward the value to all of the `<sp-swatch>` elements that are a direct child of the group, overriding any value that may be applied directly to those children.

Once applied to an `<sp-swatch-group>` element, the value of the `border`, `rounding`, `shape`, and `size` attributes/properties cannot be overridden on the children `<sp-swatch>` elements.

<sp-tabs selected="shape" auto label=" Attribute Options">
<sp-tab value="shape">Shape</sp-tab>
<sp-tab-panel value="shape">

```html
<sp-swatch-group shape="rectangle">
<sp-swatch color="var(--spectrum-blue-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-indigo-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-purple-500)"></sp-swatch>
</sp-swatch-group>
```

</sp-tab-panel>
<sp-tab value="rounding">Rounding</sp-tab>
<sp-tab-panel value="rounding">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it is useful to show the rounding="none" option? According to the design guidelines, that's actually the preferred/default corner rounding for swatch groups. We haven't shown that anywhere in the docs, however.

Along the same lines, do you think it would be useful to show the border="none" option? I was just thinking we should show examples of all of the available values for those attributes, since it's not super clear just from the API table.

Copy link
Collaborator

@rise-erpelding rise-erpelding Aug 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

It's unfortunate that the import of the border/rounding/shape types doesn't seem to work properly for the API table, since we end up with just the name of the type (for instance SwatchBorder) instead of the actual values it can take.

Either way, I think the swatch docs can do a lot of the heavy lifting for showing all the different features and options for a swatch and we don't necessarily need to repeat all of that, and it might be fine to just link to swatch somewhere around here instead of describing all the options again.

What I would want to show/tell for swatch group though would include:

  • No rounding since the design docs state that that's the preference within a group
  • Something about the border but I can't remember off the top of my head what's the most relevant within a swatch group... is the preference light border? Does it depend on the swatch's color contrast?
  • The text here talks about how you can put a property on the swatch group and it overrides any properties applied to the swatch, so I think that's what I'd want to see in the code snippet(s). If we set one rounding on the swatch group, and another on the swatch, the one on the group should take precedence. If we set a size on the swatch group, and another on the swatch, the one on the group would take precedence, etc.


```html
<sp-swatch-group rounding="full">
<sp-swatch color="var(--spectrum-blue-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-indigo-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-purple-500)"></sp-swatch>
</sp-swatch-group>
```

</sp-tab-panel>
<sp-tab value="no-rounding">No Rounding</sp-tab>
<sp-tab-panel value="no-rounding">

```html
<sp-swatch-group rounding="none">
<sp-swatch color="var(--spectrum-blue-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-indigo-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-purple-500)"></sp-swatch>
</sp-swatch-group>
```

</sp-tab-panel>
<sp-tab value="border">Border</sp-tab>
<sp-tab-panel value="border">

```html
<sp-swatch-group border="light">
<sp-swatch color="var(--spectrum-blue-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-indigo-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-purple-500)"></sp-swatch>
</sp-swatch-group>
```

</sp-tab-panel>
<sp-tab value="no-border">No Border</sp-tab>
<sp-tab-panel value="no-border">

```html
<sp-swatch-group border="none">
<sp-swatch color="var(--spectrum-blue-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-indigo-500)"></sp-swatch>
<sp-swatch color="var(--spectrum-purple-500)"></sp-swatch>
</sp-swatch-group>
```

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

### Accessibility

The swatch group implements several accessibility features:

- `tabindex="0"` on the selected swatch and unselected swatches have `tabindex="-1"`
- The swatch group role changes based on the `selects` property. When `selects="single"`, the group has `role="radiogroup"` and each swatch gets a `role="radio"`. When `selects="multiple"`, the group has `role="group"` and each swatch gets a `role="checkbox"`.

#### Best practices

- Ensure swatches have sufficient color contrast for visibility.
- Verify that swatch groups are appropriately labeled for screen readers by adding `aria-label` or `aria-labelledby` attributes to describe the purpose of the group.

#### Keyboard navigation

An `<sp-swatch-group>` element can be modified by the following attributes/properties to customize its delivery as desired for your use case: `border`, `disabled`, `mixedValue` (accepted as the `mixed-value` attribute), `nothing`, `rounding`, `shape`, and `size`. Use these in concert with each other for a variety of final visual deliveries. Applying a value for one of these attributes/properties to an `<sp-swatch-group>` element will have it forward the value to all of the `<sp-swatch>` elements that are a direct child of the group, overriding any value that may be applied directly to those children.
- `Tab`: Move focus to the next focusable element
- `Arrow keys`: Navigate between swatches in the group and move the focus indicator
- `Enter` or `Space`: Select the focused swatch
Loading