Skip to content

Commit 0f7b3ce

Browse files
authored
Add Graduated Proposals section (#1167)
Move Exclusive Accordion, Invoker Commands, Popover APi and Popover=hint to graduated proposals section Split out future invoker commands to new active proposal
1 parent e63f25d commit 0f7b3ce

File tree

7 files changed

+286
-194
lines changed

7 files changed

+286
-194
lines changed

site/src/components/navigation/navigation.astro

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ const sortedMenuNodes = menuNodes.sort((a, b) => {
1212
})
1313
1414
const groupedNodes = groupBy(sortedMenuNodes, (node) => node.frontmatter.menu)
15-
const menuHeadings = ["Overview", "Documentation", "Active Proposals", "Non-active Proposals", "Research"]
15+
const menuHeadings = ["Overview", "Documentation", "Graduated Proposals", "Active Proposals", "Non-active Proposals", "Research"]
1616
1717
// This is due to the component matrix being 2.2mb page size
1818
const routesToNotPrefetch = ['/research/component-matrix']

site/src/env.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
/// <reference path="../.astro/types.d.ts" />
12
/// <reference types="astro/client" />

site/src/pages/components/accordion.explainer.mdx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
menu: Active Proposals
2+
menu: Graduated Proposals
33
name: Exclusive Accordion (Explainer)
44
path: /components/accordion.explainer
55
pathToResearch: /components/accordion.research
@@ -16,6 +16,9 @@ layout: ../../layouts/ComponentLayout.astro
1616
- [openui/open-ui#925](https://github.com/openui/open-ui/issues/925) (UA ability for user to over-ride exclusive accordions functionality)
1717
- [w3c/html-aam#509](https://github.com/w3c/html-aam/issues/509) (describe grouping (and naming of the group) for exclusive accordions `<details name>`)
1818
- PR [whatwg/html#9400](https://github.com/whatwg/html/pull/9400) (Add name attribute for grouping details elements into an exclusive accordion)
19+
- [Specification](https://html.spec.whatwg.org/multipage/interactive-elements.html#attr-details-name)
20+
- [MDN blog on Exclusive Accordions](https://developer.mozilla.org/en-US/blog/html-details-exclusive-accordions/)
21+
- [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details#multiple_named_disclosure_boxes)
1922

2023
{/* START doctoc generated TOC please keep comment here to allow auto update */}
2124
{/* DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE */}
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
---
2+
menu: Active Proposals
3+
name: Invoker Commands Future (Explainer)
4+
layout: ../../layouts/ComponentLayout.astro
5+
---
6+
7+
- Authors: [Keith Cirkel](https://github.com/keithamus), [Luke Warlow](https://github.com/lukewarlow)
8+
9+
**NOTE:** See the original explainer for the core proposal [here](/components/invokers.explainer).
10+
11+
{/* START doctoc generated TOC please keep comment here to allow auto update */}
12+
{/* DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE */}
13+
14+
# Invoker Buttons
15+
16+
## Introduction
17+
18+
This document outlines potential future enhancements to [Invoker Commands](/components/invokers.explainer).
19+
20+
All commands noted here are ideas only and are not included in the initial release of this feature.
21+
22+
### Defaults
23+
24+
Depending on the target set by `commandfor`, invoking the button will trigger
25+
additional behaviours alongside the event dispatch, depending on the value of
26+
`command`. The following table represents ideas on how built-in invocations on specific
27+
element types are handled. These need further design on exactly how
28+
they will behave based on implications such as accessibility, security,
29+
interactivity, and how the button may need to respond to such actions.
30+
31+
| Invokee Element | `command` hint | Behaviour |
32+
| :-------------------- | :--------------------- | :------------------------------------------------------------------------------------------------------------- |
33+
| `<dialog>` | `'request-close'` | If the `<dialog>` is `open`, request to close and use the button `value` for returnValue. Similar to `.requestClose(value) |
34+
| `<* openable>` | `'toggle-openable'` | Opens the `openable` if closed, otherwise closes. Similar to `.toggleOpenable()` |
35+
| `<* openable>` | `'close-openable'` | Closes the `openable` if open, otherwise does nothing. Similar to `.closeOpenable()` |
36+
| `<* openable>` | `'open-openable'` | Opens the `openable` if closed, otherwise does nothing. Similar to `.openOpenable()` |
37+
| `<details>` | `'toggle'` | If the `<details>` is `open`, then close it, otherwise open it |
38+
| `<details>` | `'open'` | If the `<details>` is not `open`, then open it |
39+
| `<details>` | `'close'` | If the `<details>` is `open`, then close it |
40+
| `<dialog>` | `'toggle'` | If the `<dialog>` is `open`, then close it and use the button `value` for returnValue, otherwise open as modal |
41+
| `<select>` | `'show-picker'` | Shows the native picker. Similar to `.showPicker()` on the invokee |
42+
| `<input>` | `'show-picker'` | Shows the native picker. Similar to `.showPicker()` on the invokee |
43+
| `<video>` | `'play-pause'` | If the video is not playing, plays the video. Otherwise pauses it. Similar to `el.playing = !el.playing` |
44+
| `<video>` | `'pause'` | If the video is playing, pause the video. Similar `.playing = false` |
45+
| `<video>` | `'play'` | If the video is not playing, play the video. Similar to `.playing = true` |
46+
| `<video>` | `'toggle-muted'` | If the video is muted, it unmutes the video, otherwise it mutes it. Similar to `el.muted = !el.muted` |
47+
| `<audio>` | `'play-pause'` | If the audio is not playing, plays the audio. Otherwise pauses it. Similar to `el.playing = !el.playing` |
48+
| `<audio>` | `'pause'` | If the audio is playing, pause the audio. Similar `.playing = false` |
49+
| `<audio>` | `'play'` | If the audio is not playing, play the audio. Similar to `.playing = true` |
50+
| `<audio>` | `'toggle-muted'` | If the audio is muted, it unmutes the audio, otherwise it mutes it. Similar to `el.muted = !el.muted` |
51+
| `<*>` | `'toggle-fullscreen'` | If the element is fullscreen, then exit, otherwise request to enter |
52+
| `<*>` | `'request-fullscreen'` | Request the element to enter into 'fullscreen' mode |
53+
| `<*>` | `'exit-fullscreen'` | If the element is fullscreen, then exit |
54+
| `<input type=number>` | `'step-up'` | Call `.stepUp()` on the invokee |
55+
| `<input type=number>` | `'step-down'` | Call `.stepDown()` on the invokee |
56+
57+
> Note: Ideas are welcome. Please submit an issue if you have one!
58+
59+
Further to the initial ship we're also exploring implicit `command` or implicit
60+
`commandfor` values where the value can easily be inferred.
61+
62+
### Accessibility
63+
64+
For built-in behaviours `command` attribute maps to specific accessibility
65+
mappings which are placed on the button. The button may also use the
66+
`commandfor` referenced element to gather other details (for example the state
67+
of the element) to reflect that state on the button.
68+
69+
These mappings will happen implicitly on the browsers Accessible Nodes, and so
70+
while (for simplicity) this section refers to various `aria-` attributes,
71+
buttons will not sprout these attributes in the DOM, but the effective
72+
equivalent will be exposed to Assistive Technologies.
73+
74+
#### Buttons with `command=request-close`
75+
76+
Buttons with this dialog command will implicitly receive `aria-details=IDREF`,
77+
where `IDREF` matches that of the `commandfor` attribute, while the dialog is
78+
in the showing state, and the button is not a descendant of the dialog.
79+
80+
<details>
81+
<summary>Why?</summary>
82+
83+
A button that cancels a dialog is very typically found inside of the dialog, but
84+
in some cases it may be found outside, perhaps as a "toggle" style button which
85+
opens and closes a dialog as non-modal. This button may be used to close an open
86+
dialog that is shown as non-modal. It may be useful for a user to traverse into
87+
the dialog before closing it, for example to check if they have unsaved changes
88+
within the dialog.
89+
90+
</details>
91+
92+
<br/><br/>
93+
94+
Buttons will also implicitly receive an `aria-expanded` value, if they are not a
95+
descendant of the `commandfor=` referenced element. The state of the
96+
`aria-expanded` value will map to the state of the dialog's openness. When the
97+
dialog is open the button will have `aria-expanded="true"`, when closed,
98+
`aria-expanded="false"`. This will be recomputed whenever the dialog changes
99+
state, such that the button always reflects the state of openness.
100+
101+
<details>
102+
<summary>Why?</summary>
103+
104+
A button that cancels a dialog is very typically found inside of the dialog, but
105+
in some cases it may be found outside, perhaps as a "toggle" style button which
106+
opens and closes a dialog as non-modal.
107+
108+
Buttons outside of the dialog may be used to close an open dialog that is shown
109+
as non-modal. It may be useful for a user to traverse into the dialog before
110+
closing it, for example to check if they have unsaved changes within the dialog.
111+
It may also be useful to know if the dialog is already closed (as in its
112+
`aria-expanded` state is false), as this may help the user make a decision to
113+
whether or not they action the close button.
114+
115+
</details>
116+
117+
<br/><br/>
118+
119+
<details>
120+
<summary>Other considerations not explicitly proposed.</summary>
121+
122+
##### aria-pressed
123+
124+
Given elements will have `aria-expanded`, adding `aria-pressed` would be
125+
confusing or redundant, and as such won't be proposed for these buttons.
126+
127+
##### aria-controls
128+
129+
While `aria-controls` attempts to establish a similar style of relationship to
130+
`aria-details`, `aria-details` sees broader support among various assistive
131+
technologies, and it would be redundant to add both.
132+
133+
</details>
134+
135+
<br/><br/>
136+
137+
#### Other built-in `command=` types
138+
139+
Further built-in commands will be proposed on a case-per-case basis,
140+
and additional aria or other logic will be considered with those at the time.
141+
142+
### Security
143+
144+
See the main [Invoker Commands explainer](/components/invokers.explainer#security) for an overview of the
145+
security considerations.
146+
147+
**Note**: The security considerations for the proposed commands are not yet complete and will be specified in more detail
148+
in the future.
149+
150+
Below is a brief summary of the security considerations for the commands proposed above:
151+
152+
#### Details
153+
154+
This proposal aims to allow opening and closing `<details>` elements with
155+
`invoketarget`. This is not considered to be new capability, as it is already
156+
possible to do this with the `<summary>` element.
157+
158+
#### Input
159+
160+
It should be noted that input pickers (like the file picker dialog) render native
161+
controls outside of the bounds of the document frame (iframe or browser window).
162+
Due to this, the security implications of invoking these elements should be
163+
carefully considered.
164+
165+
Scripts can call `.showPicker()` on form elements, and the picker will open.
166+
There are some cross-origin restrictions, for example calling `.showPicker()`
167+
on elements in a cross-origin context only works for `<input type=file>` or
168+
`<input type=color>`.
169+
170+
It is also possible to wrap an `<input>` in a `<label>`, where invoking the
171+
label will open the picker. This is quite common practice when trying to style
172+
`<input type=file>` for example; dressing the `<label>` to look like a
173+
`<button>` and hiding the `<input>`.
174+
175+
This proposal allows showing the pickers of input elements, for example an
176+
invoker can target an `<input type=file>` and clicking the invoker will open
177+
the operating systems file picker dialog. As stated above, this is already
178+
possible with `<label>` elements, but care should be taken to ensure that
179+
the same cross-origin restrictions apply for Invokers as they do for scripting.
180+
181+
#### Fullscreen elements
182+
183+
Turning an element into a fullscreen needs to be carefully consdidered.
184+
Scripting already allows this via the `.requestFullscreen()` API which, as the
185+
name suggests, may not always be successful given the UA context. This API
186+
requires the document context to be active, for example requiring a user
187+
activation (this is true of invokers in the general case), it also requires
188+
the Permissions Policy to allow for this behaviour, and requires the element to
189+
not already be on the Top Layer.
190+
191+
All of these constraints should also be true for invokers opening fullscreen
192+
elements. This means the only _significant_ new behavioural difference between
193+
an invoker opening a fullscreen element vs the existing behaviour which
194+
requires scripting, is that sanboxed iframes which disallow scripting but allow
195+
fullscreen may now declare a button that can fullscreen. Consider the following:
196+
197+
```html
198+
<iframe sandbox allow="fullscreen">
199+
<html id="invokee">
200+
<button type="button" commandfor="invokee" command="toggleFullscreen">Invoke</button>
201+
<button onclick="invokee.requestFullscreen()">Go fullscreen</button>
202+
</html>
203+
</iframe>
204+
````
205+
206+
In this example, the `<button onclick>` will do nothing as the iframe is
207+
sandboxed and does not allow scripting. The `<button invoketarget>` will
208+
fullscreen the element, however, as the `allow=fullscreen` Permission Policy is
209+
enabled to allow fullscreen.
210+
211+
This is considered to be a low security threat, as it requires opt-in to the
212+
fullscreen Permission Policy explitly via iframe attributes or scripting. We
213+
will, however, continue to explore if this should be a possibility.
214+
215+
#### Media Elements
216+
217+
This proposal allows video and audio elements to be controlled with buttons
218+
outside of the browsers native video controls. This includes playing, pausing,
219+
and toggling mute/unmute. Today this is only possible using scripting via the
220+
equivalent scripting APIs: `.play()` / `.pause()` / `.muted=`. These APIs are
221+
guarded by Permissions Policy, and so should the invoker equivalent. Some User
222+
Agents can be configured to reject calls to `.play()`, and this should also be
223+
true of invokers. As such the key new capability here is the ability to call
224+
these APIs without scripting enabled. This is effectively the same concern as
225+
fullscreen; the security model is guarded around the Permissions Policy.
226+
227+
There is also additional concern around the media element invokers being able
228+
to circumvent autoplay policies. Invokers should not be able to circumvent
229+
these. By design, invokers require a user interaction (clicking the button)
230+
and so this should not circumvent autoplay policies.
231+
232+
#### Further proposals...
233+
234+
There are continued suggestions for new capabilities of Invokers, such as
235+
[invoking picture-in-picture](https://github.com/openui/open-ui/issues/916).
236+
237+
Each of these will need to be taken into consideration on a case-per-case
238+
basis. The following questions will need to be answered for each of these:
239+
240+
- Is it possible for the user to do this today with scripting?
241+
- Is it possible for the user to do this today without scripting?
242+
- Does this behaviour bypass scripting sandboxing rules, such as
243+
Permissions Policy or iframes?
244+
- Does this enable buttons to invoke content that appears outside of the
245+
browser frame?
246+
247+
### PAQ (Potentially Asked Questions)
248+
249+
#### Do we have to always supply both? Can't we make `command` or `commandfor` implicit?
250+
251+
The original proposal had the concept of an "auto" `command` value which would
252+
determine an explicit command based on various heuristics, such as the target
253+
element. This has been deferred for the initial ship, but may be explored
254+
further. This is considered out of scope for the initial ship, however.
255+
256+
We may also explore the possibility of making `commandfor` implicit, for example
257+
if a button is a descendant of a dialog, omitting `commandfor` may make sense.
258+
This is also considered out of scope for the initial ship.

0 commit comments

Comments
 (0)