summaryrefslogtreecommitdiff
path: root/packages/integrations/markdoc/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/markdoc/README.md')
-rw-r--r--packages/integrations/markdoc/README.md256
1 files changed, 110 insertions, 146 deletions
diff --git a/packages/integrations/markdoc/README.md b/packages/integrations/markdoc/README.md
index 76291e763..85a657ea4 100644
--- a/packages/integrations/markdoc/README.md
+++ b/packages/integrations/markdoc/README.md
@@ -99,53 +99,46 @@ const { Content } = await entry.render();
### Using components
-You can add Astro and UI framework components (React, Vue, Svelte, etc.) to your Markdoc using both [Markdoc tags][markdoc-tags] and HTML element [nodes][markdoc-nodes].
+You can add Astro components to your Markdoc using both [Markdoc tags][markdoc-tags] and HTML element [nodes][markdoc-nodes].
#### Render Markdoc tags as Astro components
-You may configure [Markdoc tags][markdoc-tags] that map to components. You can configure a new tag from your `astro.config` using the `tags` attribute.
+You may configure [Markdoc tags][markdoc-tags] that map to components. You can configure a new tag by creating a `markdoc.config.mjs|ts` file at the root of your project and configuring the `tag` attribute.
+This example renders an `Aside` component, and allows a `type` prop to be passed as a string:
```js
-// astro.config.mjs
-import { defineConfig } from 'astro/config';
-import markdoc from '@astrojs/markdoc';
-
-// https://astro.build/config
-export default defineConfig({
- integrations: [
- markdoc({
- tags: {
- aside: {
- render: 'Aside',
- attributes: {
- // Component props as attribute definitions
- // See Markdoc's documentation on defining attributes
- // https://markdoc.dev/docs/attributes#defining-attributes
- type: { type: String },
- }
- },
- },
- }),
- ],
-});
+// markdoc.config.mjs
+import { defineMarkdocConfig } from '@astrojs/markdoc/config';
+import Aside from './src/components/Aside.astro';
+
+export default defineMarkdocConfig({
+ tags: {
+ aside: {
+ render: Aside,
+ attributes: {
+ // Markdoc requires type defs for each attribute.
+ // These should mirror the `Props` type of the component
+ // you are rendering.
+ // See Markdoc's documentation on defining attributes
+ // https://markdoc.dev/docs/attributes#defining-attributes
+ type: { type: String },
+ }
+ },
+ },
+})
```
-Then, you can wire this render name (`'Aside'`) to a component from the `components` prop via the `<Content />` component. Note the object key name (`Aside` in this case) should match the render name:
+This component can now be used in your Markdoc files with the `{% aside %}` tag. Children will be passed to your component's default slot:
+```md
+# Welcome to Markdoc πŸ‘‹
-```astro
----
-import { getEntryBySlug } from 'astro:content';
-import Aside from '../components/Aside.astro';
+{% aside type="tip" %}
-const entry = await getEntryBySlug('docs', 'why-markdoc');
-const { Content } = await entry.render();
----
+Use tags like this fancy "aside" to add some *flair* to your docs.
-<Content
- components={{ Aside }}
-/>
+{% /aside %}
```
#### Render Markdoc nodes / HTML elements as Astro components
@@ -153,46 +146,22 @@ const { Content } = await entry.render();
You may also want to map standard HTML elements like headings and paragraphs to components. For this, you can configure a custom [Markdoc node][markdoc-nodes]. This example overrides Markdoc's `heading` node to render a `Heading` component, passing the built-in `level` attribute as a prop:
```js
-// astro.config.mjs
-import { defineConfig } from 'astro/config';
-import markdoc from '@astrojs/markdoc';
-
-// https://astro.build/config
-export default defineConfig({
- integrations: [
- markdoc({
- nodes: {
- heading: {
- render: 'Heading',
- // Markdoc requires type defs for each attribute.
- // These should mirror the `Props` type of the component
- // you are rendering.
- // See Markdoc's documentation on defining attributes
- // https://markdoc.dev/docs/attributes#defining-attributes
- attributes: {
- level: { type: String },
- }
- },
- },
- }),
- ],
-});
-```
-
-Now, you can map the string passed to render (`'Heading'` in this example) to a component import. This is configured from the `<Content />` component used to render your Markdoc using the `components` prop:
-
-```astro
----
-import { getEntryBySlug } from 'astro:content';
-import Heading from '../components/Heading.astro';
-
-const entry = await getEntryBySlug('docs', 'why-markdoc');
-const { Content } = await entry.render();
----
-
-<Content
- components={{ Heading }}
-/>
+// markdoc.config.mjs
+import { defineMarkdocConfig } from '@astrojs/markdoc/config';
+import Heading from './src/components/Heading.astro';
+
+export default defineMarkdocConfig({
+ nodes: {
+ heading: {
+ render: Heading,
+ attributes: {
+ // Pass the attributes from Markdoc's default heading node
+ // as component props.
+ level: { type: String },
+ }
+ },
+ },
+})
```
Now, all Markdown headings will render with the `Heading.astro` component. This example uses a level 3 heading, automatically passing `level: 3` as the component prop:
@@ -215,26 +184,26 @@ This example wraps a `Aside.tsx` component with a `ClientAside.astro` wrapper:
import Aside from './Aside';
---
-<Aside client:load />
+<Aside {...Astro.props} client:load />
```
-This component [can be applied via the `components` prop](#render-markdoc-nodes--html-elements-as-astro-components):
-
-```astro
----
-// src/pages/why-markdoc.astro
-import { getEntryBySlug } from 'astro:content';
-import ClientAside from '../components/ClientAside.astro';
-
-const entry = await getEntryBySlug('docs', 'why-markdoc');
-const { Content } = await entry.render();
----
+This component can be passed to the `render` prop for any [tag][markdoc-tags] or [node][markdoc-nodes] in your config:
-<Content
- components={{
- Aside: ClientAside,
- }}
-/>
+```js
+// markdoc.config.mjs
+import { defineMarkdocConfig } from '@astrojs/markdoc/config';
+import Aside from './src/components/Aside.astro';
+
+export default defineMarkdocConfig({
+ tags: {
+ aside: {
+ render: Aside,
+ attributes: {
+ type: { type: String },
+ }
+ },
+ },
+})
```
### Access frontmatter and content collection information from your templates
@@ -253,35 +222,29 @@ The `$entry` object matches [the `CollectionEntry` type](https://docs.astro.buil
### Markdoc config
-The Markdoc integration accepts [all Markdoc configuration options](https://markdoc.dev/docs/config), including [tags](https://markdoc.dev/docs/tags) and [functions](https://markdoc.dev/docs/functions).
+The `markdoc.config.mjs|ts` file accepts [all Markdoc configuration options](https://markdoc.dev/docs/config), including [tags](https://markdoc.dev/docs/tags) and [functions](https://markdoc.dev/docs/functions).
-You can pass these options from the `markdoc()` integration in your `astro.config`. This example adds a global `getCountryEmoji` function:
+You can pass these options from the default export in your `markdoc.config.mjs|ts` file:
```js
-// astro.config.mjs
-import { defineConfig } from 'astro/config';
-import markdoc from '@astrojs/markdoc';
-
-// https://astro.build/config
-export default defineConfig({
- integrations: [
- markdoc({
- functions: {
- getCountryEmoji: {
- transform(parameters) {
- const [country] = Object.values(parameters);
- const countryToEmojiMap = {
- japan: 'πŸ‡―πŸ‡΅',
- spain: 'πŸ‡ͺπŸ‡Έ',
- france: 'πŸ‡«πŸ‡·',
- }
- return countryToEmojiMap[country] ?? '🏳'
- },
- },
+// markdoc.config.mjs
+import { defineMarkdocConfig } from '@astrojs/markdoc/config';
+
+export default defineMarkdocConfig({
+ functions: {
+ getCountryEmoji: {
+ transform(parameters) {
+ const [country] = Object.values(parameters);
+ const countryToEmojiMap = {
+ japan: 'πŸ‡―πŸ‡΅',
+ spain: 'πŸ‡ͺπŸ‡Έ',
+ france: 'πŸ‡«πŸ‡·',
+ }
+ return countryToEmojiMap[country] ?? '🏳'
},
- }),
- ],
-});
+ },
+ },
+})
```
Now, you can call this function from any Markdoc content entry:
@@ -290,47 +253,46 @@ Now, you can call this function from any Markdoc content entry:
Β‘Hola {% getCountryEmoji("spain") %}!
```
-:::note
-These options will be applied during [the Markdoc "transform" phase](https://markdoc.dev/docs/render#transform). This is run **at build time** (rather than server request time) both for static and SSR Astro projects. If you need to define configuration at runtime (ex. SSR variables), [see the next section](#define-markdoc-configuration-at-runtime).
-:::
-
πŸ“š [See the Markdoc documentation](https://markdoc.dev/docs/functions#creating-a-custom-function) for more on using variables or functions in your content.
-### Define Markdoc configuration at runtime
+### Pass Markdoc variables
-You may need to define Markdoc configuration at the component level, rather than the `astro.config.mjs` level. This is useful when mapping props and SSR parameters to [Markdoc variables](https://markdoc.dev/docs/variables).
+You may need to pass [variables][markdoc-variables] to your content. This is useful when passing SSR parameters like A/B tests.
-Astro recommends running the Markdoc transform step manually. This allows you to define your configuration and call Markdoc's rendering functions in a `.astro` file directly, ignoring any Markdoc config in your `astro.config.mjs`.
+Variables can be passed as props via the `Content` component:
-You will need to install the `@markdoc/markdoc` package into your project first:
+```astro
+---
+import { getEntryBySlug } from 'astro:content';
-```sh
-# Using NPM
-npm install @markdoc/markdoc
-# Using Yarn
-yarn add @markdoc/markdoc
-# Using PNPM
-pnpm add @markdoc/markdoc
+const entry = await getEntryBySlug('docs', 'why-markdoc');
+const { Content } = await entry.render();
+---
+
+<!--Pass the `abTest` param as a variable-->
+<Content abTestGroup={Astro.params.abTestGroup} />
```
-Now, you can define Markdoc configuration options using `Markdock.transform()`.
+Now, `abTestGroup` is available as a variable in `docs/why-markdoc.mdoc`:
-This example defines an `abTestGroup` Markdoc variable based on an SSR param, transforming the raw entry `body`. The result is rendered using the `Renderer` component provided by `@astrojs/markdoc`:
+```md
+{% if $abTestGroup === 'image-optimization-lover' %}
-```astro
----
-import Markdoc from '@markdoc/markdoc';
-import { Renderer } from '@astrojs/markdoc/components';
-import { getEntryBySlug } from 'astro:content';
+Let me tell you about image optimization...
-const { body } = await getEntryBySlug('docs', 'with-ab-test');
-const ast = Markdoc.parse(body);
-const content = Markdoc.transform({
- variables: { abTestGroup: Astro.params.abTestGroup },
-}, ast);
----
+{% /if %}
+```
-<Renderer {content} components={{ /* same `components` prop used by the `Content` component */ }} />
+To make a variable global to all Markdoc files, you can use the `variables` attribute from your `markdoc.config.mjs|ts`:
+
+```js
+import { defineMarkdocConfig } from '@astrojs/markdoc/config';
+
+export default defineMarkdocConfig({
+ variables: {
+ environment: process.env.IS_PROD ? 'prod' : 'dev',
+ }
+})
```
## Examples
@@ -360,3 +322,5 @@ See [CHANGELOG.md](https://github.com/withastro/astro/tree/main/packages/integra
[markdoc-tags]: https://markdoc.dev/docs/tags
[markdoc-nodes]: https://markdoc.dev/docs/nodes
+
+[markdoc-variables]: https://markdoc.dev/docs/variables