You may have felt limited at times if you've been writing blogs in plain Markdown. I mean, Markdown is great and all, but sometimes you need more than just headings and paragraphs, don't you? That's where shortcodes come in, and believe me, they make a big difference.
Today, I'm going to walk you through how to use shortcodes in your blog posts, and I'll be using examples from two awesome open source projects:
What is cool? Both projects have the same shortcodes, but they are set up differently for each framework. So, no matter if you're on team Astro or team Next.js, you're good to go!
Shortcodes are like small building pieces that you may add to your blog posts. You don't have to write complicated HTML or JavaScript every time you want a button or an accordion. Instead, you can just use a basic component tag. It's like having a toolbox full of ready-to-use UI components.
Instead of writing a lot of HTML for a beautiful button, you could just write:
<Button label="Click Me" link="/somewhere" style="solid" />
And bang! You have a button that looks great and works well. No trouble, no mess.
Let's discuss about MDX before we get into the shortcodes. You can use React components right inside your markdown files, which is like Markdown on steroids. That's pretty cool, right?
You're lucky if you use Astro (or Astroplate). There is built-in support for MDX. In your content directory, just make files with the .mdx extension:
src/
content/
blog/
my-awesome-post.mdx
That's all. Really.
If you use Next.js or Nextplate, MDX support is already set up for you. The project uses next-mdx-remote to show MDX material. If you're starting from scratch, you'll need:
npm install next-mdx-remote remark-gfm
The Nextplate boilerplate already has this set up in the MDXContent component, which is in charge of rendering markdown/MDX with shortcode components. You don't need to set up anything else in next.config.js for MDX!
The MDXContent component in Nextplate makes shortcodes available in all of your blog posts automatically. This is how it works:
Project Structure:
src/
layouts/
shortcodes/
Button.tsx
Notice.tsx
Accordion.tsx
Tabs.tsx
Tab.tsx
Youtube.tsx
Video.tsx
all.tsx # Exports all shortcodes
helpers/
MDXContent.tsx # Renders MDX with shortcodes
content/
blog/
*.md # Your blog posts (use .md extension)
Key Configuration Files:
next-mdx-remote with remark-gfm pluginYou don't need to import anything to use the MDXContent component because it automatically adds all shortcodes to your markdown files.
Okay, let's get to the exciting part! These are the shortcodes I use all the time in my blog posts. I'll show you how each one works with real examples.
Let's begin with something easy: buttons. They are great for CTAs, download links, or just making your links stand out. This is what they look like:
Code:
<Button label="Primary Button" link="#" style="solid" />
<Button label="Outline Button" link="#" style="outline" />
Props:
label: The text displayed on the buttonlink: URL or path to navigate tostyle: Either "solid" or "outline"rel: SEO relationship (optional, defaults to "nofollow")You know those bright callout boxes that are in documentation? Yes, those. They are quite helpful for drawing attention to essential things. There are four flavors:
Code:
<Notice type="note">Your content here</Notice>
<Notice type="tip">Your content here</Notice>
<Notice type="info">Your content here</Notice>
<Notice type="warning">Your content here</Notice>
For FAQs and extensive explanations, I always use accordions. They maintain your page neat and tidy while yet giving you all the information. Click to make it bigger, then click again to make it smaller. Simple as that:
Code:
<Accordion title="Your Question Here">
Your answer content here - can include markdown formatting!
</Accordion>
For Astro users: The client:load directive informs Astro to hydrate components when the site loads. In Nextplate (Next.js), this directive is not used—components are automatically interactive.
When you want to demonstrate the same item in different ways, like code examples for different frameworks (hint hint, Astro vs. Next.js), tabs are great. This is how they work:
Code:
<Tabs>
<Tab name="Tab 1">Content for first tab</Tab>
<Tab name="Tab 2">Content for second tab</Tab>
</Tabs>
Want to embed a YouTube video? Super easy:
Code:
<Youtube id="C0DPdy98e4c" title="Play:Youtube" />
Just grab the video ID from the YouTube URL (you know, the part after v=).
Got your own videos? No problem:
Code:
<Video width="100%" src="path/to/your/video.mp4" />
Of course, you've still got all your regular Markdown superpowers. Here's a quick refresher:
Use # for headings (H1 through H6):
# Heading 1
## Heading 2
### Heading 3
**text***text*~~text~~Inline code with backticksOrdered lists:
Unordered lists:
To highlight syntax, use three backticks with a language name:
function greet(name) {
console.log(`Hello, ${name}!`);
}
def greet(name):
print(f"Hello, {name}!")
Use the
>sign to make nice blockquotes. Great for making statements, testimonials, or key callouts stand out.
Create structured data with markdown tables:
| Feature | Astro | Next.js |
|---|---|---|
| MDX Support | ✅ Built-in | ✅ Via Plugin |
| Performance | ⚡ Excellent | ⚡ Excellent |
| Learning Curve | 📚 Easy | 📚 Moderate |
Code:
| Feature | Astro | Next.js |
| : ------------- | : ----------: | ------------: |
| MDX Support | ✅ Built -in | ✅ Via Plugin |
| Performance | ⚡ Excellent | ⚡ Excellent |
| Learning Curve | 📚 Easy | 📚 Moderate |
Once you get comfortable with these shortcodes, you might want to create your own. It's not that hard, really! Here's how to make the Button and Notice components:
Here's how the Button component is actually implemented in Nextplate:
import Link from "next/link";
const Button = ({
label,
link,
style,
rel,
}: {
label: string;
link: string;
style?: string;
rel?: string;
}) => {
return (
<Link
href={link}
target="_blank"
rel={`noopener noreferrer ${
rel ? (rel === "follow" ? "" : rel) : "nofollow"
}`}
className={`btn mb-4 me-4 no-underline hover:text-white dark:hover:text-black ${
style === "outline" ? "btn-outline-primary" : "btn-primary"
}`}
>
{label}
</Link>
);
};
export default Button;
Key differences from basic implementation:
Link component for optimized navigationdark:hover:text-blackThe Notice component in Nextplate includes custom SVG icons for each type:
import { humanize } from "@/lib/utils/text-converter";
import React from "react";
function Notice({
type,
children,
}: {
type: string;
children: React.ReactNode;
}) {
return (
<div className={`notice ${type}`}>
<div className="notice-head">
{/* SVG icons for tip, info, warning, and note types */}
{type === "tip" ? (
<svg width="20" height="20" viewBox="0 0 24 24" fill="none">
{/* Checkmark icon for tips */}
</svg>
) : type === "info" ? (
<svg width="20" height="20" viewBox="0 0 18 20" fill="none">
{/* Info icon */}
</svg>
) : type === "warning" ? (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
{/* Warning X icon */}
</svg>
) : (
<svg width="20" height="20" viewBox="0 0 20 20" fill="none">
{/* Note icon */}
</svg>
)}
<p className="my-0 ml-1.5">{humanize(type)}</p>
</div>
<div className="notice-body">{children}</div>
</div>
);
}
export default Notice;
Note: The actual component includes full SVG paths for each icon type. It also uses the humanize utility to format the type name.
Here are some things I wish someone had told me when I started using shortcodes!
client:load only when you really need immediate interactivity. For stuff below the fold, client:visible is your friend.Depending on whether you're using Astro or Next.js, there are a few framework-specific things worth knowing:
client:load for interactive components that need immediate interactivityclient:visible for components that can wait until they're in viewportclient:idle for lower-priority interactive componentsI understand that plain Markdown is easy and that's great. But occasionally your blog postings need a little more power. Shortcodes do just that. These components make your material much more interesting, whether you're using Astroplate for a quick Astro experience or Nextplate for the Next.js ecosystem.
Begin with little steps! Start by learning 2–3 shortcodes, and then add more as you get more comfortable.
And the best part is that what I've shown you today is only the tip of the iceberg. You may make custom components for just about anything, like image galleries, comparison tables, interactive demos, and more. There are no limits!
Happy blogging! 🚀