Prototype low-level component foundation based on composing behaviors into interaction patterns
A behavior is an atomic bit of functionality that can apply to a component, such as "can be disabled" or "has items". Each behavior is defined as an interface. Behaviors can be cumulative. For example, a component that "has an active item" must inherent "have items".
Behaviors can be added to an existing class via mixin, which here is a function that takes
in a class
and augments it with some additional functionality.
Behaviors compose into patterns.
A pattern is a union of behaviors that corresponds to one of the canonnical "interaction pattern" common to the web. For the most part, these align with the standard ARIA roles.
Each pattern defines an interface as a union of behaviors and a mixin that applies all of said behaviors onto an existing class.
The code here aims provide "behavioral primitives" that can be used in any framework or with no framework at all.
Different frameworks have their own systems for performing DOM manipulation, so we defer all rendering to the framework level.
- All behaviors live at the container level, while child items are simple state containers.
- The container must know about the children because of patterns like
aria-activedescendant
- Having the child items also know about the parent would introduce a circular data flow that would make the patterns more difficult to reason about.
- This implies that either event listeners must live at the container level, or that the container must have some way of knowing when the child state changes via some implementation of the Observer pattern.
- This also implies that the container, which cares about order, must either have some way to query for its child items or that child items must broadcast when they are added/remove/moved and that they must be aware of their own index.
- Example: A
listbox
knows about its options, but the each option knows nothing of its listbox.
- The container must know about the children because of patterns like
- From an API perspective, end-developers want to interact with the container for things that
deal with the child items. For example, reading the selected value from a
listbox
, even though the selection state lives on theoption
.
- The DOM acts as the output of the state rather than as the source of truth, which aligns with most frameworks.
- For custom elements, the pattern class is the custom
Element
.
- listbox
- option
- combobox
- dialog
- grid (row, gridcell, rowgroup, rowheader)
- tree
- slider
- menu
- menuitem, menuitemcheckbox, menuitemradio
- menubar
- tablist
- tab
- tabpanel
- radio-group
- Expansion panel
- Accordion
- Datepicker