Search code examples
javascripthtmlmarkdownastrojs

What's the best way to pass markdown to an Astro component as a prop


What I'm trying to do

A simple way to render the content of a markdown file when it's passed as a string to another component using .compiledContent (or even using .rawContnent)? Or even a better way than this as obviously usually in Astro we can use the <Content /> Component, but from my knowledge, I can't pass a component or this functionality to another component without using a <slot /> in the parent component.

I have some JS for the parent component and using a <slot/> instead of passing the props to the component would change things, so hopefully looking for a solution with using this.

My setup

  • Data stored in /src/data/experience as markdown files with a year and a description formatted as markdown in the content section of each file
  • A component called Tabs.astro which takes props of headings and contents which are both lists of strings
  • A page /src/pages/experience.astro with the Tabs component in it which is displaying this data

I take the below code to get the data from the markdown files and pass the years and descriptions to the Tab component.

experience.astro

---
import Tabs from "../components/Tabs.astro";

const jobs = await Astro.glob("../data/experience/*.md");
const years = jobs.map((job) => job.frontmatter.year);
const descriptions = jobs.map((job) => job.compiledContent);
---
<!-- My component taking the data to be rendered -->
<Tabs headings={years} contents={descriptions} />

Tabs.astro

And the component renders the info like so

<!-- Tabs -->
<div class="tabs">
  <ul class="tabs-header">
    {
      headings.map((heading) => (
        <li>{heading}</li>
      ))
    }
  </ul>
  <ul class="tabs-content">
    {contents.map((content) => <li class="tab">{content}</li>)}
  </ul>
</div>

My current solution

At the moment using .compiledContent gets me the correct HTML, however it is all in a string so the HTML doesn't actually render.

What I'm looking for

  • Is there a native way in Astro to pass markdown as a prop to a component?
  • If not is there a manual and recommended way in Astro to convert a markdown string and sanitise it to protect against XSS attacks? (if this is a risk in Astro when rendered statically?)
  • If not what are your most recommended ways to render markdown and sanitise it in JS?

Thanks so much for your time and help! I'm loving using Astro

p.s Also happy to concede and just use a <slot/> in my component if needed... ;)


Solution

  • Astro has a set:html directive you can use in combination with a Fragment like this

    <Fragment set:html={post.compiledContent()}/>