List/Collection System #1463
Replies: 2 comments
-
Looking at the color picker i understand why but can you expand a little why it doesn't have an orientation? Isn't there technically a |
Beta Was this translation helpful? Give feedback.
-
Thanks for writing this up this is really great. Part of me wants to see some type of |
Beta Was this translation helpful? Give feedback.
-
I wanted to layout plans for building a Collection System in Canvas Kit.
What is a Collection?
Like the Popup system, a Collection system is a collection of models and behaviors that aid in creating accessible lists and grids. A "list" or "grid" doesn't have meaning in accessibility without context. For example "ordered list", "unordered list", "tab list", or "navigation list". Which type of list determines the roles, aria attributes, and behaviors associated with the list. A Collection system is fundamental units of functionality that support these higher-order lists or grids.
Why a Collection System?
Many components have the same functionality and concepts. For example, a
TabList
and aMenu
have many shared behaviors. Without a system, code duplication is common. For example, in Canvas Kit v6 the previewSelect
and the labsMenu
use custom and duplicated code to achieve very similar functionality. A system allows commonality and shared code between all components that make up lists. A system must be simple and flexible enough to support all use-cases without increasing complexity beyond custom code.Collection System Concepts
Lists and Grids
A list is a single-dimension collection with an
orientation
(vertical or horizontal). A grid a two-dimension collection with acolumnCount
. [More later?]Registering and unregistering items
Each item in a collection must be registered to a collection when it is added, and unregistered when it is removed. This process keeps the UI and the data representation in sync. A static collection may use JSX to create items while a dynamic dynamic may use data instead:
Static:
Dynamic:
The static examples leads with UI first while the dynamic example leads with data first. Registration keeps both UI and data in sync regardless of which method is used.
Orientation
A list can be vertical or horizontal. The data model needs to know the UI representation so that keyboard commands make sense. A grid doesn't have an orientation. Lists are single dimensional collections, and the orientation describes the direction laid out on the screen. A grid has 2 dimensions and only has one orientation.
Cursors
A "cursor" often represents focus within the UI, but not always directly a browser's
document.activeElement
. It gives the user an indicator of what keyboard inputs will do next. "Cursor" covers more use-cases than "focus". For example,aria-activedescendent
is an indicator within a list even though the list item never has browser focus, but is still considered a cursor.Cursors are used mostly by keyboard users to navigate a list. Navigation input is context-specific. For example, if a cursor is on the first item in a vertical list, the down arrow will move the cursor to the second item in a list. The up arrow may either stay on the first element, wrap to the last element, or navigate out of the current list (as in a toolbar menu). There can only be a single item represented by a cursor.
Navigation is related to cursors. The type of list can determine what key commands do. The cursor system allows the injection of a custom navigation manager. For example, the navigation manager determines if a list should wrap start and end items together.
Selection
Some lists have the concept of selection. For example, a
TabList
uses selection to determine which tab item is currently activated. Selection is almost always used with a cursor. For example, a cursor is used to navigate a select menu list. The enter key is used to select the current cursor item.Selection can be single or multiple and, like navigation, has a selection manager. The selection manager determines how a
select
event handles selection state transitions. A Single Select Manager will only allow the selection of a single item, while a MultiSelect Manager will toggle selection state of each item.Virtualization
A "Virtual List" should not be confused with an "Infinite List". A Virtual List has a finite number of items. Like a non-virtualized list, a virtual list has a scrollbar to mark the current window into the overall list. A virtual list also has aria properties to mark position for screenreader users. Virtualization is a rendering optimization for large lists of data and should be thought of as such. Often the only difference between a virtual list and a non-virtual list is lack of "Find in Page" functionality. Many large data set lists have other techniques to deal with this though. For example, a single select uses keyboard inputs to jump to first/second/third letters. A filtered select may use option filtering.
Virtualization can work for both fully loaded data sets and partially loaded data sets. For example, a fully loaded data set may include a single select with 50 options that are loaded from a backend at once. Virtualization only applies to rendering and localized filtering techniques work. Partially loaded data sets often include hundreds, thousands, or millions of items that are sent to the user on demand. Partially loaded data sets require special handling of navigation, selection, and filtering.
Lists should support virtualization so that a list system is not only useful for arbitrarily small data set sizes.
Virtualization has additional requirements to predict overall set height or width, cache item height/width calculations, and scrolling to items that don't currently exist in the DOM.
Responsive
Single dimension lists can be too big for the container and must overflow somewhere. The Collection System has some overflow behavior hooks and a model to handle overflow calculation using a polyfilled
ResizeObserver
. TheTabs
component uses this overflow already in v6.Roadmap
The initial release of a Collection System will be in v7 which is scheduled to be released in May 2022. Planned components to use the Collection System with the release of v7:
Rough API
Models
A
ListModel
contains state and events for registration, a cursor, and selection. Everything needed to build complex behaviors. AListModel
takes in initial state, optionalitems
, an optionalnavigation
manager, optionalselection
manager, and any guards or callbacks needed to make the model behave as desired.A
OverflowListModel
contains everthing a list does, but has extra state and events to handle lists that are responsive to their containers. Overflow requires a dynamic API, because rendered items are determined by render area. A typical use-case would be lists that should overflow into a separate overflow menu. For example, a tab list with an overflow menu of additional tabs that don't fit the renderable area.A
VirtualListModel
contains everything a list does, but has extra state and events to handle virtualization. AVirtualListModel
takes all the configuration aListModel
does and adds additional configuration for the virtualization layer. A likely candidate isreact-virtual
which is a hook to aid in virtualization. The model API will likely be modeled around thereact-virtual
API.Behavior Hooks
A list consists of 2 parts: a list, and a list item. Behavior hooks are applied to either of these element types.
useListRegisterItem
Item
Responsible for registering and unregistering items within a list. This hook keeps the UI and model in sync. It should be the first hook run as other item hooks depend on the
name
attribute that is produced to uniquely identify the item in the list.useListRovingFocus
Item
Responsible to navigating a list by both setting the cursor position and browser focus via the roving tabindex technique. Also adds a click handler that sets the cursor to the item when clicked.
useListSelectItem
Item
Responsible for adding selection to an item when clicked. If the item is a
button
element and usesuseListRovingFocus
, the enter and spacebar keys will also select.useListResetCursorOnBlur
List
Resets the cursor to the currently selected item if the list loses focus.
Examples
Tab List
The
Tabs
compound component uses a list system to both create a list of tabs with keyboard navigation and roving tabindex, but also the overflow calculations and the overflow menu. TheTabs
andMenu
component share most of the functionality event though the two components look different. The source code of Tabs in v6 can be used to get a rough idea of how the Collection System can be used.Beta Was this translation helpful? Give feedback.
All reactions