Skip to content

Commit af1991d

Browse files
feat: formAssociated attribute (#89)
* feat: formAssociated attribute * test: Add test case for class & function components * docs: Add mention to ReadMe w/ new "Static Properties" section --------- Co-authored-by: Ryan Christian <[email protected]>
1 parent 21e984e commit af1991d

File tree

3 files changed

+54
-1
lines changed

3 files changed

+54
-1
lines changed

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,25 @@ register(TextSelection, 'text-selection', [], { shadow: true });
105105
</text-section>
106106
```
107107

108+
### Static Properties
109+
110+
We support a number of static properties on your component that map to special behaviors of the custom element. These can be set on components like so:
111+
112+
```js
113+
class MyCustomElement extends Component {
114+
static tagName = 'my-custom-element';
115+
}
116+
117+
function MyOtherCustomElement() { ... }
118+
MyOtherCustomElement.tagName = 'my-other-custom-element';
119+
```
120+
121+
- `tagName`
122+
- the custom element's tag name (if not passed as the second argument to `register()`)
123+
- `observedAttributes`
124+
- an array of attribute names to observe (if not passed as the third argument to `register()`)
125+
- `formAssociated`
126+
- a boolean indicating whether the custom element should be form-associated
108127

109128
## Related
110129

src/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ export default function register(Component, tagName, propNames, options) {
6464
Object.keys(Component.propTypes || {});
6565
PreactElement.observedAttributes = propNames;
6666

67+
if (Component.formAssociated) {
68+
PreactElement.formAssociated = true;
69+
}
70+
6771
// Keep DOM properties and Preact props in sync
6872
propNames.forEach((name) => {
6973
Object.defineProperty(PreactElement.prototype, name, {

src/index.test.jsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { assert } from '@open-wc/testing';
2-
import { h, createContext } from 'preact';
2+
import { h, createContext, Component } from 'preact';
33
import { useContext } from 'preact/hooks';
44
import { act } from 'preact/test-utils';
55
import registerElement from './index';
@@ -279,4 +279,34 @@ describe('web components', () => {
279279
root.appendChild(el);
280280
assert.isTrue(el.shadowRoot === null);
281281
});
282+
283+
it('supports the `formAssociated` property', async () => {
284+
class FormAssociatedClass extends Component {
285+
static formAssociated = true;
286+
287+
render() {
288+
return <input name="foo" />;
289+
}
290+
}
291+
registerElement(FormAssociatedClass, 'x-form-associated-class', []);
292+
293+
function FormAssociatedFunction() {
294+
return <input name="bar" />;
295+
}
296+
FormAssociatedFunction.formAssociated = true;
297+
registerElement(FormAssociatedFunction, 'x-form-associated-function', []);
298+
299+
root.innerHTML = `
300+
<form id="myForm">
301+
<x-form-associated-class></x-form-associated-class>
302+
<x-form-associated-function></x-form-associated-function>
303+
</form>
304+
`;
305+
306+
const myForm = document.getElementById('myForm');
307+
308+
// The `.elements` property of a form includes all form-associated elements
309+
assert.equal(myForm.elements[0].tagName, 'X-FORM-ASSOCIATED-CLASS');
310+
assert.equal(myForm.elements[2].tagName, 'X-FORM-ASSOCIATED-FUNCTION');
311+
});
282312
});

0 commit comments

Comments
 (0)