diff --git a/.changeset/twelve-lions-tie.md b/.changeset/twelve-lions-tie.md
new file mode 100644
index 000000000..2010637ca
--- /dev/null
+++ b/.changeset/twelve-lions-tie.md
@@ -0,0 +1,14 @@
+---
+'astro': patch
+---
+
+Add support for components defined in Frontmatter. Previously, the following code would throw an error. Now it is officially supported!
+
+```astro
+---
+const { level = 1 } = Astro.props;
+const Element = `h${level}`;
+---
+
+Hello world!
+```
diff --git a/packages/astro/src/compiler/codegen/index.ts b/packages/astro/src/compiler/codegen/index.ts
index 7bfb55f53..6a5b5e546 100644
--- a/packages/astro/src/compiler/codegen/index.ts
+++ b/packages/astro/src/compiler/codegen/index.ts
@@ -688,7 +688,21 @@ async function compileHtml(enterNode: TemplateNode, state: CodegenState, compile
componentInfo = components.get(componentNamespace);
}
if (!componentInfo && !isCustomElementTag(componentName)) {
- throw new Error(`Unknown Component: ${componentName}`);
+ if (hydrationAttributes.method) {
+ throw new Error(`Unable to hydrate "${componentName}" because it is statically defined in the frontmatter script. Hydration directives may only be used on imported components.`);
+ }
+
+ // Previously we would throw here, but this is valid!
+ // If the frontmatter script defines `const Element = 'h1'`,
+ // you should be able to statically render ``
+
+ if (curr === 'markdown') {
+ await pushMarkdownToBuffer();
+ }
+
+ paren++;
+ buffers[curr] += `h(${componentName}, ${attributes ? generateAttributes(attributes) : 'null'}`;
+ return;
}
if (componentName === 'Markdown') {
const { $scope } = attributes ?? {};
diff --git a/packages/astro/test/astro-basic.test.js b/packages/astro/test/astro-basic.test.js
index 38f62085e..c2051b3eb 100644
--- a/packages/astro/test/astro-basic.test.js
+++ b/packages/astro/test/astro-basic.test.js
@@ -95,4 +95,12 @@ Basics('Allows spread attributes with TypeScript (#521)', async ({ runtime }) =>
assert.equal($('#spread-ts').attr('c'), '2');
});
+Basics('Allows Components defined in frontmatter', async ({ runtime }) => {
+ const result = await runtime.load('/frontmatter-component');
+ const html = result.contents;
+ const $ = doc(html);
+
+ assert.equal($('h1').length, 1);
+});
+
Basics.run();
diff --git a/packages/astro/test/fixtures/astro-basic/src/pages/frontmatter-component.astro b/packages/astro/test/fixtures/astro-basic/src/pages/frontmatter-component.astro
new file mode 100644
index 000000000..69f708505
--- /dev/null
+++ b/packages/astro/test/fixtures/astro-basic/src/pages/frontmatter-component.astro
@@ -0,0 +1,6 @@
+---
+const { level = 1 } = Astro.props;
+const Element = `h${level}`;
+---
+
+Hello world!