Skip to content

Commit 551f8a0

Browse files
author
Ana Sollano Kim
committed
Add platform-provided behaviors demo
1 parent 5e0fa53 commit 551f8a0

5 files changed

Lines changed: 892 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ sync'd July 30, 2025
175175
| JSON dummy data | Simple JSON files. Used for [View a JSON file or server response with formatting](https://learn.microsoft.com/microsoft-edge/web-platform/json-viewer). | [/json-dummy-data/](https://github.com/MicrosoftEdge/Demos/tree/main/json-dummy-data) | [JSON dummy data](https://microsoftedge.github.io/Demos/json-dummy-data/) (Readme) |
176176
| OpaqueRange | Demonstrates the `OpaqueRange` API for creating ranges over `<textarea>` and `<input>` values, enabling caret popup positioning and CSS Custom Highlight API usage on form controls. | [/opaque-range/](https://github.com/MicrosoftEdge/Demos/tree/main/opaque-range) | [OpaqueRange demo](https://microsoftedge.github.io/Demos/opaque-range/) |
177177
| Page Colors Custom Scrollbars demo | Shows a custom, green scrollbar in a page that has custom colors. | [/page-colors-custom-scrollbars/](https://github.com/MicrosoftEdge/Demos/tree/main/page-colors-custom-scrollbars) | [Page Colors Custom Scrollbars demo](https://microsoftedge.github.io/Demos/page-colors-custom-scrollbars/) |
178+
| Platform-provided behaviors | Demonstrates `HTMLSubmitButtonBehavior` for custom elements: form submission, override properties, implicit submission, and accessibility. | [/platform-behaviors/](https://github.com/MicrosoftEdge/Demos/tree/main/platform-behaviors) | [Platform-provided behaviors demo](https://microsoftedge.github.io/Demos/platform-behaviors/) |
178179
| Reference Target demos | Interactive demos of the Reference Target proposal, which allows ID references to cross shadow DOM boundaries. | [/reference-target/](https://github.com/MicrosoftEdge/Demos/tree/main/reference-target) | [Reference Target demos](https://microsoftedge.github.io/Demos/reference-target/) |
179180
| Reader app | An article reader app used to demonstrate how to use various web APIs such as CSS Custom Highlight, `<selectmenu>`, EyeDropper, CSS and JSON modules, Scroll animation timeline, and Async Clipboard. | [/reader/](https://github.com/MicrosoftEdge/Demos/tree/main/reader) | [Reader](https://microsoftedge.github.io/Demos/reader/) demo |
180181
| Scoped Custom Element Registries | Define custom elements scoped to a specific shadow roots, elements, or documents. | [/scoped-custom-element-registries/](https://github.com/MicrosoftEdge/Demos/tree/main/scoped-custom-element-registries) | [Scoped Custom Element Registries](https://microsoftedge.github.io/Demos/scoped-custom-element-registries/) demo |

platform-behaviors/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Platform-Provided Behaviors for Custom Elements
2+
3+
➡️ **[Open the demo](https://microsoftedge.github.io/Demos/platform-behaviors/)** ⬅️
4+
5+
🔗 **Links:**
6+
* Explainer: [Platform-provided behaviors explainer](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/PlatformProvidedBehaviors/explainer.md)
7+
* WHATWG issue: [#12150](https://github.com/whatwg/html/issues/12150)
8+
* Spec PR: [whatwg/html#12409](https://github.com/whatwg/html/pull/12409)
9+
* Chromium bug: [crbug.com/486928684](https://crbug.com/486928684)
10+
11+
## Overview
12+
13+
Platform-provided behaviors allow custom elements to adopt native HTML behaviors through `attachInternals({ behaviors: [...] })`. The first behavior, `HTMLSubmitButtonBehavior`, turns a custom element into a submit button that participates in form submission, contributes name/value pairs, supports form override attributes, triggers implicit submission, exposes the correct accessibility semantics, and responds to keyboard activation.
14+
15+
## Demos
16+
17+
- **Basic form submission**: A custom element with `HTMLSubmitButtonBehavior` submits a form the same way a native `<button type="submit">` does.
18+
- **Form override properties**: Shows how `name`, `value`, `formAction`, `formMethod`, and `formEnctype` work on a custom submit button.
19+
- **Implicit submission**: Pressing Enter in a text field triggers implicit submission through the custom element.
20+
- **Accessibility and keyboard activation**: The element gets `role="button"`, focusability, and Enter/Space activation with no extra code.
21+
22+
## Learn more
23+
24+
Read the [platform-provided behaviors explainer](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/PlatformProvidedBehaviors/explainer.md).
25+
26+
## Test the feature
27+
28+
The feature is behind a flag and not yet enabled by default.
29+
30+
* Use Microsoft Edge or another Chromium-based browser, version 149 or later.
31+
32+
* Go to `about://flags` and enable **Experimental Web Platform features**.
33+
34+
* Restart the browser.
35+
36+
## Provide feedback
37+
38+
Comment on the [WHATWG issue](https://github.com/whatwg/html/issues/12150).

platform-behaviors/index.html

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
4+
<head>
5+
<meta charset="UTF-8">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>Platform-provided behaviors for custom elements demo</title>
8+
<link rel="icon" type="image/png" href="https://edgestatic.azureedge.net/welcome/static/favicon.png">
9+
<link rel="stylesheet" href="style.css">
10+
</head>
11+
12+
<body>
13+
<h1>Platform-provided behaviors for custom elements</h1>
14+
<p>
15+
Platform-provided behaviors allow custom elements to adopt native HTML
16+
behaviors through <code>attachInternals({ behaviors: [...] })</code>. The first
17+
behavior, <code>HTMLSubmitButtonBehavior</code>, turns a custom element into a
18+
submit button that participates in form submission, contributes name/value
19+
pairs, supports form override attributes, triggers implicit submission,
20+
exposes the correct accessibility semantics, and responds to keyboard
21+
activation.
22+
<a href="https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/PlatformProvidedBehaviors/explainer.md">Read
23+
the explainer</a>.
24+
<a href="https://github.com/whatwg/html/issues/12150">Give feedback</a>.
25+
</p>
26+
27+
<div id="feature-warning" class="warning" hidden>
28+
<strong>⚠️ HTMLSubmitButtonBehavior is not supported in this browser.</strong>
29+
Enable the <strong>Experimental Web Platform features</strong> flag at
30+
<code>about://flags</code> in Microsoft Edge or another Chromium-based browser (version 149+).
31+
</div>
32+
33+
<!-- Use Case 1: Basic Form Submission -->
34+
<section class="demo-section">
35+
<h2>Use case 1: Basic form submission</h2>
36+
<p>
37+
A custom element with <code>HTMLSubmitButtonBehavior</code> submits a form
38+
just like a native <code>&lt;button type="submit"&gt;</code>. Click the
39+
custom submit button below to submit the form.
40+
</p>
41+
42+
<form id="form-basic">
43+
<div class="form-row">
44+
<label for="basic-name">Name:</label>
45+
<input type="text" id="basic-name" name="username" placeholder="Enter your name" value="Alice">
46+
</div>
47+
<div class="form-row">
48+
<label for="basic-email">Email:</label>
49+
<input type="email" id="basic-email" name="email" placeholder="Enter your email" value="alice@example.com">
50+
</div>
51+
<my-submit-button>Submit form</my-submit-button>
52+
</form>
53+
<div id="basic-output" class="output" hidden>
54+
<h3>Form data submitted:</h3>
55+
<pre id="basic-data"></pre>
56+
</div>
57+
58+
<details class="code-details">
59+
<summary>View source</summary>
60+
<pre class="code-block"><code>class MySubmitButton extends HTMLElement {
61+
static formAssociated = true;
62+
63+
constructor() {
64+
super();
65+
const behavior = new HTMLSubmitButtonBehavior();
66+
this.attachInternals({ behaviors: [behavior] });
67+
}
68+
}
69+
customElements.define("my-submit-button", MySubmitButton);</code></pre>
70+
</details>
71+
</section>
72+
73+
<!-- Use Case 2: Form Override Properties -->
74+
<section class="demo-section">
75+
<h2>Use case 2: Form override properties</h2>
76+
<p>
77+
<code>HTMLSubmitButtonBehavior</code> exposes <code>name</code>,
78+
<code>value</code>, <code>formAction</code>, <code>formEnctype</code>,
79+
and <code>formMethod</code> on the behavior instance. The custom
80+
element below sets these properties on the behavior to override the
81+
form's method and include its own name/value pair in the submission data.
82+
</p>
83+
84+
<form id="form-overrides">
85+
<div class="form-row">
86+
<label for="override-message">Message:</label>
87+
<input type="text" id="override-message" name="message" value="Hello, world!">
88+
</div>
89+
<div class="button-group">
90+
<override-submit-button id="save-btn">
91+
Save (POST)
92+
</override-submit-button>
93+
<override-submit-button id="draft-btn">
94+
Save as draft (GET)
95+
</override-submit-button>
96+
</div>
97+
</form>
98+
<div id="overrides-output" class="output" hidden>
99+
<h3>Submission details:</h3>
100+
<pre id="overrides-data"></pre>
101+
</div>
102+
103+
<details class="code-details">
104+
<summary>View source</summary>
105+
<pre class="code-block"><code>class OverrideSubmitButton extends HTMLElement {
106+
static formAssociated = true;
107+
#behavior;
108+
109+
constructor() {
110+
super();
111+
this.#behavior = new HTMLSubmitButtonBehavior();
112+
this.attachInternals({ behaviors: [this.#behavior] });
113+
}
114+
115+
get behavior() { return this.#behavior; }
116+
}
117+
customElements.define("override-submit-button", OverrideSubmitButton);
118+
119+
// Set form override properties on the behavior instance:
120+
const saveBtn = document.querySelector("#save-btn");
121+
saveBtn.behavior.name = "action";
122+
saveBtn.behavior.value = "save";
123+
saveBtn.behavior.formMethod = "post";
124+
125+
const draftBtn = document.querySelector("#draft-btn");
126+
draftBtn.behavior.name = "action";
127+
draftBtn.behavior.value = "draft";
128+
draftBtn.behavior.formMethod = "get";
129+
130+
// To reflect HTML attributes to behavior properties, handle
131+
// attributeChangedCallback yourself. The platform does not
132+
// automatically map element attributes to the behavior.</code></pre>
133+
</details>
134+
</section>
135+
136+
<!-- Use Case 3: Implicit Submission -->
137+
<section class="demo-section">
138+
<h2>Use case 3: Implicit submission</h2>
139+
<p>
140+
When a form contains a custom element with <code>HTMLSubmitButtonBehavior</code>,
141+
pressing <kbd>Enter</kbd> in a text field triggers implicit submission through
142+
that element, just like it would with a native submit button. Try pressing
143+
<kbd>Enter</kbd> in the input below.
144+
</p>
145+
146+
<form id="form-implicit">
147+
<div class="form-row">
148+
<label for="implicit-search">Search:</label>
149+
<input type="text" id="implicit-search" name="query" placeholder="Type something and press Enter...">
150+
</div>
151+
<implicit-submit-button>Search</implicit-submit-button>
152+
</form>
153+
<div id="implicit-output" class="output" hidden>
154+
<h3>Implicitly submitted:</h3>
155+
<pre id="implicit-data"></pre>
156+
</div>
157+
158+
<details class="code-details">
159+
<summary>View source</summary>
160+
<pre class="code-block"><code>class ImplicitSubmitButton extends HTMLElement {
161+
static formAssociated = true;
162+
163+
constructor() {
164+
super();
165+
const behavior = new HTMLSubmitButtonBehavior();
166+
this.attachInternals({ behaviors: [behavior] });
167+
}
168+
}
169+
customElements.define("implicit-submit-button", ImplicitSubmitButton);</code></pre>
170+
<pre class="code-block" data-lang="html"><code>&lt;!-- No extra wiring needed for implicit submission --&gt;
171+
&lt;form id="form-implicit"&gt;
172+
&lt;input type="text" name="query"&gt;
173+
&lt;implicit-submit-button&gt;Search&lt;/implicit-submit-button&gt;
174+
&lt;/form&gt;
175+
&lt;!-- Pressing Enter in the input submits via the custom element --&gt;</code></pre>
176+
</details>
177+
</section>
178+
179+
<!-- Use Case 4: Accessibility -->
180+
<section class="demo-section">
181+
<h2>Use case 4: Accessibility and keyboard activation</h2>
182+
<p>
183+
Custom elements with <code>HTMLSubmitButtonBehavior</code> automatically get:
184+
</p>
185+
<ul>
186+
<li>Implicit ARIA <code>role="button"</code></li>
187+
<li>Focusability (default <code>tabindex=0</code>)</li>
188+
<li>Keyboard activation via <kbd>Enter</kbd> and <kbd>Space</kbd></li>
189+
</ul>
190+
<p>
191+
Try using <kbd>Tab</kbd> to focus the button below, then press
192+
<kbd>Enter</kbd> or <kbd>Space</kbd> to activate it.
193+
</p>
194+
195+
<form id="form-a11y">
196+
<div class="form-row">
197+
<label for="a11y-data">Data:</label>
198+
<input type="text" id="a11y-data" name="payload" value="keyboard-submitted">
199+
</div>
200+
<a11y-submit-button>Accessible submit</a11y-submit-button>
201+
</form>
202+
<div id="a11y-output" class="output" hidden>
203+
<h3>Activated via keyboard:</h3>
204+
<pre id="a11y-data-output"></pre>
205+
</div>
206+
<p id="a11y-info" class="info-text">
207+
Inspect the custom element in DevTools. Its computed accessibility role is
208+
<code>button</code>, with no explicit ARIA attributes needed.
209+
</p>
210+
211+
<details class="code-details">
212+
<summary>What you get for free</summary>
213+
<pre class="code-block"><code>// The platform provides all of this, no manual code needed:
214+
//
215+
// ✔ role="button" in the accessibility tree
216+
// ✔ Focusable with Tab (tabindex=0 by default)
217+
// ✔ Enter and Space dispatch a click event
218+
// ✔ Participates in the tab order without explicit tabindex
219+
//
220+
// Compare with what you'd need without behaviors:
221+
element.setAttribute("role", "button");
222+
element.setAttribute("tabindex", "0");
223+
element.addEventListener("keydown", (e) =&gt; {
224+
if (e.key === "Enter" || e.key === " ") {
225+
e.preventDefault();
226+
element.click();
227+
}
228+
});</code></pre>
229+
</details>
230+
</section>
231+
232+
<script src="script.js"></script>
233+
</body>
234+
235+
</html>

0 commit comments

Comments
 (0)