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
Reduce declarative template entrypoint size by moving optional map and lifecycle support behind schema hooks, replacing the custom template element with a native publisher, and updating docs/fixtures.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
"comment": "Remove the public declarative TemplateElement configuration APIs and make declarative templates use an internal native f-template publisher with explicit hydration opt-in.",
@@ -29,9 +29,10 @@ the relevant registry and waits for the matching declarative template when it is
29
29
already present or inserted later.
30
30
31
31
The `@microsoft/fast-element/declarative.js` entrypoint itself remains
32
-
side-effect free at import time. The hydratable `ViewTemplate` runtime is
33
-
installed lazily when `TemplateParser`, `TemplateElement`, or
34
-
`declarativeTemplate()` first create a declarative template.
32
+
side-effect free at import time. Declarative APIs lazily install declarative
33
+
debug messages when they create templates. Hydratable `ViewTemplate` support is
34
+
installed only when `enableHydration()` is called from
35
+
`@microsoft/fast-element/hydration.js`.
35
36
36
37
Example:
37
38
```html
@@ -59,158 +60,77 @@ format and initial-state application details, see
59
60
60
61
## Lifecycle Callbacks
61
62
62
-
FAST Element's declarative entrypoint provides lifecycle callbacks that allow
63
-
you to hook into various stages of template processing and element hydration.
64
-
These callbacks are useful for tracking the rendering lifecycle, gathering
65
-
analytics, or coordinating complex initialization sequences.
63
+
FAST Element's declarative APIs provide lifecycle callbacks that allow you to
64
+
hook into template processing and hydration. The callbacks are split by scope:
66
65
67
-
### Available Callbacks
68
-
69
-
**Template Lifecycle Callbacks:**
70
-
-`elementDidRegister(name: string)` - Called after the JavaScript class definition has been registered
71
-
-`templateWillUpdate(name: string)` - Called before the template has been evaluated and assigned
72
-
-`templateDidUpdate(name: string)` - Called after the template has been assigned to the definition
73
-
-`elementDidDefine(name: string)` - Called after the custom element has been defined
74
-
75
-
**Hydration Lifecycle Callbacks:**
76
-
-`hydrationStarted()` - Called once when the first prerendered element begins hydrating
77
-
-`elementWillHydrate(source: HTMLElement)` - Called before an element begins hydration
78
-
-`elementDidHydrate(source: HTMLElement)` - Called after an element completes hydration
79
-
-`hydrationComplete()` - Called after all prerendered elements have completed hydration
80
-
81
-
Hydration callbacks are tracked at the element level by `ElementController` — `hydrationComplete` fires only after every prerendered element has finished binding.
82
-
83
-
### Configuring Callbacks
66
+
| Scope | API | Callbacks |
67
+
|---|---|---|
68
+
| Per element |`declarativeTemplate(callbacks)`|`elementDidRegister`, `templateWillUpdate`, `templateDidUpdate`, `elementDidDefine`, `elementWillHydrate`, `elementDidHydrate`|
69
+
| Global hydration |`enableHydration(options)`|`hydrationStarted`, `hydrationComplete`|
84
70
85
-
Configure lifecycle callbacks using `TemplateElement.config()`:
71
+
Hydration is opt-in. Call `enableHydration()` before FAST elements connect when
72
+
you want prerendered Declarative Shadow DOM to be reused:
4.**Completion**: `hydrationComplete` is called after all prerendered elements finish hydrating
87
+
Pass per-element lifecycle callbacks directly to `declarativeTemplate()`:
136
88
137
-
**Note:** Template processing is asynchronous and happens independently for each element. The template and hydration phases can be interleaved when multiple elements are being processed simultaneously.
properties for every **leaf binding** in the template — simple expressions
269
-
like `{{foo}}` or `id="{{foo-bar}}"` that have no nested properties. The
270
-
default behavior uses the `"none"` attribute name strategy.
271
-
`TemplateElement.options()` remains available as a compatibility fallback via
272
-
`attributeMap: {}`.
273
-
274
-
By default, the **attribute name** and **property name** are both the binding key exactly as written in the template — no normalization is applied. Because HTML attributes are case-insensitive, binding keys should use lowercase names (optionally dash-separated). Properties with dashes must be accessed via bracket notation (e.g. `element["foo-bar"]`).
188
+
properties for every **leaf binding** in the template — simple expressions like
189
+
`{{foo}}` or `id="{{fooBar}}"` that have no nested properties.
275
190
276
-
Properties already decorated with `@attr` or `@observable` on the class are left untouched.
191
+
By default, the binding key is treated as a camelCase property name and the HTML
192
+
attribute name is derived by converting it to kebab-case. Properties already
193
+
decorated with `@attr` or `@observable` on the class are left untouched.
277
194
278
195
```typescript
279
196
MyElement.define(
@@ -291,21 +208,26 @@ With the template:
291
208
<f-templatename="my-element">
292
209
<template>
293
210
<p>{{greeting}}</p>
294
-
<p>{{first-name}}</p>
211
+
<p>{{firstName}}</p>
295
212
</template>
296
213
</f-template>
297
214
```
298
215
299
-
This registers `greeting` (attribute `greeting`, property `greeting`) and `first-name` (attribute `first-name`, property `first-name`) as `@attr` properties on the element prototype, enabling `setAttribute("first-name", "Jane")` to trigger a template re-render automatically.
216
+
This registers `greeting` (attribute `greeting`, property `greeting`) and
217
+
`firstName` (attribute `first-name`, property `firstName`) as `@attr`
218
+
properties on the element prototype, enabling `setAttribute("first-name",
219
+
"Jane")` to trigger a template re-render automatically.
300
220
301
221
### `attribute-name-strategy`
302
222
303
-
The `attribute-name-strategy` configuration option controls how template binding keys map to HTML attribute names. This matches the build-time `--attribute-name-strategy` option in `@microsoft/fast-build`.
223
+
The `attribute-name-strategy` configuration option controls how template binding
224
+
keys map to HTML attribute names. This matches the build-time
225
+
`--attribute-name-strategy` option in `@microsoft/fast-build`.
304
226
305
227
| Strategy | Behaviour | Example |
306
228
|---|---|---|
307
-
|`"none"` (default) | Binding key used as-is for both property and attribute |`{{foo-bar}}` → property `foo-bar`, attribute `foo-bar`|
308
-
|`"camelCase"`| Binding key is the camelCase property; attribute name derived as kebab-case |`{{fooBar}}` → property `fooBar`, attribute `foo-bar`|
229
+
|`"camelCase"` (default) | Binding key is the camelCase property; attribute name is derived as kebab-case |`{{fooBar}}` → property `fooBar`, attribute `foo-bar`|
230
+
|`"none"`| Binding key used as-is for both property and attribute |`{{foo-bar}}` → property `foo-bar`, attribute `foo-bar`|
309
231
310
232
```typescript
311
233
MyElement.define(
@@ -315,24 +237,14 @@ MyElement.define(
315
237
},
316
238
[
317
239
attributeMap({
318
-
"attribute-name-strategy": "camelCase",
240
+
"attribute-name-strategy": "none",
319
241
}),
320
242
],
321
243
);
322
244
```
323
245
324
-
With the template:
325
-
326
-
```html
327
-
<f-templatename="my-element">
328
-
<template>
329
-
<p>{{greeting}}</p>
330
-
<p>{{firstName}}</p>
331
-
</template>
332
-
</f-template>
333
-
```
334
-
335
-
This registers `greeting` (attribute `greeting`, property `greeting`) and `firstName` (attribute `first-name`, property `firstName`) as `@attr` properties. `setAttribute("first-name", "Jane")` triggers a re-render, and the property is accessible as `element.firstName`.
246
+
When using the `"none"` strategy, property names may contain dashes and must be
247
+
accessed via bracket notation (e.g. `element["foo-bar"]`).
The public declarative API is now the functional API. The `<f-template>`
162
+
implementation is internal and is defined automatically by `declarativeTemplate()`.
163
+
164
+
| Removed | Replacement |
165
+
|---|---|
166
+
|`TemplateElement` public export |`declarativeTemplate()` on each FAST element definition |
167
+
|`TemplateElement.define({ name: "f-template" })`| No manual definition; `declarativeTemplate()` defines the internal publisher in the target registry |
168
+
|`TemplateElement.config(callbacks)` / `HydrationLifecycleCallbacks`| Per-element callbacks via `declarativeTemplate(callbacks)` and global hydration callbacks via `enableHydration(options)`|
0 commit comments