Render remote HTML or Markdown content in Astro with full control over the output.
Powered by ultrahtml
and marked
.
npm install astro-remote
pnpm install astro-remote
yarn install astro-remote
The most basic function of astro-remote
is to convert a string of HTML or Markdown to HTML. Use the Markup
and Markdown
components depending on your input.
---
import { Markup, Markdown } from 'astro-remote';
const { html, markdown } = await fetch('http://my-site.com/api/v1/post').then(res => res.json());
---
<Markup content={html} />
<Markdown content={markdown} />
By default, all HTML content will be sanitized with sensible defaults (script
blocks are dropped). This can be controlled using the SanitizeOptions
available in ultrahtml
. Set to false
to disable sanitization.
---
import { Markup } from 'astro-remote';
const content = await fetch('http://my-site.com/api/v1/post').then(res => res.text());
---
<!-- Disallow `head` and `style` attributes, and standard formatting from host website -->
<Markup
content={content}
sanitize={{
dropElements: ["head","style"],
blockElements: ["html", "body", "div"],
}}
/>
Both Markup
and Markdown
allow full control over the rendering of output. The components
option allows you to replace a standard HTML element with a custom component.
---
import { Markdown, Markup } from 'astro-remote';
import Title from '../components/Title.astro';
const content = await fetch('http://my-site.com/api/v1/post').then(res => res.text());
---
<!-- Render <h1> as custom <Title> component -->
<Markup content={content} components={{ h1: Title }} />
<Markdown content={content} components={{ h1: Title }} />
In addition to built-in HTML Elements, Markdown
also supports a few custom components for convenience.
<Heading />
The Heading
component renders all h1
through h6
elements. It receives the following props:
as
, the h1
through h6
taghref
, a pre-generated, slugified href
text
, the text content of the children (for generating a custom slug)---
import { Markdown } from 'astro-remote';
import Heading from '../components/Heading.astro';
const content = await fetch('http://my-site.com/api/v1/post').then(res => res.text());
---
<!-- Render all <h1> through <h6> using custom <Heading> component -->
<Markdown content={content} components={{ Heading }} />
A sample Heading
component might look something like this.
---
const { as: Component, href } = Astro.props;
---
<Component><a href={href}><slot /></a></Component>
<CodeBlock />
The CodeBlock
component allows you customize the rendering of code blocks. It receives the following props:
lang
, the language specified after the three backticks (defaults to plaintext
)code
, the raw code to be highlighted. Be sure to escape the output!...props
, any other attributes passed to the three backticks. These should follow HTML attribute format (name="value"
)A sample CodeBlock
component might look something like this.
---
const { lang, code, ...props } = Astro.props;
const highlighted = await highlight(code, { lang });
---
<pre class={`language-${lang}`}><code set:html={highlighted} /></pre>
<CodeSpan />
The CodeSpan
component allows you customize the rendering of inline code spans. It receives the following props:
code
, the value of the code spanA sample CodeSpan
component might look something like this.
---
const { code } = Astro.props;
---
<code set:text={code} />
<Note />
The Note
component allows you customize the rendering of GitHub-style notes and warnings. It receives the following props:
type
, either "note"
or "warning"
To use a Note
component in Markdown, use the following syntax:
> **Note**
> Some tip here!
> **Warning**
> Some warning here!
If you'd like to allow custom components in Markdown, you can do so using a combination of the sanitize
and components
options. By default, sanitization removes components.
Given the following markdown source:
# Hello world!
<MyCustomComponent a="1" b="2" c="3">It works!</MyCustomComponent>
---
import { Markdown } from 'astro-remote';
import MyCustomComponent from '../components/MyCustomComponent.astro';
const content = await fetch('http://my-site.com/api/v1/post').then(res => res.text());
---
<Markdown content={content} sanitize={{ allowComponents: true }} components={{ MyCustomComponent }} />
If you'd like to extend the underlying Marked behavior, the marked
prop accepts extensions
.
---
import { Markdown } from 'astro-remote';
import markedAlert from 'marked-alert'
const content = await fetch('http://my-site.com/api/v1/post').then(res => res.text());
---
<Markdown content={content} marked={{ extensions: [ markedAlert() ] }} />