惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
SegmentFault 最新的问题
Google DeepMind News
Google DeepMind News
G
Google Developers Blog
Martin Fowler
Martin Fowler
MongoDB | Blog
MongoDB | Blog
月光博客
月光博客
Jina AI
Jina AI
宝玉的分享
宝玉的分享
人人都是产品经理
人人都是产品经理
D
DataBreaches.Net
V
V2EX
WordPress大学
WordPress大学
T
The Blog of Author Tim Ferriss
Last Week in AI
Last Week in AI
B
Blog
博客园 - 叶小钗
小众软件
小众软件
Stack Overflow Blog
Stack Overflow Blog
P
Proofpoint News Feed
A
About on SuperTechFans
J
Java Code Geeks
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog

CSS-Tricks

Let’s Use the Emergent CSS random() Function in all the Browsers | CSS-Tricks What’s !important #18: <geolocation>, Syntax ::highlight()ing, named-feature(), and More | CSS-Tricks Creating Web Widgets Using the Document Picture-in-Picture API | CSS-Tricks animation-trigger | CSS-Tricks MicroLighter: Syntax Highlighter | CSS-Tricks WordPress PHP-Only Block Registration | CSS-Tricks Resolved: CSS Class Prefix Selector | CSS-Tricks CSS Navigation Matching, Early Days | CSS-Tricks WordPress.com Student Plan | CSS-Tricks Dark mode toggles: two states are enough | CSS-Tricks What’s !important #17: Custom Highlight API, CSS Navigation Matching, Fixing text-stroke, and More | CSS-Tricks Blocked aria-hidden: The Warning is Right, and Every Fix You've Found is Wrong | CSS-Tricks Animating CSS border-image | CSS-Tricks SmashingConf Freiburg 2026, September 7-10 | CSS-Tricks Using and Styling the Dialog Element | CSS-Tricks 2026 State of CSS, Devs Surveys | CSS-Tricks Gap Decorations Are Now Available, Here’s What’s New | CSS-Tricks What’s !important #16: sibling-index() Animations, Use Cases for the infinity Keyword, Container Stuck Queries, and More | CSS-Tricks writing-mode | CSS-Tricks pointer-events | CSS-Tricks What’s !important #15: Boundary-aware CSS, Time-based CSS, Full-bleed CSS, and More | CSS-Tricks Get Ready For the Powerful CSS border-shape Property! | CSS-Tricks What’s !important #14: Gap Decorations, random(), <select> field sizing, and More | CSS-Tricks The Shifting Line Between CSS States and JavaScript Events | CSS-Tricks translateZ() | CSS-Tricks translateY() | CSS-Tricks translateX() | CSS-Tricks translate() | CSS-Tricks Using Scroll-Driven Animations for Opposing Scroll Directions | CSS-Tricks A First Look at Scroll-Triggered Animations | CSS-Tricks
Astro Markdown Component Utility for Any Framework | CSS-...
Zell Liew · 2026-06-01 · via CSS-Tricks

In the previous article, I spoke about the why and how to use a Markdown component in Astro.

Here, we’re going to expand on that and help you use Markdown everywhere — regardless of the framework you use. So, this works for React, Vue, and Svelte.

The entire process hinges on the Markdown utility I’ve built for Splendid Labz.

Why This Utility?

I hit a snag when using most Markdown libraries. I naturally write Markdown content like this:

<div>
  <div>
    <!-- prettier-ignore -->
    <Markdown>
      This is a paragraph

      This is a second paragraph
    </Markdown>
  </div>
</div>

But since most markdown libraries don’t account for whitespace indentation, they create an output with <pre> and <code> tags.

This is because Markdown treats the indentation beyond four spaces as a code block:

<div>
  <div>
    <pre><code>  This is a paragraph

      This is a second paragraph
    </code></pre>
  </div>
</div>

So you’re forced to strip all indentation and write it like this instead:

<div>
  <div>
    <!-- prettier-ignore -->
    <Markdown>
  This is a paragraph

  This is a second paragraph
    </Markdown>
  </div>
</div>

That’s hard to read and annoying to maintain.

My Markdown utility handles this whitespace issue and generates the correct HTML regardless of how your code is indented:

<div>
  <div>
    <p>This is a paragraph</p>
    <p>This is a second paragraph</p>
  </div>
</div>

Using This in Your Framework

It’s easy. You have to pass the Markdown text into the utility. If inline is true, then markdown will return an output without paragraph tags.

Here’s an example with Astro.

---
import { markdown } from '@splendidlabz/utils'
const { inline = false, content } = Astro.props
const slotContent = await Astro.slots.render('default')

// Process content
const html = markdown(content || slotContent, { inline })
---

<Fragment set:html={html} />

You can then use it like this:

<Markdown>
   <!-- Your content here -->
</Markdown>

Here’s another example for Svelte.

Svelte cannot read dynamic content from slots, so we can only pass it through a prop.

<script>
  import { markdown } from '@splendidlabz/utils'
  const { content, inline = false } = $props()
  const html = markdown(content, { inline })
</script>

<!-- eslint-disable-next-line svelte/no-at-html-tags -->
{@html html}

And you can use it like this:

<Markdown content=`
  ### This is a header

  This is a paragraph
`/>

It’s rather simple to build the same for React and Vue so I’d leave that up to you.

Taking it Further

I’ve been building for the web — long enough to experience the frustration of doing the same things over and over again.

So I consolidated everything I use into a few simple libraries — like Splendid Utils, and a few others for layouts, Astro and Svelte components.

I write about all of them on my blog. Come by if you’re interested in better DX as you build your sites and apps!