+```
+
+
+
+
+
+For a more in depth look at the differences between Enhance and React components, [read this post on the Begin blog](https://begin.com/blog/posts/2024-03-08-a-react-developers-guide-to-writing-enhance-components).
diff --git a/app/docs/md/patterns/event-listeners.md b/app/cookbook/use-event-listeners.md
similarity index 99%
rename from app/docs/md/patterns/event-listeners.md
rename to app/cookbook/use-event-listeners.md
index d93ce45b..6882c5f9 100644
--- a/app/docs/md/patterns/event-listeners.md
+++ b/app/cookbook/use-event-listeners.md
@@ -1,5 +1,5 @@
---
-title: Event Listeners
+title: Use event listeners
---
An event is a signal that something has happened on your page. The browser notifies you so you can react to them.
diff --git a/app/cookbook/use-typescript.md b/app/cookbook/use-typescript.md
new file mode 100644
index 00000000..a101c9c9
--- /dev/null
+++ b/app/cookbook/use-typescript.md
@@ -0,0 +1,104 @@
+---
+title: Use TypeScript
+---
+
+If you prefer to work with TypeScript, we recommend starting with our [TypeScript starter project](https://github.com/enhance-dev/enhance-starter-typescript).
+
+
+## Getting Started
+
+Assuming you’re starting a new Enhance project, you would run the command:
+
+```bash
+npx "@enhance/cli@latest" new ./myproject \
+ --template https://github.com/enhance-dev/enhance-starter-typescript -y
+```
+
+This will set up a new Enhance project where you’ll code your APIs, elements and pages in TypeScript instead of JavaScript. Instead of editing files in the `app` folder, you’ll do your editing in the `ts` folder.
+
+
+### Project Structure
+
+``` \
+ts
+├── api ............... data routes
+│ └── index.mts
+├── browser ........... browser JavaScript
+│ └── index.mts
+├── components ........ single file web components
+│ └── my-card.mts
+├── elements .......... custom element pure functions
+│ └── my-header.mts
+├── pages ............. file-based routing
+│ └── index.html
+└── head.mts .......... custom component
+```
+
+Note: We are using `.mts` to tell the TypeScript Compiler to generate ES Modules as `.mjs` files..
+
+
+## Local Development
+
+Running the local development environment is the same as any other Enhance project. The new `@enhance/plugin-typescript` is responsible for watching the `ts` folder for any file changes. If a file with an `.mts` extension is updated, it will be re-compiled with the compilation target being the `app` folder. All other file types are simply copied to their corresponding locations in the `app` folder.
+
+## Authoring Code
+
+Write your code in TypeScript. We already have [types](https://github.com/enhance-dev/types) that you can import into your elements:
+
+
+
+```typescript
+import type { EnhanceElemArg } from "@enhance/types"
+
+export default ({ html, state: { attrs } }: EnhanceElemArg) => {
+ const { state = "" } = attrs
+ return html`
+ ${state === "complete" ? "☑" : "☐"}
+
+ `
+}
+```
+
+
+
+Or APIs:
+
+
+
+```typescript
+import type {
+ EnhanceApiFn,
+ EnhanceApiReq,
+ EnhanceApiRes,
+} from "@enhance/types";
+
+type Todo = {
+ title: string;
+ completed?: boolean;
+};
+
+export const get: EnhanceApiFn = async function (
+ request: EnhanceApiReq,
+): Promise {
+
+ console.log(`Handling ${request.path}...`);
+
+ const todos: Todo[] = [
+ { title: "todo 1", completed: false },
+ { title: "todo 2", completed: true },
+ { title: "todo 3" },
+ ];
+
+ const response: EnhanceApiRes = {
+ json: { todos },
+ };
+
+ return response;
+};
+```
+
+
+
+## Deploying
+
+Use the [`@begin/deploy`](https://begin.com/deploy/docs/workflows/deploying-code) package to deploy your application. Alternatively, you can write a GitHub Action to [deploy on every commit](https://github.com/enhance-dev/enhance-starter-typescript/blob/main/.github/workflows/CI.yml).
diff --git a/app/docs/md/patterns/form-validation.md b/app/cookbook/validate-forms.md
similarity index 99%
rename from app/docs/md/patterns/form-validation.md
rename to app/cookbook/validate-forms.md
index f101a51e..835b85dd 100644
--- a/app/docs/md/patterns/form-validation.md
+++ b/app/cookbook/validate-forms.md
@@ -1,5 +1,5 @@
---
-title: Form Validation
+title: Validate forms
---
HTML forms are very powerful on their own.
diff --git a/app/docs/md/patterns/testing/index.md b/app/cookbook/write-unit-tests.md
similarity index 98%
rename from app/docs/md/patterns/testing/index.md
rename to app/cookbook/write-unit-tests.md
index 05c7e11a..3d67bff6 100644
--- a/app/docs/md/patterns/testing/index.md
+++ b/app/cookbook/write-unit-tests.md
@@ -1,5 +1,5 @@
---
-title: Testing
+title: Write unit tests
---
A big benefit of Enhance custom element [pure functions](https://en.wikipedia.org/wiki/Pure_function) is that they return a string that you can test against an expected output. It doesn't need to get any more complicated than that to get started.
diff --git a/app/docs/md/patterns/testing/webdriverio.md b/app/docs/md/patterns/testing/webdriverio.md
deleted file mode 100644
index f4999f5e..00000000
--- a/app/docs/md/patterns/testing/webdriverio.md
+++ /dev/null
@@ -1,44 +0,0 @@
----
-title: Component Testing With WebdriverIO
----
-
-Running component tests allow you to mount, render and interact with a single Enhance component in isolation.
-To ensure that test conditions are as close as possible to the real world, we recommend to run them in actual browser rather than using e.g. [JSDOM](https://github.com/jsdom/jsdom) which is just a JavaScript implementation of web standards provided by browsers.
-To run Enhance component tests you can use [WebdriverIO](https://webdriver.io/) as a browser automation framework.
-It is based on the [WebDriver](https://www.w3.org/TR/webdriver/) protocol, a browser automation web standard which guarantees that your tests interact with your components as closely as possible to how a user would.
-
-To add a WebdriverIO test harness to your project, run:
-
-```shell
-npm init wdio@latest ./
-```
-
-The command initializes a configuration wizard that helps you set-up the test harness.
-Make sure to select on the first question: "_Where should your tests be launched?_" the answer: "_browser - for unit and component testing in the browser_".
-
-An example test file should be created. Replace the content with e.g.:
-
-```javascript
-import { expect, browser, $$ } from '@wdio/globals'
-import enhance from '@enhance/ssr'
-
-// see actual component here: https://github.com/webdriverio/component-testing-examples/blob/main/enhance/app/elements/my-header.mjs
-import MyHeader from '../../app/elements/my-header.mjs'
-
-describe('Enhance Framework', () => {
- it('should render MyHeader element correctly', async () => {
- const html = enhance({
- elements: {
- 'my-header': MyHeader
- }
- })
- const actual = document.createElement('div')
- actual.innerHTML = (html``).replace(/<\/?\s*(html|head|body)>/g, '')
- document.body.appendChild(actual)
- expect(await $$('img').length).toBe(2)
- })
-})
-```
-
-You can find the WebdriverIO API docs at [webdriver.io/docs/api](https://webdriver.io/docs/api) and the full example for Enhance component testing [on GitHub](https://github.com/webdriverio/component-testing-examples/tree/main/enhance).
-If you have any questions, join the project's [Discord](https://discord.webdriver.io/) server.
\ No newline at end of file
diff --git a/app/docs/nav-data.mjs b/app/docs/nav-data.mjs
index 841853ec..c9c44727 100644
--- a/app/docs/nav-data.mjs
+++ b/app/docs/nav-data.mjs
@@ -137,17 +137,6 @@ export const data = [
slug: 'patterns',
items: [
'progressive-enhancement',
- 'building-for-the-browser',
- 'form-validation',
- {
- slug: 'testing',
- path: '/docs/patterns/testing/',
- hasChildren: true,
- items: [ { slug: 'webdriverio', label: 'WebdriverIO' } ],
- },
- 'architect-migration',
- 'rendering-markdown',
- 'event-listeners',
],
},
/*
diff --git a/app/elements/code-compare.mjs b/app/elements/code-compare.mjs
new file mode 100644
index 00000000..3fd6f1f3
--- /dev/null
+++ b/app/elements/code-compare.mjs
@@ -0,0 +1,20 @@
+export default function CodeCompare ({ html }) {
+ return html`
+
+
+ `
+}
diff --git a/app/elements/cookbook/article.mjs b/app/elements/cookbook/article.mjs
new file mode 100644
index 00000000..f3acab0d
--- /dev/null
+++ b/app/elements/cookbook/article.mjs
@@ -0,0 +1,221 @@
+export default function CookbookArticle ({ html }) {
+ return html`
+
+
+
+
+ More recipes
+
+
+
+
+
+
+
+ `
+}
diff --git a/app/elements/cookbook/header.mjs b/app/elements/cookbook/header.mjs
new file mode 100644
index 00000000..5deb5b2c
--- /dev/null
+++ b/app/elements/cookbook/header.mjs
@@ -0,0 +1,58 @@
+export default function CookbookHeader ({ html }) {
+ return html`
+
+
+
+
+
+
+
+
+
+ Let’s get cooking!
+
+
+
+ Learning new things can be fun — but also challenging. The Enhance Cookbook is here to show you around the kitchen and help you get your hands dirty.
+
+
+ `
+}
diff --git a/app/elements/cookbook/recipe-box.mjs b/app/elements/cookbook/recipe-box.mjs
new file mode 100644
index 00000000..0fa58629
--- /dev/null
+++ b/app/elements/cookbook/recipe-box.mjs
@@ -0,0 +1,13 @@
+export default function RecipeBox ({ html }) {
+ return html`
+
+
+ `
+}
diff --git a/app/elements/cookbook/recipe-card.mjs b/app/elements/cookbook/recipe-card.mjs
new file mode 100644
index 00000000..8a6d8d88
--- /dev/null
+++ b/app/elements/cookbook/recipe-card.mjs
@@ -0,0 +1,42 @@
+export default function Recipe ({ html, state }) {
+ const { attrs } = state
+ const { href, name } = attrs
+
+ return html`
+
+
+
+