Skip to content

Commit 5a6623c

Browse files
janechuCopilot
andcommitted
docs(fast-html): add AttributeMap documentation to DESIGN.md and README.md
Document the dash-removal convention (foo-bar attribute → foobar property), leaf-binding eligibility rules, and usage pattern in both files. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent c83ab9e commit 5a6623c

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

packages/fast-html/DESIGN.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,17 @@ An optional layer that uses the `Schema` to automatically:
8989

9090
Enabled via `TemplateElement.options({ "my-element": { observerMap: "all" } })`.
9191

92+
### `AttributeMap` — automatic `@attr` definitions
93+
94+
An optional layer that uses the `Schema` to automatically register `@attr`-style reactive properties for every **leaf binding** in the template — i.e. simple expressions like `{{foo}}` or `id="{{foo-bar}}"` that have no nested properties, no explicit type, and no child element references.
95+
96+
- The **attribute name** is the binding key exactly as written in the template (e.g. `foo-bar`).
97+
- The **property name** is derived by removing all dashes (e.g. `foo-bar``foobar`).
98+
- Properties already decorated with `@attr` or `@observable` are left untouched.
99+
- `FASTElementDefinition.attributeLookup` and `propertyLookup` are patched so `attributeChangedCallback` correctly delegates to the new `AttributeDefinition`.
100+
101+
Enabled via `TemplateElement.options({ "my-element": { attributeMap: "all" } })`.
102+
92103
### Syntax constants (`syntax.ts`)
93104

94105
All delimiters used by the parser are defined in a single `Syntax` interface and exported as named constants from `syntax.ts`. This makes the syntax pluggable and easy to audit.
@@ -284,6 +295,15 @@ flowchart LR
284295

285296
For a deep dive into the schema structure, context tracking, and proxy system see [SCHEMA_OBSERVER_MAP.md](./SCHEMA_OBSERVER_MAP.md).
286297

298+
### AttributeMap and leaf bindings
299+
300+
When `attributeMap: "all"` is set, `AttributeMap.defineProperties()` is called after parsing. It iterates `Schema.getRootProperties()` and skips any property whose schema entry contains `properties`, `type`, or `anyOf` — keeping only plain leaf bindings. For each leaf:
301+
302+
1. The schema key (e.g. `foo-bar`) is used as the **attribute name**.
303+
2. Dashes are removed to form the **JS property name** (e.g. `foobar`).
304+
3. A new `AttributeDefinition` is registered via `Observable.defineProperty`.
305+
4. `FASTElementDefinition.attributeLookup` and `propertyLookup` are updated so `attributeChangedCallback` can route attribute changes to the correct property.
306+
287307
---
288308

289309
## Lifecycle

packages/fast-html/README.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,33 @@ if (process.env.NODE_ENV === 'development') {
217217
}
218218
```
219219

220+
#### `attributeMap`
221+
222+
When `attributeMap: "all"` is configured for an element, `@microsoft/fast-html` automatically creates reactive `@attr` properties for every **leaf binding** in the template — simple expressions like `{{foo}}` or `id="{{foo-bar}}"` that have no nested properties.
223+
224+
The **attribute name** is the binding key as written in the template. The **property name** is derived by removing all dashes (`foo-bar``foobar`). Properties already decorated with `@attr` or `@observable` on the class are left untouched.
225+
226+
```typescript
227+
TemplateElement.options({
228+
"my-element": {
229+
attributeMap: "all",
230+
},
231+
});
232+
```
233+
234+
With the template:
235+
236+
```html
237+
<f-template name="my-element">
238+
<template>
239+
<p>{{greeting}}</p>
240+
<p>{{first-name}}</p>
241+
</template>
242+
</f-template>
243+
```
244+
245+
This registers `greeting` (attribute `greeting`, property `greeting`) and `first-name` (attribute `first-name`, property `firstname`) as `@attr` properties on the element prototype, enabling `setAttribute("first-name", "Jane")` to trigger a template re-render automatically.
246+
220247
### Syntax
221248

222249
All bindings use a handlebars-like syntax.

0 commit comments

Comments
 (0)