Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ Each package includes a DESIGN.md file, read that to gain a general understandin
- `examples/design-system/` β€” Shared semantic design tokens (`@microsoft/fast-examples-design-system`) consumed by all example apps.
- `examples/csr/todo-app/` β€” A simple To-Do app demonstrating FAST usage patterns and using the shared `@microsoft/fast-examples-design-system` tokens.
- `examples/csr/todo-mobx-app/` β€” A To-Do app demonstrating how to integrate MobX state with `@microsoft/fast-element` using a single `autorun` per component (no custom bridge code).
- `examples/ssr/webui-todo-app/` β€” A To-Do app demonstrating FAST declarative HTML with `@microsoft/webui` prerendering and `@microsoft/fast-html` hydration. Light theme.

## Skills

Expand Down
14 changes: 8 additions & 6 deletions examples/DESIGN.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# FAST example apps β€” design guidance

This document is the workspace-level guide for building UI in `examples/*`
and its rendering-strategy subfolders (currently `examples/csr/`). It
explains how the apps share a visual language, the constraints every example
must follow, and the rules that humans and coding agents should apply when
making changes. The token vocabulary itself lives in
and its rendering-strategy subfolders (`examples/csr/` and `examples/ssr/`).
It explains how the apps share a visual language, the constraints every
example must follow, and the rules that humans and coding agents should
apply when making changes. The token vocabulary itself lives in
[`design-system/DESIGN.md`](./design-system/DESIGN.md); read that file
alongside this one.

Expand Down Expand Up @@ -157,8 +157,10 @@ document.documentElement.removeAttribute("data-theme"); // restore system
```

For an intentionally single-theme app β€” like
[`todo-app`](./todo-app/) β€” hard-code the attribute in markup
(`<html data-theme="light">`) and never touch it from JavaScript.
[`csr/todo-app`](./csr/todo-app/) and
[`ssr/webui-todo-app`](./ssr/webui-todo-app/) β€” hard-code the attribute in
markup (`<html data-theme="light">` or `<html data-theme="dark">`) and never
touch it from JavaScript.

## Authoring rules

Expand Down
25 changes: 15 additions & 10 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ FAST patterns in a complete app context.
| `design-system` | `@microsoft/fast-examples-design-system` | Shared CSS design tokens (no JS) consumed by every example app. |
| `csr/todo-app` | `@microsoft/fast-todo-app-example` | A To-Do app demonstrating `@microsoft/fast-element` patterns end to end, styled with the shared design-system tokens (light theme, no runtime toggle). |
| `csr/todo-mobx-app` | `@microsoft/fast-todo-mobx-app-example` | A To-Do app showing how to integrate MobX state with `@microsoft/fast-element` using a single `autorun` per component (no custom bridge code), styled with the shared design-system tokens. |
| `ssr/webui-todo-app` | `@microsoft/fast-webui-todo-app-example` | A To-Do app pre-rendered by `@microsoft/webui` and hydrated by `@microsoft/fast-html`, styled with the shared design-system tokens (light theme, no runtime toggle). |

Example apps are grouped by rendering strategy. Client-side-rendered (CSR)
apps live under [`examples/csr/`](./csr/); future server-side-rendered (SSR)
apps will live alongside them under their own subfolder.
apps live under [`examples/csr/`](./csr/) and server-side-rendered (SSR) apps
live under [`examples/ssr/`](./ssr/).

## Shared design system

Expand Down Expand Up @@ -51,17 +52,20 @@ See:
## Creating a new example app

1. Scaffold a new folder under the appropriate rendering-strategy subfolder
(CSR apps go under `examples/csr/<your-app>/`).
2. Use [`examples/csr/todo-app/`](./csr/todo-app/) as a reference for
`package.json`, `tsconfig.json`, `vite.config.ts`, and `index.html`.
3. Add `"@microsoft/fast-examples-design-system": "workspace:*"` to the new
(CSR apps go under `examples/csr/<your-app>/`; SSR apps go under
`examples/ssr/<your-app>/`).
2. Use [`examples/csr/todo-app/`](./csr/todo-app/) as a reference for CSR
apps, or [`examples/ssr/webui-todo-app/`](./ssr/webui-todo-app/) as a
reference for SSR apps (`package.json`, `tsconfig.json`, build config,
entry HTML).
3. Add `"@microsoft/fast-examples-design-system": "^1.0.0"` to the new
app's `dependencies` and run `npm install` from the repo root.
4. Import `@microsoft/fast-examples-design-system/tokens.css` exactly once at
the app entry point (typically `src/main.ts`). For an intentionally
single-theme app, hard-code `<html data-theme="light">` (or `"dark"`)
in `index.html` and never touch it from JavaScript.
the app entry point (typically `src/main.ts` or `src/index.ts`). For an
intentionally single-theme app, hard-code `<html data-theme="light">` (or
`"dark"`) in the entry HTML and never touch it from JavaScript.
5. Reference tokens via `var(--fast-...)` in component `css` template
literals β€” do not hard-code design values.
literals or `.css` files β€” do not hard-code design values.
6. If the app needs a theme toggle, set or remove the `data-theme` attribute
on `<html>` from your app code:
```ts
Expand All @@ -86,6 +90,7 @@ For the existing example apps:
```shell
npm start -w @microsoft/fast-todo-app-example
npm start -w @microsoft/fast-todo-mobx-app-example
npm start -w @microsoft/fast-webui-todo-app-example
```

## Useful links
Expand Down
142 changes: 142 additions & 0 deletions examples/ssr/webui-todo-app/DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# WebUI Todo App β€” design and architecture

This document describes the SSR todo example in
`examples/ssr/webui-todo-app/`. For the shared token catalog and naming rules,
see [`../../design-system/README.md`](../../design-system/README.md) and
[`../../design-system/DESIGN.md`](../../design-system/DESIGN.md).

## Purpose

This example demonstrates three pieces working together:

- FAST declarative templates stored as co-located `*.html` and `*.css` files.
- `@microsoft/webui` prerendering on the server, including Declarative Shadow
DOM output.
- Client-side hydration through `@microsoft/fast-html`, so the prerendered UI
becomes interactive without re-rendering from scratch.

The app stays intentionally small: a single todo list with add, toggle, and
delete behavior backed by a JSON state file.

## Folder structure

```text
examples/ssr/webui-todo-app/
β”œβ”€β”€ DESIGN.md
β”œβ”€β”€ README.md
β”œβ”€β”€ data/
β”‚ └── state.json
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ index.html
β”‚ β”œβ”€β”€ index.ts
β”‚ β”œβ”€β”€ todo-app/
β”‚ β”‚ β”œβ”€β”€ todo-app.css
β”‚ β”‚ β”œβ”€β”€ todo-app.html
β”‚ β”‚ └── todo-app.ts
β”‚ └── todo-item/
β”‚ β”œβ”€β”€ todo-item.css
β”‚ β”œβ”€β”€ todo-item.html
β”‚ └── todo-item.ts
β”œβ”€β”€ package.json
└── tsconfig.json
```

### File roles

- `src/index.html` β€” document shell, page-level layout, and static
`data-theme="light"` selection.
- `src/index.ts` β€” hydration entry; imports shared `tokens.css`, registers the
custom elements, and defines `<f-template>`.
- `src/todo-app/` β€” root template, styles, and list management logic.
- `src/todo-item/` β€” per-row template, styles, and event dispatch for toggle
and delete actions.
- `data/state.json` β€” initial server state consumed by `webui serve`.

## Build and serve flow

1. `npm run build -w @microsoft/fast-webui-todo-app-example` runs esbuild on
`src/index.ts`.
2. Esbuild emits `dist/index.js` for hydration and bootstrap code.
3. Because `src/index.ts` imports
`@microsoft/fast-examples-design-system/tokens.css`, esbuild also emits
`dist/index.css`.
4. `webui serve ./src --state ./data/state.json --plugin=fast --servedir ./dist`
uses `./src` as the source root for HTML templates and exposes the bundled
assets from `./dist`.
5. On each request, `webui` reads `src/index.html`, resolves `{{}}` bindings
from `data/state.json`, renders Declarative Shadow DOM, and returns
prerendered HTML.
6. In the browser, `/index.js` defines the FAST custom elements and hydrates the
prerendered DOM in place.
7. `/index.css` makes the shared `--fast-*` tokens available to both the page
shell and shadow-root component styles.

## Component model

### `todo-app`

`todo-app` is the root custom element. It:

- reads the prerendered `<todo-item>` children during `prepare()`,
- converts them into an observable `items` array,
- tracks `remainingCount`,
- handles add, toggle, and delete operations, and
- re-renders the list through FAST bindings after hydration.

### `todo-item`

`todo-item` is a focused row component. It accepts `id`, `title`, and `state`
attributes, then emits `toggle-item` and `delete-item` events that the parent
handles.

## Design system wiring

This example consumes the shared
`@microsoft/fast-examples-design-system` workspace package.

- `src/index.ts` imports `@microsoft/fast-examples-design-system/tokens.css`
exactly once.
- `src/index.html` links the generated `/index.css` bundle before its inline
page-shell styles.
- `<html dir="{{textdirection}}" lang="en" data-theme="light">` hard-codes the
light theme at document level.
- There is no runtime theme toggle, no theme persistence, and no JavaScript
that mutates `data-theme`.

The design-system package is CSS-only. This example just consumes the
registered custom properties through `var(--fast-...)`.

## Representative tokens

The component styles rely on shared tokens rather than hard-coded design
values. Representative examples include:

- Page shell: `--fast-background-web-page-primary`,
`--fast-foreground-ctrl-neutral-primary-rest`,
`--fast-padding-content-xx-large`.
- Root card and section chrome: `--fast-background-layer-primary-solid`,
`--fast-stroke-divider-subtle`, `--fast-corner-large`,
`--fast-shadow-card-rest`.
- Typography: `--fast-text-style-default-regular-font-family`,
`--fast-text-global-body3-font-size`,
`--fast-text-global-body3-line-height`,
`--fast-text-global-title1-font-size`,
`--fast-text-global-title1-line-height`.
- Brand actions: `--fast-background-ctrl-brand-rest`,
`--fast-background-ctrl-brand-hover`,
`--fast-background-ctrl-brand-pressed`,
`--fast-foreground-ctrl-on-brand-rest`.
- Focus and motion: `--fast-ctrl-focus-outer-stroke`,
`--fast-ctrl-focus-outer-stroke-width`, `--fast-duration-fast`,
`--fast-curve-easy-ease`.
- Status states: `--fast-status-success-tint-foreground`,
`--fast-status-success-tint-background`,
`--fast-status-danger-tint-foreground`,
`--fast-status-danger-tint-background`.

## Why this example lives under `examples/ssr/`

Although the UI hydrates into client-side FAST components, the initial render is
produced through `@microsoft/webui` on the server. The important example
behavior is therefore SSR + prerendering + hydration, not a purely client-only
bootstrap.
124 changes: 124 additions & 0 deletions examples/ssr/webui-todo-app/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# WebUI Todo App

A Todo app demonstrating FAST declarative HTML templates with
[webui](https://github.com/microsoft/webui) prerendering and hydration.

This example shows how to combine `@microsoft/fast-html` declarative templates
with `@microsoft/webui` for server-side prerendering, producing a fast initial
render that hydrates into a fully interactive FAST web component application.

## Features

- **Declarative templates**: Uses `.html` and `.css` files instead of
imperative `html`/`css` tagged template literals
- **Server-side prerendering**: `webui serve` compiles declarative templates
and renders initial state into static HTML
- **Client-side hydration**: `@microsoft/fast-html` picks up prerendered DOM
and attaches FAST reactive bindings
- **Todo functionality**: Add items, toggle completion, delete items,
remaining count

## Prerequisites

From the monorepo root, install dependencies and build packages:

```bash
npm ci
npm run build
```

## Running

```bash
# Build client bundle and start the webui dev server
npm start -w @microsoft/fast-webui-todo-app-example
```

The app will be available at `http://localhost:8081`.

For development with live reloading, run the client and server in separate
terminals:

```bash
# Terminal 1: Watch and rebuild client bundle
npm run start:client -w @microsoft/fast-webui-todo-app-example

# Terminal 2: Start webui dev server with --watch
npm run start:server -w @microsoft/fast-webui-todo-app-example
```

## Design system

This example consumes the shared `@microsoft/fast-examples-design-system`
workspace package. The design-system package is **CSS-only** β€” there are no
JavaScript or TypeScript exports. `src/index.ts` imports
`@microsoft/fast-examples-design-system/tokens.css` once, and the rest of the
app references the registered `--fast-*` design tokens through `var(...)`.

The app uses the **light** theme. `<html data-theme="light">` is set
statically in [`src/index.html`](./src/index.html); the app does not implement
a runtime theme toggle. (The shared design-system package supports dark and
system-preference themes via the same `data-theme` attribute β€” see
[`../../design-system/README.md`](../../design-system/README.md) β€” but this
example deliberately keeps the SSR surface area minimal and demonstrates only
token consumption.)

For the shared package overview, the token catalog, and authoring rules, see
[`../../design-system/README.md`](../../design-system/README.md) and
[`../../design-system/DESIGN.md`](../../design-system/DESIGN.md).

## Architecture

### Server-side (`webui serve`)

The `webui` CLI serves the app with the `--plugin=fast` flag, which enables
FAST-aware template processing:

1. Scans `./src` for declarative HTML templates (`.html` files wrapped in
`<f-template>` or containing `<template shadowrootmode="open">`)
2. Reads initial state from `./data/state.json`
3. Renders templates server-side with `{{}}` bindings resolved from state
4. Injects Declarative Shadow DOM for instant first paint
5. Serves the bundled client assets from `./dist`

`src/index.ts` imports `@microsoft/fast-examples-design-system/tokens.css`.
When esbuild bundles the entry point, it emits both `dist/index.js` and
`dist/index.css`. `src/index.html` links `/index.css` so the shared `--fast-*`
tokens are available during prerendering and after hydration.

### Templates (`src/todo-app/`, `src/todo-item/`)

Each component uses co-located files:

- `*.html` β€” Declarative template with `<template shadowrootmode="open">`
and FAST bindings
- `*.css` β€” Scoped styles loaded via `<link rel="stylesheet">` in the shadow
DOM
- `*.ts` β€” Component class using `RenderableFASTElement` mixin with
`defineAsync`

### Client entry (`src/index.ts`)

Bootstraps hydration by:

1. Importing components (side-effect registration via `defineAsync`)
2. Configuring `TemplateElement` with observer maps for reactive attribute
tracking
3. Defining `<f-template>` to trigger hydration of prerendered shadow DOM

### Binding syntax

| Syntax | Scope | Example |
|---|---|---|
| `{{expr}}` | Server + client | `{{title}}` β€” HTML-escaped value |
| `{{{expr}}}` | Server + client | Raw unescaped HTML |
| `{expr}` | Client-only | `{onClick(e)}` β€” event handlers, refs |
| `@event="{handler}"` | Client-only | `@click="{onAddClick()}"` |
| `f-ref="{prop}"` | Client-only | `f-ref="{addInput}"` β€” element reference |

### Template directives

| Directive | Purpose | Example |
|---|---|---|
| `<for each="item in items">` | Iteration | `<for each="item in items"><todo-item>...</todo-item></for>` |
| `<if condition="expr">` | Conditional | `<if condition="state == 'done'">...</if>` |
23 changes: 23 additions & 0 deletions examples/ssr/webui-todo-app/data/state.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"textdirection": "ltr",
"language": "en",
"title": "FAST Todos",
"remainingCount": 2,
"items": [
{
"id": "1",
"title": "Buy groceries",
"state": "done"
},
{
"id": "2",
"title": "Write documentation",
"state": "pending"
},
{
"id": "3",
"title": "Ship feature",
"state": "pending"
}
]
}
Loading