Render remote HTML or Markdown content in Astro with full control over the output
MIT License
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() ] }} />