You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: add extensions array argument to FASTElement.define() (#7465)
# Pull Request
## 📖 Description
Adds support for an optional extensions array parameter on `FASTElement.define()` and `FASTElementDefinition.define()`. Extensions are `FASTElementExtension` callbacks that receive the resolved `FASTElementDefinition` and are invoked **before** platform registration via `customElements.define()`, enabling a plugin pattern for element registration hooks.
**Example:**
```typescript
class MyComponent extends FASTElement {}
MyComponent.define({
name: "my-component"
}, [myPlugin()]);
```
## 👩💻 Reviewer Notes
- Extensions run before `customElements.define()` so side-effects are available before element upgrade.
- The `FASTElementExtension` type receives the full `FASTElementDefinition` (not `PartialFASTElementDefinition`) so extensions have access to resolved metadata.
- Both method-style (`MyEl.define(config, extensions)`) and static-style (`FASTElement.define(MyEl, config, extensions)`) calling conventions are supported.
- Rebased onto latest `releases/fast-element-v3` which made `compose`/`define` async (returning Promises). The extensions parameter integrates with the new async `define` flow — extensions are passed through to `FASTElementDefinition.define()` and invoked before platform registration.
- Removed the separate `composeAsync`/`defineAsync` methods that were previously in this branch since the base branch now handles async natively.
## 📑 Test Plan
All existing fast-element tests pass. Added 7 new Playwright tests covering:
- Method-style define with extensions
- Static-style define with extensions
- Multiple extensions called in order
- Extensions called before platform registration
- Empty extensions array
- Extension receives FASTElementDefinition instance
- Factory pattern with extensions
## ✅ Checklist
### General
- [x] I have included a change request file using `$ npm run change`
- [x] I have added tests for my changes.
- [x] I have tested my changes.
- [x] I have updated the project documentation to reflect my changes.
- [x] I have read the [CONTRIBUTING](https://github.com/microsoft/fast/blob/main/CONTRIBUTING.md) documentation and followed the [standards](https://github.com/microsoft/fast/blob/main/CODE_OF_CONDUCT.md#our-standards) for this project.
Copy file name to clipboardExpand all lines: packages/fast-element/DESIGN.md
+20Lines changed: 20 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -103,6 +103,26 @@ The `KernelServiceId` object controls which numeric/string keys are used for sha
103
103
104
104
`FASTElementDefinition` wraps all the metadata for a custom element class: its tag name, template, styles, and observed attribute list. It is created by `FASTElement.compose()` (which returns `Promise<FASTElementDefinition>`, always resolving immediately) and registered globally via `fastElementRegistry`. `FASTElement.define()` returns `Promise<TType>` — resolving immediately for complete definitions or deferring when `templateOptions` is `"defer-and-hydrate"` and no template is provided. `FASTElementDefinition.register()` returns `Promise<Function>` — resolving when a definition with the given name has been registered.
105
105
106
+
#### Extensions
107
+
108
+
`FASTElement.define()` and `FASTElementDefinition.define()` accept an optional array of **extension callbacks** (`FASTElementExtension`). Each extension is a function that receives the resolved `FASTElementDefinition` and is invoked **before** the element is registered with the platform via `customElements.define()`. This allows plugins to inspect or act on the definition metadata (name, template, styles, attributes) before any existing DOM elements are upgraded.
Custom directives can also await `controller.isPrerendered` (a `Promise<boolean>` on the `ViewController` interface) to determine whether the view's content was prerendered.
75
+
Custom directives can also await `controller.isPrerendered` (a `Promise<boolean>` on the `ViewController` interface) to determine whether the view's content was prerendered.
76
+
77
+
## Define Extensions
78
+
79
+
`FASTElement.define()` accepts an optional second argument — an array of extension callbacks that are invoked with the resolved element definition before the element is registered with the platform. This enables a plugin pattern where reusable behaviors can hook into element registration.
Each extension receives the full `FASTElementDefinition`, which includes the resolved element name, type, template, styles, and attribute metadata. Extensions run before `customElements.define()`, so any setup they perform is available when existing DOM elements are upgraded.
// Warning: (ae-internal-missing-underscore) The name "fastElementRegistry" should be prefixed with an underscore because the declaration is marked as @internal
0 commit comments