This is a prerelease version of FAST (3.0.0-rc.1).

Migrating from 2.x to 3.x

Breaking Changes

HydratableElementController removed

The HydratableElementController class has been removed. Its functionality is now built into ElementController via automatic prerendered content detection. When a component connects with an existing shadow root (from SSR or declarative shadow DOM), the system automatically hydrates the existing DOM.

2.x Example:

import { HydratableElementController } from "@microsoft/fast-element";

HydratableElementController.install();

3.x: Hydration is now opt-in via enableHydration():

import { enableHydration } from "@microsoft/fast-element/hydration.js";

enableHydration();

Remove any import "@microsoft/fast-element/install-hydration.js" side-effect imports as part of the migration. The older install-hydratable-view-templates.js helper remains available for advanced use cases, but the preferred API is enableHydration(). @microsoft/fast-element no longer installs hydration automatically.

needsHydrationAttribute and deferHydrationAttribute removed

These attributes are no longer needed in server-rendered markup.

2.x Markup:

<my-component defer-hydration needs-hydration text="Hello">
    <template shadowrootmode="open">...</template>
</my-component>

3.x Markup:

<my-component text="Hello">
    <template shadowrootmode="open">...</template>
</my-component>

HydrationControllerCallbacks replaced by enableHydration + declarativeTemplate callbacks

2.x Example:

import { HydratableElementController } from "@microsoft/fast-element";

HydratableElementController.config({
    hydrationComplete() { /* ... */ }
});

3.x Example:

import { declarativeTemplate } from "@microsoft/fast-element/declarative.js";
import { enableHydration } from "@microsoft/fast-element/hydration.js";

// Global hydration callbacks
enableHydration({
    hydrationStarted() { /* ... */ },
    hydrationComplete() { /* ... */ },
});

// Per-element hydration callbacks
MyComponent.define({
    name: "my-component",
    template: declarativeTemplate({
        elementWillHydrate(source: HTMLElement) { /* ... */ },
        elementDidHydrate(source: HTMLElement) { /* ... */ },
    }),
});

Note: elementWillHydrate and elementDidHydrate now receive the HTMLElement instance instead of a string name.

isPrerendered and isHydrated split

The isPrerendered property on ElementController and ViewController now resolves true when the element had a declarative shadow root (DSD) at connect time, regardless of whether hydration ran. A new isHydrated: Promise<boolean> property resolves true only when hydration actually ran successfully.

connectedCallback() {
    super.connectedCallback();
    const ctrl = this.$fastController;
    const prerendered = await ctrl.isPrerendered;
    const hydrated = await ctrl.isHydrated;

    if (prerendered && !hydrated) {
        // Had DSD but hydration wasn't enabled
    }
}

Declarative HTML imports moved

The @microsoft/fast-html package has been removed. Import declarative HTML APIs from the FAST Element root package instead:

// Before
import { TemplateElement } from "@microsoft/fast-html";
import { deepMerge } from "@microsoft/fast-html/utilities.js";

// After
import { declarativeTemplate } from "@microsoft/fast-element/declarative.js";
import { deepMerge } from "@microsoft/fast-element/declarative-utilities.js";

Import FAST Element APIs such as FASTElement, FAST, ElementController, definition/controller types, and helper APIs from @microsoft/fast-element:

API Import path
Updates @microsoft/fast-element
Observable, observable @microsoft/fast-element
attr, AttributeDefinition, converters, ValueConverter @microsoft/fast-element
Binding, oneWay, oneTime, listener @microsoft/fast-element
DOM, DOMAspect, DOMPolicy @microsoft/fast-element
Schema, schemaRegistry, schema types @microsoft/fast-element
css @microsoft/fast-element
html, ViewTemplate, HTMLView @microsoft/fast-element
Compiler, HTMLDirective, htmlDirective, templating/view types @microsoft/fast-element
render, RenderBehavior, RenderDirective @microsoft/fast-element
enableHydration, HydrationTracker, hydration types @microsoft/fast-element/hydration.js
ArrayObserver @microsoft/fast-element
volatile @microsoft/fast-element
children @microsoft/fast-element
elements, NodeObservationDirective @microsoft/fast-element
ref @microsoft/fast-element
slotted @microsoft/fast-element
when @microsoft/fast-element
repeat @microsoft/fast-element

Hydration is opt-in via enableHydration() from @microsoft/fast-element/hydration.js.

Declarative TemplateElement API removed

The <f-template> implementation is now internal and is defined automatically when an element uses template: declarativeTemplate().

Removed Replacement
TemplateElement public export declarativeTemplate()
TemplateElement.define({ name: "f-template" }) No manual definition needed
TemplateElement.config(callbacks) declarativeTemplate(callbacks) for per-element callbacks and enableHydration(options) for global hydration callbacks
TemplateElement.options(...) attributeMap() and observerMap() define extensions
AttributeMap / ObserverMap class exports from the old declarative public surface attributeMap() / observerMap() helpers and config types

Import declarativeTemplate() and schema-driven map extensions from @microsoft/fast-element:

import { attributeMap } from "@microsoft/fast-element/attribute-map.js";
import { declarativeTemplate } from "@microsoft/fast-element/declarative.js";
import { enableHydration } from "@microsoft/fast-element/hydration.js";
import { observerMap } from "@microsoft/fast-element/observer-map.js";

enableHydration();

MyElement.define(
    {
        name: "my-element",
        template: declarativeTemplate(),
    },
    [attributeMap(), observerMap()],
);

FASTElementDefinition.schema is optional. Declarative templates assign it automatically during template resolution. Non-declarative users can provide a manual schema on the definition, or pass one directly to observerMap({ schema }).

import { Schema } from "@microsoft/fast-element";
import { observerMap } from "@microsoft/fast-element/observer-map.js";

const schema = new Schema("my-element");
MyElement.define({ name: "my-element" }, [observerMap({ schema })]);

debug.js requires explicit enablement

@microsoft/fast-element no longer configures FAST just by being imported. Call enableDebug() explicitly instead:

// Before
import "@microsoft/fast-element";

// After
import { enableDebug } from "@microsoft/fast-element";

enableDebug();

If you want debug behavior enabled automatically, keep using the root package development export or the debug rollup bundle.

RenderableFASTElement removed (@microsoft/fast-html)

The RenderableFASTElement mixin has been removed. Components extend FASTElement and call define() directly.

2.x Example:

import { RenderableFASTElement } from "@microsoft/fast-html";

RenderableFASTElement(MyComponent).defineAsync({
    name: "my-component",
    templateOptions: "defer-and-hydrate",
});

3.x Example:

MyComponent.define({
    name: "my-component",
});

Bare e removed from declarative event handlers

Declarative event handlers now reserve only $e for the DOM event and $c for the execution context. Bare e is no longer treated as the event object.

Before:

<button @click="{handleClick(e)}"></button>

After:

<button @click="{handleClick($e)}"></button>

If you used TemplateParser.hasDeprecatedEventSyntax in custom tooling, remove that check as part of the migration.

prepare() lifecycle hook removed (@microsoft/fast-html)

The prepare() hook is no longer available. Move initialization logic to connectedCallback:

2.x Example:

class MyComponent extends FASTElement {
    async prepare() {
        this.data = await fetchData();
    }
}

3.x Example:

class MyComponent extends FASTElement {
    connectedCallback() {
        super.connectedCallback();
        this.loadData();
    }
    async loadData() {
        this.data = await fetchData();
    }
}

ViewTemplate.render() signature unchanged

The isPrerendered parameter that was briefly added to ViewTemplate.render() has been removed. The prerendered path is handled entirely by the pluggable hydration hook installed via ElementController.installHydrationHook().

globalThis.FAST removed

The FAST object is no longer attached to globalThis. It is now a module-scoped export from @microsoft/fast-element.

2.x Example:

globalThis.FAST.addMessages({ ... });

3.x Example:

import { FAST } from "@microsoft/fast-element";

FAST.addMessages({ ... });

FAST.getById() removed

The FAST.getById(id, initializer) slot registry has been removed. Kernel services (update queue, observable system, etc.) are resolved through standard ES module imports.

FASTGlobal type removed

The FASTGlobal interface type has been removed. Code that referenced this type should be updated to use the FAST export directly.

KernelServiceId enum removed

The KernelServiceId enum (used with FAST.getById()) has been removed. Import kernel services directly from their respective modules.

css moved to @microsoft/fast-element

css, CSSTemplateTag, and CSSValue are imported from @microsoft/fast-element. Other style APIs (ElementStyles, CSSDirective, cssDirective, ComposableStyles, HostBehavior, HostController, StyleStrategy, and StyleTarget) are imported from @microsoft/fast-element.

Update imports to:

import { css, ElementStyles } from "@microsoft/fast-element";

ArrayObserver moved to @microsoft/fast-element

ArrayObserver is imported from @microsoft/fast-element. Other array helpers such as Splice, SpliceStrategy, SpliceStrategySupport, lengthOf, sortedCount, and Sort remain available from @microsoft/fast-element.

Update imports to:

import { ArrayObserver } from "@microsoft/fast-element";

deferHydrationAttribute moved to @microsoft/fast-element

deferHydrationAttribute is available from the root package export.

2.x imported deferHydrationAttribute from the root package.

2.x Example:

const attribute = "defer-hydration";

3.x Example:

import { deferHydrationAttribute } from "@microsoft/fast-element";

requestIdleCallback polyfill removed

The built-in requestIdleCallback / cancelIdleCallback polyfill has been removed. If your application targets environments without these APIs, provide your own polyfill.

Hydration marker format changed

The SSR hydration markers have been simplified from verbose, index-embedded comments to compact sequential markers. This is a breaking change to the SSR output format — SSR and client versions must match.

Old format New format
fe-b$$start$$<index>$$<scopeId>$$fe-b fe:b
fe-b$$end$$<index>$$<scopeId>$$fe-b fe:/b
fe-repeat$$start$$<itemIndex>$$fe-repeat fe:r
fe-repeat$$end$$<itemIndex>$$fe-repeat fe:/r
fe-eb$$start$$<elementId>$$fe-eb fe:e
fe-eb$$end$$<elementId>$$fe-eb fe:/e
data-fe-b="0 1 2" / data-fe-b-0 / data-fe-c-0-3 data-fe="N"

The HydrationMarkup API methods have been renamed (e.g., parseAttributeBindingparseAttributeBindingCount) and no longer accept index/scope parameters. See the package MIGRATION.md for the complete API mapping.

New Exports

Export Package Description
ElementController.isPrerendered fast-element Promise<boolean> — resolves true when element had DSD at connect time
ElementController.isHydrated fast-element Promise<boolean> — resolves true only when hydration ran successfully
enableHydration() fast-element/hydration.js Enables hydration support for FAST elements
HydrationTracker fast-element/hydration.js Standalone hydration lifecycle tracker class
HydrationOptions fast-element/hydration.js Type for hydration configuration options
ViewController.isPrerendered fast-element/templating.js Promise<boolean> — DSD detection for custom directives
ViewController.isHydrated fast-element/templating.js Promise<boolean> — hydration status for custom directives