Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,25 @@ register(TextSelection, 'text-selection', [], { shadow: true });
</text-section>
```

### Static Properties

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:

```js
class MyCustomElement extends Component {
static tagName = 'my-custom-element';
}

function MyOtherCustomElement() { ... }
MyOtherCustomElement.tagName = 'my-other-custom-element';
```

- `tagName`
- the custom element's tag name (if not passed as the second argument to `register()`)
- `observedAttributes`
- an array of attribute names to observe (if not passed as the third argument to `register()`)
- `formAssociated`
- a boolean indicating whether the custom element should be form-associated

## Related

Expand Down
4 changes: 4 additions & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ export default function register(Component, tagName, propNames, options) {
Object.keys(Component.propTypes || {});
PreactElement.observedAttributes = propNames;

if (Component.formAssociated) {
PreactElement.formAssociated = true;
}

// Keep DOM properties and Preact props in sync
propNames.forEach((name) => {
Object.defineProperty(PreactElement.prototype, name, {
Expand Down
32 changes: 31 additions & 1 deletion src/index.test.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { assert } from '@open-wc/testing';
import { h, createContext } from 'preact';
import { h, createContext, Component } from 'preact';
import { useContext } from 'preact/hooks';
import { act } from 'preact/test-utils';
import registerElement from './index';
Expand Down Expand Up @@ -279,4 +279,34 @@ describe('web components', () => {
root.appendChild(el);
assert.isTrue(el.shadowRoot === null);
});

it('supports the `formAssociated` property', async () => {
class FormAssociatedClass extends Component {
static formAssociated = true;

render() {
return <input name="foo" />;
}
}
registerElement(FormAssociatedClass, 'x-form-associated-class', []);

function FormAssociatedFunction() {
return <input name="bar" />;
}
FormAssociatedFunction.formAssociated = true;
registerElement(FormAssociatedFunction, 'x-form-associated-function', []);

root.innerHTML = `
<form id="myForm">
<x-form-associated-class></x-form-associated-class>
<x-form-associated-function></x-form-associated-function>
</form>
`;

const myForm = document.getElementById('myForm');

// The `.elements` property of a form includes all form-associated elements
assert.equal(myForm.elements[0].tagName, 'X-FORM-ASSOCIATED-CLASS');
assert.equal(myForm.elements[2].tagName, 'X-FORM-ASSOCIATED-FUNCTION');
});
});