diff --git a/change/@microsoft-fast-element-e173d34b-0061-4c9d-94b5-415929d7dc5e.json b/change/@microsoft-fast-element-e173d34b-0061-4c9d-94b5-415929d7dc5e.json
new file mode 100644
index 00000000000..076ceecae26
--- /dev/null
+++ b/change/@microsoft-fast-element-e173d34b-0061-4c9d-94b5-415929d7dc5e.json
@@ -0,0 +1,7 @@
+{
+ "type": "patch",
+ "comment": "Support element filters for declarative f-children directives.",
+ "packageName": "@microsoft/fast-element",
+ "email": "pradeepramolaa@gmail.com",
+ "dependentChangeType": "none"
+}
diff --git a/packages/fast-element/docs/declarative/syntax.md b/packages/fast-element/docs/declarative/syntax.md
index f2f7fff4b9b..cdfa2058695 100644
--- a/packages/fast-element/docs/declarative/syntax.md
+++ b/packages/fast-element/docs/declarative/syntax.md
@@ -336,6 +336,8 @@ Attribute directives include:
Example:
```html
+
+
```
- **ref**
diff --git a/packages/fast-element/src/declarative/template-bridge.pw.spec.ts b/packages/fast-element/src/declarative/template-bridge.pw.spec.ts
index be149fa427b..6a598cb61bf 100644
--- a/packages/fast-element/src/declarative/template-bridge.pw.spec.ts
+++ b/packages/fast-element/src/declarative/template-bridge.pw.spec.ts
@@ -678,6 +678,49 @@ test.describe("declarativeTemplate", () => {
expect(result.shadowText).toContain("reconnected");
});
+ test("applies element filters to declarative f-children directives", async ({
+ page,
+ }) => {
+ await page.goto("/");
+
+ const result = await page.evaluate(async () => {
+ // @ts-expect-error: Client module.
+ const { FASTElement, declarativeTemplate, uniqueElementName } = await import(
+ "/declarative-main.js"
+ );
+
+ const elementName = uniqueElementName();
+
+ document.body.insertAdjacentHTML(
+ "beforeend",
+ `IncludedText node
`,
+ );
+
+ class TestElement extends FASTElement {
+ public items = ["Foo", "Bar"];
+ public allChildren: Node[] = [];
+ public filteredChildren: Node[] = [];
+ }
+
+ await TestElement.define({
+ name: elementName,
+ template: declarativeTemplate(),
+ });
+
+ const element = document.createElement(elementName) as TestElement;
+ document.body.appendChild(element);
+ await new Promise(resolve => requestAnimationFrame(resolve));
+
+ return {
+ allChildrenTags: element.allChildren.map(node => node.nodeName),
+ filteredChildrenTags: element.filteredChildren.map(node => node.nodeName),
+ };
+ });
+
+ expect(result.allChildrenTags).toEqual(["LI", "LI"]);
+ expect(result.filteredChildrenTags).toEqual(["SPAN"]);
+ });
+
test("does not reassign a resolved template for duplicate f-template names", async ({
page,
}) => {
diff --git a/packages/fast-element/src/declarative/template-parser.ts b/packages/fast-element/src/declarative/template-parser.ts
index 4df9c5e8993..7bf75ebdbf5 100644
--- a/packages/fast-element/src/declarative/template-parser.ts
+++ b/packages/fast-element/src/declarative/template-parser.ts
@@ -45,6 +45,11 @@ interface TemplateResolutionContext {
schema: Schema;
}
+interface NodeDirectiveOptions {
+ property: string;
+ filter?: ReturnType;
+}
+
/**
* Tracks string segments accumulated during template parsing and maintains
* a running concatenation so that `bindingResolver` can receive the full
@@ -232,27 +237,12 @@ export class TemplateParser {
): void {
switch (name) {
case "children": {
- externalValues.push(children(propName));
+ externalValues.push(children(this.resolveNodeDirectiveOptions(propName)));
break;
}
case "slotted": {
- const parts = propName.trim().split(" filter ");
- const slottedOption = {
- property: parts[0],
- };
-
- if (parts[1]) {
- if (parts[1].startsWith("elements(")) {
- let params = parts[1].replace("elements(", "");
- params = params.substring(0, params.lastIndexOf(")"));
- Object.assign(slottedOption, {
- filter: elements(params || undefined),
- });
- }
- }
-
- externalValues.push(slotted(slottedOption));
+ externalValues.push(slotted(this.resolveNodeDirectiveOptions(propName)));
break;
}
@@ -264,6 +254,21 @@ export class TemplateParser {
}
}
+ private resolveNodeDirectiveOptions(propName: string): NodeDirectiveOptions {
+ const parts = propName.trim().split(" filter ");
+ const options: NodeDirectiveOptions = {
+ property: parts[0],
+ };
+
+ if (parts[1]?.startsWith("elements(")) {
+ let params = parts[1].replace("elements(", "");
+ params = params.substring(0, params.lastIndexOf(")"));
+ options.filter = elements(params || undefined);
+ }
+
+ return options;
+ }
+
/**
* Resolve an access binding — shared by content bindings, boolean-attribute
* fallback, and default attribute bindings.