logo

Allow/Deny Filtering

@humanspeak/svelte-markdown provides a set of utility functions for controlling which elements are rendered. You can allowlist specific elements (blocking everything else), denylist specific elements (allowing everything else), or block all elements of a category.

There are two separate sets of functions: one for HTML tag renderers and one for markdown renderers.

HTML Tag Filtering

These functions return HtmlRenderers objects that you pass to renderers.html.

allowHtmlOnly(allowed)

Creates an HTML renderer map where only the specified tags use their default components. All other tags are replaced with UnsupportedHTML (which renders nothing).

<script>
    import SvelteMarkdown, { allowHtmlOnly } from '@humanspeak/svelte-markdown'

    // Only allow these safe inline HTML tags
    const safeHtml = allowHtmlOnly(['strong', 'em', 'a', 'code', 'br'])
</script>

<SvelteMarkdown source={markdown} renderers={{ html: safeHtml }} />
<script>
    import SvelteMarkdown, { allowHtmlOnly } from '@humanspeak/svelte-markdown'

    // Only allow these safe inline HTML tags
    const safeHtml = allowHtmlOnly(['strong', 'em', 'a', 'code', 'br'])
</script>

<SvelteMarkdown source={markdown} renderers={{ html: safeHtml }} />

You can also provide custom components for specific tags using tuple syntax:

import { allowHtmlOnly } from '@humanspeak/svelte-markdown'
import CustomDiv from './CustomDiv.svelte'

// Allow <a> with its default renderer, and <div> with a custom component
const html = allowHtmlOnly(['a', ['div', CustomDiv]])
import { allowHtmlOnly } from '@humanspeak/svelte-markdown'
import CustomDiv from './CustomDiv.svelte'

// Allow <a> with its default renderer, and <div> with a custom component
const html = allowHtmlOnly(['a', ['div', CustomDiv]])

Signature:

function allowHtmlOnly(
    allowed: Array<HtmlKey | [HtmlKey, Component | null]>
): HtmlRenderers
function allowHtmlOnly(
    allowed: Array<HtmlKey | [HtmlKey, Component | null]>
): HtmlRenderers

excludeHtmlOnly(excluded, overrides?)

Creates an HTML renderer map where the specified tags are blocked (set to UnsupportedHTML). All other tags use their default components.

<script>
    import SvelteMarkdown, { excludeHtmlOnly } from '@humanspeak/svelte-markdown'

    // Block potentially dangerous tags, allow everything else
    const filteredHtml = excludeHtmlOnly(['iframe', 'form', 'input', 'script', 'embed'])
</script>

<SvelteMarkdown source={markdown} renderers={{ html: filteredHtml }} />
<script>
    import SvelteMarkdown, { excludeHtmlOnly } from '@humanspeak/svelte-markdown'

    // Block potentially dangerous tags, allow everything else
    const filteredHtml = excludeHtmlOnly(['iframe', 'form', 'input', 'script', 'embed'])
</script>

<SvelteMarkdown source={markdown} renderers={{ html: filteredHtml }} />

You can optionally override non-excluded tags with custom components:

import { excludeHtmlOnly } from '@humanspeak/svelte-markdown'
import CustomA from './CustomA.svelte'

// Block iframe, override <a> with custom component
const html = excludeHtmlOnly(['iframe'], [['a', CustomA]])
import { excludeHtmlOnly } from '@humanspeak/svelte-markdown'
import CustomA from './CustomA.svelte'

// Block iframe, override <a> with custom component
const html = excludeHtmlOnly(['iframe'], [['a', CustomA]])

Exclusions take precedence over overrides. If a tag appears in both the exclusion list and the overrides, it will be blocked.

Signature:

function excludeHtmlOnly(
    excluded: HtmlKey[],
    overrides?: Array<[HtmlKey, Component | null]>
): HtmlRenderers
function excludeHtmlOnly(
    excluded: HtmlKey[],
    overrides?: Array<[HtmlKey, Component | null]>
): HtmlRenderers

buildUnsupportedHTML()

Creates an HTML renderer map where every tag is set to UnsupportedHTML. This blocks all raw HTML rendering.

<script>
    import SvelteMarkdown, { buildUnsupportedHTML } from '@humanspeak/svelte-markdown'

    // Disable all raw HTML in markdown
    const noHtml = buildUnsupportedHTML()
</script>

<SvelteMarkdown source={markdown} renderers={{ html: noHtml }} />
<script>
    import SvelteMarkdown, { buildUnsupportedHTML } from '@humanspeak/svelte-markdown'

    // Disable all raw HTML in markdown
    const noHtml = buildUnsupportedHTML()
</script>

<SvelteMarkdown source={markdown} renderers={{ html: noHtml }} />

Signature:

function buildUnsupportedHTML(): HtmlRenderers
function buildUnsupportedHTML(): HtmlRenderers

Markdown Renderer Filtering

These functions return partial Renderers objects (excluding the html key) that you spread into or merge with the renderers prop.

allowRenderersOnly(allowed)

Creates a renderer map where only the specified markdown renderers use their default components. All other renderers are set to Unsupported (which renders nothing).

<script>
    import SvelteMarkdown, { allowRenderersOnly } from '@humanspeak/svelte-markdown'

    // Only allow paragraphs, text, links, and emphasis
    const minimal = allowRenderersOnly(['paragraph', 'text', 'link', 'em', 'strong'])
</script>

<SvelteMarkdown source={markdown} renderers={minimal} />
<script>
    import SvelteMarkdown, { allowRenderersOnly } from '@humanspeak/svelte-markdown'

    // Only allow paragraphs, text, links, and emphasis
    const minimal = allowRenderersOnly(['paragraph', 'text', 'link', 'em', 'strong'])
</script>

<SvelteMarkdown source={markdown} renderers={minimal} />

You can provide custom components using tuple syntax:

import { allowRenderersOnly } from '@humanspeak/svelte-markdown'
import CustomParagraph from './CustomParagraph.svelte'

const renderers = allowRenderersOnly([
    ['paragraph', CustomParagraph],
    'text',
    'link'
])
import { allowRenderersOnly } from '@humanspeak/svelte-markdown'
import CustomParagraph from './CustomParagraph.svelte'

const renderers = allowRenderersOnly([
    ['paragraph', CustomParagraph],
    'text',
    'link'
])

Signature:

function allowRenderersOnly(
    allowed: Array<RendererKey | [RendererKey, RendererComponent]>
): Omit<Renderers, 'html'>
function allowRenderersOnly(
    allowed: Array<RendererKey | [RendererKey, RendererComponent]>
): Omit<Renderers, 'html'>

excludeRenderersOnly(excluded, overrides?)

Creates a renderer map where the specified keys are set to Unsupported. All other keys use their defaults.

<script>
    import SvelteMarkdown, { excludeRenderersOnly } from '@humanspeak/svelte-markdown'

    // Disable images and code blocks
    const renderers = excludeRenderersOnly(['image', 'code'])
</script>

<SvelteMarkdown source={markdown} renderers={renderers} />
<script>
    import SvelteMarkdown, { excludeRenderersOnly } from '@humanspeak/svelte-markdown'

    // Disable images and code blocks
    const renderers = excludeRenderersOnly(['image', 'code'])
</script>

<SvelteMarkdown source={markdown} renderers={renderers} />

With custom overrides on non-excluded keys:

import { excludeRenderersOnly } from '@humanspeak/svelte-markdown'
import CustomHeading from './CustomHeading.svelte'

// Exclude images, override headings with a custom component
const renderers = excludeRenderersOnly(
    ['image'],
    [['heading', CustomHeading]]
)
import { excludeRenderersOnly } from '@humanspeak/svelte-markdown'
import CustomHeading from './CustomHeading.svelte'

// Exclude images, override headings with a custom component
const renderers = excludeRenderersOnly(
    ['image'],
    [['heading', CustomHeading]]
)

Signature:

function excludeRenderersOnly(
    excluded: RendererKey[],
    overrides?: Array<[RendererKey, RendererComponent]>
): Omit<Renderers, 'html'>
function excludeRenderersOnly(
    excluded: RendererKey[],
    overrides?: Array<[RendererKey, RendererComponent]>
): Omit<Renderers, 'html'>

buildUnsupportedRenderers()

Creates a renderer map where every markdown renderer is set to Unsupported. This blocks all markdown rendering (but does not affect HTML tag renderers).

import { buildUnsupportedRenderers } from '@humanspeak/svelte-markdown'

const renderers = {
    ...buildUnsupportedRenderers(),
    // Re-enable only paragraph and text
    paragraph: defaultRenderers.paragraph,
    text: defaultRenderers.text
}
import { buildUnsupportedRenderers } from '@humanspeak/svelte-markdown'

const renderers = {
    ...buildUnsupportedRenderers(),
    // Re-enable only paragraph and text
    paragraph: defaultRenderers.paragraph,
    text: defaultRenderers.text
}

Signature:

function buildUnsupportedRenderers(): Omit<Renderers, 'html'>
function buildUnsupportedRenderers(): Omit<Renderers, 'html'>

Combining HTML and Markdown Filtering

You can combine both HTML and markdown filtering in a single configuration:

<script>
    import SvelteMarkdown, {
        allowHtmlOnly,
        excludeRenderersOnly
    } from '@humanspeak/svelte-markdown'

    const renderers = {
        // Disable image and code renderers
        ...excludeRenderersOnly(['image', 'code']),
        // Only allow safe HTML tags
        html: allowHtmlOnly(['strong', 'em', 'a'])
    }
</script>

<SvelteMarkdown source={markdown} {renderers} />
<script>
    import SvelteMarkdown, {
        allowHtmlOnly,
        excludeRenderersOnly
    } from '@humanspeak/svelte-markdown'

    const renderers = {
        // Disable image and code renderers
        ...excludeRenderersOnly(['image', 'code']),
        // Only allow safe HTML tags
        html: allowHtmlOnly(['strong', 'em', 'a'])
    }
</script>

<SvelteMarkdown source={markdown} {renderers} />

Available Keys

Use the exported key arrays to see all valid keys:

import { rendererKeys, htmlRendererKeys } from '@humanspeak/svelte-markdown'

console.log(rendererKeys)
// ['heading', 'paragraph', 'text', 'image', 'link', ...]

console.log(htmlRendererKeys)
// ['a', 'abbr', 'address', 'article', 'aside', ...]
import { rendererKeys, htmlRendererKeys } from '@humanspeak/svelte-markdown'

console.log(rendererKeys)
// ['heading', 'paragraph', 'text', 'image', 'link', ...]

console.log(htmlRendererKeys)
// ['a', 'abbr', 'address', 'article', 'aside', ...]

Related