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-remoteThe 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.
The Heading component renders all h1 through h6 elements. It receives the following props:
as, theh1throughh6taghref, a pre-generated, slugifiedhreftext, 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>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 toplaintext)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>The CodeSpan component allows you customize the rendering of inline code spans. It receives the following props:
code, the value of the code span
A sample CodeSpan component might look something like this.
---
const { code } = Astro.props;
---
<code set:text={code} />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() ] }} />