|
1 | | -## Description |
| 1 | +## Overview |
2 | 2 |
|
3 | | -An `<sp-grid>` element displays a virtualized grid of elements built from its `items`, a normalized array of javascript objects, applied to a supplied `renderItem`, a `TemplateResult` returning method. `sp-grid` is a class extension of [`lit-virtualizer`](https://www.npmjs.com/package/@lit-labs/virtualizer/v/0.7.0-pre.2) and as such surfaces all of its underlying methods and events. |
4 | | - |
5 | | -Elements displayed in the grid can be focused via the [roving tabindex](https://www.w3.org/TR/wai-aria-practices-1.2/#kbd_roving_tabindex) that allows the grid to be entered via the `Tab` key and then subsequent elements to be focused via the arrow keys. To inform the `<sp-grid>` element what part of the DOM created by the `renderItem` method can be focused, supply a value to `focusableSelector`. Focus will always enter the element list at index 0 of ALL available elements, not just those currently realized to the page. |
6 | | - |
7 | | -Elements rendered via `renderItem` can have their width and height customized by supplying a value for `itemSize` that accepts an object: `{ width: number, height: number }`. You can customize the space between these elements via the `gap` property that accepts a value of `0` or `${number}px`. |
| 3 | +An `<sp-grid>` element displays a virtualized grid of elements built from its `items`, a normalized array of JavaScript objects, applied to a supplied `renderItem`, a `TemplateResult` returning method. The `<sp-grid>` is a class extension of [`lit-virtualizer`](https://www.npmjs.com/package/@lit-labs/virtualizer/v/0.7.0-pre.2) and as such surfaces all of its underlying methods and events. |
8 | 4 |
|
9 | 5 | ### Usage |
10 | 6 |
|
11 | 7 | [](https://www.npmjs.com/package/@spectrum-web-components/grid) |
12 | 8 | [](https://bundlephobia.com/result?p=@spectrum-web-components/grid) |
13 | 9 |
|
14 | | -``` |
| 10 | +```bash |
15 | 11 | yarn add @spectrum-web-components/grid |
16 | 12 | ``` |
17 | 13 |
|
18 | 14 | Import the side effectful registration of `<sp-grid>` via: |
19 | 15 |
|
20 | | -``` |
| 16 | +```javascript |
21 | 17 | import '@spectrum-web-components/grid/sp-grid.js'; |
22 | 18 | ``` |
23 | 19 |
|
24 | 20 | When looking to leverage the `Grid` base class as a type and/or for extension purposes, do so via: |
25 | 21 |
|
26 | | -``` |
| 22 | +```javascript |
27 | 23 | import { Grid } from '@spectrum-web-components/grid'; |
28 | 24 | ``` |
29 | 25 |
|
| 26 | +### Anatomy |
| 27 | + |
| 28 | +The grid consists of several key parts: |
| 29 | + |
| 30 | +- A virtualized container that efficiently renders only visible items |
| 31 | +- Individual grid items rendered via the `renderItem` method |
| 32 | +- A roving tabindex system for keyboard navigation |
| 33 | +- Configurable layout properties for item sizing and spacing |
| 34 | + |
| 35 | +```html |
| 36 | +<sp-grid id="basic-grid"></sp-grid> |
| 37 | +<script type="module"> |
| 38 | + const grid = document.querySelector('#basic-grid'); |
| 39 | + grid.items = [{ name: 'Item 1' }, { name: 'Item 2' }, { name: 'Item 3' }]; |
| 40 | + grid.renderItem = (item) => { |
| 41 | + const div = document.createElement('div'); |
| 42 | + div.textContent = item.name; |
| 43 | + return div; |
| 44 | + }; |
| 45 | +</script> |
| 46 | +``` |
| 47 | + |
| 48 | +### Options |
| 49 | + |
| 50 | +#### Properties |
| 51 | + |
| 52 | +The grid supports several properties for configuration: |
| 53 | + |
| 54 | +##### Items |
| 55 | + |
| 56 | +The `items` property accepts a normalized array of JavaScript objects that will be rendered in the grid: |
| 57 | + |
| 58 | +```javascript |
| 59 | +const grid = document.querySelector('sp-grid'); |
| 60 | +grid.items = [ |
| 61 | + { name: 'Card 1', date: '10/15/18' }, |
| 62 | + { name: 'Card 2', date: '10/16/18' }, |
| 63 | + { name: 'Card 3', date: '10/17/18' }, |
| 64 | +]; |
| 65 | +``` |
| 66 | + |
| 67 | +##### Render Item |
| 68 | + |
| 69 | +The `renderItem` property is a function that receives an item, index, and selected state, and returns a DOM element to be rendered: |
| 70 | + |
| 71 | +```javascript |
| 72 | +grid.renderItem = (item, index, selected) => { |
| 73 | + const card = document.createElement('sp-card'); |
| 74 | + card.heading = item.name; |
| 75 | + card.selected = selected; |
| 76 | + return card; |
| 77 | +}; |
| 78 | +``` |
| 79 | + |
| 80 | +##### Item Size |
| 81 | + |
| 82 | +Control the dimensions of each grid item using the `itemSize` property, which accepts an object with `width` and `height` properties: |
| 83 | + |
| 84 | +```javascript |
| 85 | +grid.itemSize = { |
| 86 | + width: 200, |
| 87 | + height: 300, |
| 88 | +}; |
| 89 | +``` |
| 90 | + |
| 91 | +##### Gap |
| 92 | + |
| 93 | +Customize the space between grid items via the `gap` property, which accepts a value of `0` or `${number}px`: |
| 94 | + |
| 95 | +```javascript |
| 96 | +grid.gap = '10px'; |
| 97 | +``` |
| 98 | + |
| 99 | +##### Focusable Selector |
| 100 | + |
| 101 | +Specify which element within the rendered item can receive focus by providing a CSS selector to the `focusableSelector` property: |
| 102 | + |
| 103 | +```javascript |
| 104 | +grid.focusableSelector = 'sp-card'; |
| 105 | +``` |
| 106 | + |
| 107 | +This informs the `<sp-grid>` element what part of the DOM created by the `renderItem` method can be focused via keyboard navigation. |
| 108 | + |
| 109 | +### Behaviors |
| 110 | + |
| 111 | +#### Virtualization |
| 112 | + |
| 113 | +The `<sp-grid>` uses virtualization to efficiently render large lists of items. Only the items visible in the viewport (plus a small buffer) are rendered to the DOM, which significantly improves performance for large datasets. As you scroll, the grid dynamically updates which items are rendered. |
| 114 | + |
| 115 | +#### Focus Management |
| 116 | + |
| 117 | +Elements displayed in the grid can be focused via the [roving tabindex](https://www.w3.org/TR/wai-aria-practices-1.2/#kbd_roving_tabindex) pattern. This allows the grid to be entered via the <kbd>Tab</kbd> key and then subsequent elements to be focused via the arrow keys. |
| 118 | + |
| 119 | +Focus will always enter the element list at index 0 of all available elements, not just those currently realized to the page. |
| 120 | + |
| 121 | +#### Selection Management |
| 122 | + |
| 123 | +The grid supports selection of items. You can maintain a `selectedItems` array and update it based on user interactions: |
| 124 | + |
| 125 | +```javascript |
| 126 | +grid.selectedItems = []; |
| 127 | + |
| 128 | +grid.renderItem = (item, index, selected) => { |
| 129 | + const card = document.createElement('sp-card'); |
| 130 | + card.selected = grid.selectedItems.includes(card.value); |
| 131 | + card.addEventListener('change', () => { |
| 132 | + if (grid.selectedItems.includes(card.value)) { |
| 133 | + grid.selectedItems = grid.selectedItems.filter( |
| 134 | + (item) => item !== card.value |
| 135 | + ); |
| 136 | + } else { |
| 137 | + grid.selectedItems.push(card.value); |
| 138 | + } |
| 139 | + }); |
| 140 | + return card; |
| 141 | +}; |
| 142 | +``` |
| 143 | + |
| 144 | +### Accessibility |
| 145 | + |
| 146 | +The `<sp-grid>` is designed with accessibility in mind and follows ARIA best practices for grid patterns. |
| 147 | + |
| 148 | +#### Keyboard Navigation |
| 149 | + |
| 150 | +The grid supports keyboard navigation through the roving tabindex pattern: |
| 151 | + |
| 152 | +- <kbd>Tab</kbd>: Enter the grid (focus moves to first item) |
| 153 | +- <kbd>Arrow Keys</kbd>: Navigate between grid items |
| 154 | +- Focus always starts at index 0 of all available elements |
| 155 | + |
| 156 | +#### ARIA Attributes |
| 157 | + |
| 158 | +When implementing a grid, ensure you provide appropriate ARIA attributes for screen reader support: |
| 159 | + |
| 160 | +```javascript |
| 161 | +grid.role = 'grid'; |
| 162 | +grid.ariaLabel = 'Select images'; |
| 163 | +grid.ariaMultiSelectable = 'true'; |
| 164 | +grid.ariaRowCount = `${grid.items.length}`; |
| 165 | +grid.ariaColCount = 1; |
| 166 | +``` |
| 167 | + |
| 168 | +Additionally, each rendered item should have appropriate ARIA attributes: |
| 169 | + |
| 170 | +```javascript |
| 171 | +card.role = 'row'; |
| 172 | +card.label = `Card Heading ${index}`; |
| 173 | +card.ariaSelected = grid.selectedItems.includes(card.value); |
| 174 | +card.ariaRowIndex = `${index + 1}`; |
| 175 | +``` |
| 176 | + |
| 177 | +#### Focusable Elements |
| 178 | + |
| 179 | +Use the `focusableSelector` property to specify which elements within each grid item should receive focus. This ensures that keyboard users can navigate to interactive elements within the grid. |
| 180 | + |
30 | 181 | ## Example |
31 | 182 |
|
32 | 183 | To interact with a fully accessible grid example, reference our [Grid Storybook](https://opensource.adobe.com/spectrum-web-components/storybook/index.html?path=/story/grid/) documentation. |
|
0 commit comments