visit
You’ve probably seen many websites using cool bullet points instead of plain old-boring ones. How do they do it? Is there an effective and simple way to create fancy bullets while writing really simple code?
I'm going to assume you know how to use Astro and you know how to integrate MDX into Astro. If you don't, don't worry. Just follow through and you should get a basic idea of how things work, then go figure out how to use Astro and MDX.
They are:
<List>
component that takes in your bullets in the <slot>
content.<List>
component.
---
const { bullet } = Astro.props
---
<ul class='List'>
{
listItems.map(item => (
<li>
<!-- Your SVG here -->
<Fragment set:html={item.innerHTML} />
</li>
))
}
</ul>
The cool thing about this is you can add extra properties like fill
, stroke
, and all sorts of things to change the SVG so it renders with enough uniqueness.
Here are some examples where I changed the SVG fill
for .
I'm going to show you how to build a simple version that lets you insert an SVG you want. We won't be going through the advanced stuff like adding fill
and stroke
and other conditions though!
Astro lets you get the contents of a <slot>
element inside your component.
You can get this content by calling a render
function. You'll see a string
that contains the HTML which will be created.
---
const html = await Astro.slots.render('default')
console.log(html)
---
Next, this is where the magic happens
You can parse this HTML string and get the list items — just like doing a standard document.querySelectorAll
with JavaScript.
There are many parsers you can use here. The one I've chosen to use for my projects is node-html-parser
. (Because it's fast).
---
import { parse } from 'node-html-parser'
const html = await Astro.slots.render('default')
const root = parse(html)
---
After parsing the HTML, you can grab the list items by using querySelectorAll
.
---
// ...
const listItems = root.querySelectorAll('li')
---
---
// ...
---
<ul class='List'>
{
listItems.map(item => (
<li>
<!-- Your SVG goes here -->
<Fragment set:html={item.innerHTML} />
</li>
))
}
</ul>
If you want to switch between different types of list items, you can ask the user to pass in a bullet
property. Then, you inline a different SVG depending on the bullet
value.
---
const { bullet } = Astro.props
// ...
---
<ul class='List'>
{
listItems.map(item => (
<li>
{ bullet === 'green-check' && <svg> ... </svg> }
{ bullet === 'red-cross' && <svg> ... </svg> }
{ bullet === 'star' && <svg> ... </svg> }
<Fragment set:html={item.innerHTML} />
</li>
))
}
</ul>
---
import SVG from './SVG.astro'
const { bullet } = Astro.props
// ...
---
<ul class='List'>
{
listItems.map(item => (
<li>
<SVG name={bullet} />
<Fragment set:html={item.innerHTML} />
</li>
))
}
</ul>
---
// SVG component
const { name } = Astro.props
---
{ bullet === 'green-check' && <svg> ... </svg> }
{ bullet === 'red-cross' && <svg> ... </svg> }
{ bullet === 'star' && <svg> ... </svg> }
svgs
foldername
into the <SVG>
component
If you'd like to find out how I build the SVG
component, along with how I use Astro and Svelte, scroll down and leave your email in the form below. I'd love to share more with you!
What's pretty cool about this approach is you can even use Astro to validate the type of bullet
you pass into <List>
, the fill
, the stroke
, and other properties you want.
const validators = {
bullet: [{
type: 'star',
fill: ['yellow', 'green', 'red', 'blue'],
stroke: ['black', 'transparent'],
}]
}
validate({ ...Astro.props })
function validate () {
// Check props against validators
}
Feel free to visit that if you want to have these articles delivered to your email first-hand whenever they're released! 🙂.