{"id":28247,"date":"2022-03-23T22:24:38","date_gmt":"2022-03-23T22:24:38","guid":{"rendered":"http:\/\/Embed-media-components-using-MDX-and-SvelteKit"},"modified":"2022-03-23T22:24:38","modified_gmt":"2022-03-23T22:24:38","slug":"embed-media-components-using-mdx-and-sveltekit","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/","title":{"rendered":"Embed Media Components using MDX"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>In this article, you\u2019ll learn how to effectively use this new authoring media to embed rich media components into your SvelteKit site while keeping the simplicity of markdown format for writing your content.<\/p>\n<p>To accomplish this goal, through the article you\u2019ll learn:<\/p>\n<ul>\n<li>What is MDX and MDsveX<\/li>\n<li>How to set up an SvelteKit app<\/li>\n<li>How yo create your own media components to use in the markdown<\/li>\n<\/ul>\n<p>At the end, you\u2019ll be able to add custom media elements to your markdown files like:<\/p>\n<ul>\n<li>Embeded youtube videos<\/li>\n<li>CodeSandbox<\/li>\n<li>Twitter items<\/li>\n<li>Snack<\/li>\n<li>Custom components<\/li>\n<\/ul>\n<blockquote>\n<p>You can find An example of what MDsveX can achieve directly <a href=\"https:\/\/mdsvex.com\/playground\">in the playground<\/a><\/p>\n<\/blockquote>\n<p>You can find the result of this tutorial in <a href=\"https:\/\/github.com\/matiasfha\/mdsvex-sveltekit-demo\">this github repository<\/a> or play around in the following sandbox.<\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/cranky-buck-sfmip?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=%2Fsrc%2Froutes%2Fapi%2Fblog%2Findex.json.ts&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"Embed media components using MDX and SvelteKit\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><h2>What is MDX and MDsveX?<\/h2>\n<p><a href=\"https:\/\/github.com\/mdx-js\/mdx\">MDX<\/a> is a combination of Markdown and JSX<\/p>\n<p>An authoring format that allows the writer to write the well-known markdown format but also introduce dynamic content by using the power of JSX components<\/p>\n<p>It takes a string of markdown and transforms it to a Javascript string (React or Svelte)<\/p>\n<p>It basically allows you to consider a regular markdown file as a component opening the door to add working code into the markdown file.<\/p>\n<p>The MDX parser will insert your custom components into the parsed result, you can even replace base elements like paragraphs, headings, and others HTML elements.<\/p>\n<p>This allows you to have a better authoring experience and to create all of your content using your lovely markdown, but also empowering your content with rich media elements like interactive charts, alerts, or embed external content like youtube videos, images, etc.<\/p>\n<p><a href=\"https:\/\/mdsvex.com\/\">MDsveX<\/a> is the answer from <a href=\"https:\/\/svelte.dev\">Svelte <\/a>world to the same need of authoring rich media content using a powerful media like markdown. This is a markdown pre-processor for Svelte components, this preprocessor allows you to use Svelte components in your markdown, or vice versa. It supports all Svelte syntax and almost all Markdown<\/p>\n<p>It uses  <a href=\"https:\/\/remark.js.org\/\">remark<\/a> and <a href=\"https:\/\/github.com\/rehypejs\/rehype\">rehype<\/a> so you can use several plugins to enhance your experience.<\/p>\n<h2>Get up running with SvelteKit<\/h2>\n<p>SvelteKit is a framework on top of Svelte, at the time of this writing is still in beta and under active development. This framework can be seen as the Next.js version for Svelte, full of features and opinions about routing, layout, state management, API endpoints, SSG, and SSR.<\/p>\n<p>SvelteKit allows you to build full-fledged applications with an outstanding developer experience and an incredibly fast user experience coming from the Svelte philosophy.<\/p>\n<p>One way to try Sveltekit is by building a website to share content like a blog or articles site, this is the easier way to accomplish two things:<\/p>\n<ul>\n<li>Get to know SvelteKit<\/li>\n<li>Integrate MDsveX to the mix.<\/li>\n<\/ul>\n<p>Let\u2019s start by setting up your SvelteKit powered site<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">npm<\/span> <span class=\"hljs-selector-tag\">init<\/span> <span class=\"hljs-selector-tag\">svelte<\/span><span class=\"hljs-keyword\">@next<\/span> my-site\ncd my-site\nnpm install\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<blockquote>\n<p>Add an image here<\/p>\n<\/blockquote>\n<p>Then to add some style will add tailwind<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npx svelte-add tailwindcss\n<\/code><\/span><\/pre>\n<p>and similar to add MDsveX<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">npx svelte-add mdsvex\n<\/code><\/span><\/pre>\n<p>With that, you\u2019ll have the base setup for a SvelteKit site that will use Tailwindcss and MDsveX<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\">\u251c\u2500\u2500 <span class=\"hljs-selector-tag\">README<\/span><span class=\"hljs-selector-class\">.md<\/span>\n\u251c\u2500\u2500 <span class=\"hljs-selector-tag\">mdsvex<\/span><span class=\"hljs-selector-class\">.config<\/span><span class=\"hljs-selector-class\">.cjs<\/span>\n\u251c\u2500\u2500 <span class=\"hljs-selector-tag\">mdsvex<\/span><span class=\"hljs-selector-class\">.config<\/span><span class=\"hljs-selector-class\">.js<\/span>\n\u251c\u2500\u2500 <span class=\"hljs-selector-tag\">package<\/span><span class=\"hljs-selector-class\">.json<\/span>\n\u251c\u2500\u2500 <span class=\"hljs-selector-tag\">postcss<\/span><span class=\"hljs-selector-class\">.config<\/span><span class=\"hljs-selector-class\">.cjs<\/span>\n\u251c\u2500\u2500 <span class=\"hljs-selector-tag\">src<\/span>\n\u2502   \u251c\u2500\u2500 <span class=\"hljs-selector-tag\">app<\/span><span class=\"hljs-selector-class\">.html<\/span>\n\u2502   \u251c\u2500\u2500 <span class=\"hljs-selector-tag\">app<\/span><span class=\"hljs-selector-class\">.postcss<\/span>\n\u2502   \u251c\u2500\u2500 <span class=\"hljs-selector-tag\">global<\/span><span class=\"hljs-selector-class\">.d<\/span><span class=\"hljs-selector-class\">.ts<\/span>\n\u2502   \u251c\u2500\u2500 <span class=\"hljs-selector-tag\">lib<\/span>\n\u2502   \u2514\u2500\u2500 <span class=\"hljs-selector-tag\">routes<\/span>\n\u2502       \u2514\u2500\u2500 <span class=\"hljs-selector-tag\">index<\/span><span class=\"hljs-selector-class\">.svelte<\/span>\n\u251c\u2500\u2500 <span class=\"hljs-selector-tag\">svelte<\/span><span class=\"hljs-selector-class\">.config<\/span><span class=\"hljs-selector-class\">.js<\/span>\n\u251c\u2500\u2500 <span class=\"hljs-selector-tag\">tailwind<\/span><span class=\"hljs-selector-class\">.config<\/span><span class=\"hljs-selector-class\">.cjs<\/span>\n\u2514\u2500\u2500 <span class=\"hljs-selector-tag\">tsconfig<\/span><span class=\"hljs-selector-class\">.json<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Let\u2019s say that you want to have a list of blog posts and you love markdown to write those<\/p>\n<p>Since SvelteKit uses a file-based routing system you can leverage this and quickly set up your markdown files (or .svx) inside <code>src\/routes<\/code> everything under that folder will be considered as a page.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\">\u251c\u2500\u2500 <span class=\"hljs-selector-tag\">src<\/span>\n\u2502   \u2514\u2500\u2500 <span class=\"hljs-selector-tag\">routes<\/span>\n\u2502       \u251c\u2500\u2500 <span class=\"hljs-selector-tag\">blog<\/span>\n\u2502       \u2502   \u2514\u2500\u2500 <span class=\"hljs-selector-tag\">my-first-post<\/span><span class=\"hljs-selector-class\">.svx<\/span>\n\u2502       \u2514\u2500\u2500 <span class=\"hljs-selector-tag\">index<\/span><span class=\"hljs-selector-class\">.svelte<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This means that there is a new page under <code>https:\/\/your-site.com\/blog\/my-first-post<\/code><\/p>\n<p>You can try this right away by running <code>npm run dev<\/code> and visiting  <code>http:\/\/localhost:3000\/blog\/my-first-post<\/code><\/p>\n<h2>Markdown Content<\/h2>\n<p>The markdown file will support frontmatter, this content will act as metadata variables that can be used by the svelte components.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">--- \ntitle: Svex up your markdown \ndescription: My first markdown content\nkeywords:\n - Keyword <span class=\"hljs-number\">1<\/span>\n - Keyword <span class=\"hljs-number\">2<\/span>\n--- \n\n<span class=\"hljs-comment\"># { title }<\/span>\n\nThis is more markdown **base content**\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>To enhance the experience further, mdsvex allow the use of custom layouts<\/p>\n<h3>Layouts<\/h3>\n<p>SvelteKit supports the concept of Layouts, this is a special component that can wrap every page under it, this is very useful to create shared elements that should be visible across every page.<\/p>\n<p>To create a layout component you just need to create a file named as <code>__layout.svelte<\/code><\/p>\n<p>Upon creation of your site code, there is a base layout component under <code>src\/routes\/__layout.svelte<\/code><\/p>\n<p>A similar concept exists for mdsvex files. There is a configuration option that allows you to provide a custom layout component that will wrap your mdsvex file like<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Layout<\/span> {<span class=\"hljs-attr\">...props<\/span>}&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">YourMarkdownContent<\/span> \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Layout<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This layout components will receive all the frontmatter data of your files as props<\/p>\n<p>To configure this layout you can update the <code>mdsvez.config.js<\/code> file and pass a <code>string<\/code> that represents the path to your layout component<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">mdsvex<\/span>({\n\t<span class=\"hljs-attribute\">layout<\/span>: <span class=\"hljs-built_in\">join<\/span>(__dirname, <span class=\"hljs-string\">'.\/src\/components\/PostLayout.svelte'<\/span>)\n})\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>There are cases where you have different markdown based pages with completely different content, in this cases would be useful to have different layouts for the content, that can be addressed by passing an object to the <code>layout<\/code> property where each key of the object is considered as the name of the layout.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"CSS\" data-shcb-language-slug=\"css\"><span><code class=\"hljs language-css shcb-wrap-lines\"><span class=\"hljs-selector-tag\">mdsvex<\/span>({\n\t<span class=\"hljs-attribute\">layout<\/span>: {\n\t\tblog: <span class=\"hljs-string\">\".\/path\/to\/blog\/layout.svelte\"<\/span>,\n\t\tarticle: <span class=\"hljs-string\">\".\/path\/to\/article\/layout.svelte\"<\/span>,\n\t\t_: <span class=\"hljs-string\">\".\/path\/to\/fallback\/layout.svelte\"<\/span> \/\/ Default layout\n\t}\n});\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">CSS<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">css<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>By using this configuration you can decide with the layout should be used to which file by declaring it in the frontmatter section of the file, but if that option is not present, MDsveX will try to pick the correct layout based on your folder structured.<\/p>\n<p>Let\u2019s create a layout for your current post files, just create a new folder and file under <code>src\/lib\/components\/PostLayout.svelte<\/code><\/p>\n<blockquote>\n<p>In this example, components are saved under the <code>lib<\/code> folder to make it easy to access them. SvelteKit <a href=\"https:\/\/kit.svelte.dev\/docs#modules-$lib\">comes with some default paths<\/a> as <code>$lib<\/code> that make reference to the <code>src\/lib<\/code> folder.<\/p>\n<\/blockquote>\n<p>This component can look something like this<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n\t<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">let<\/span> title;\n\t<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">let<\/span> description;\n\t<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">let<\/span> keywords;\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">svelte:head<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">title<\/span>&gt;<\/span>{title}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">title<\/span>&gt;<\/span>\n \t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"description\"<\/span> <span class=\"hljs-attr\">content<\/span>=<span class=\"hljs-string\">{description}<\/span> \/&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">meta<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"keywords\"<\/span> <span class=\"hljs-attr\">content<\/span>=<span class=\"hljs-string\">{keywords.join(<\/span>', ')} \/&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">svelte:head<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">article<\/span>  <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"w-full p-8\"<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">header<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>{title}<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">header<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">slot<\/span> \/&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">footer<\/span>&gt;<\/span>\n\t\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">\"\"<\/span>&gt;<\/span>Share this on Twitter<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">footer<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">article<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>at the very top, you can see a few variables exposed as props inside the script tag, the value for these props come directly from the markdown front matter.<\/p>\n<blockquote>\n<p>Check [this page under the svelte documentation](<a href=\"https:\/\/svelte.dev\/docs#script\">https:\/\/svelte.dev\/docs#script<\/a> <a href=\"https:\/\/svelte.dev\/docs#script\">https:\/\/svelte.dev\/docs#script<\/a>) to learn more about props<\/p>\n<\/blockquote>\n<p>Then, in the component code you can see a reference to <code>svelte:head<\/code>, this is a svelte element that makes it possible to manage the content of the <code>document.head<\/code>. By using it, all the content you add as a child of <code>svelte:head<\/code> gets inserted in the <code>&lt;head \/&gt;<\/code> of the current document. This way you can handle some of the SEO content for your article.<\/p>\n<p>Then, is the actual post layout that in this case consists just of a few HTML elements. You can see that this component reference the <code>title<\/code> prop to render the title. And use another svelte especial element <code>&lt;slot \/&gt;<\/code>. This is a way to define child components, meaning that the \u201cuser\u201d of this component can insert any element into this place. This slot is used by MDsveX to insert the parsed markdown content.<\/p>\n<p>This way you can control the way your markdown content is rendered, if you want to have more granular control over how the HTML elements inside the slot are created, then you can use what is known as <code>custom components<\/code>.<\/p>\n<h3>Custom components<\/h3>\n<p>Under MDsveX, custom components are a way to replace the elements that markdown would normally generate, for example, the example markdown content used here<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">--- \ntitle: Svex up your markdown \ndescription: My first markdown content\nkeywords:\n - Keyword <span class=\"hljs-number\">1<\/span>\n - Keyword <span class=\"hljs-number\">2<\/span>\n--- \n\n<span class=\"hljs-comment\"># { title }<\/span>\n\nThis is more markdown **base content**\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Will be compiled to<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1<\/span>&gt;<\/span>title<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">h1<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">p<\/span>&gt;<\/span>This is more markdown <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">strong<\/span>&gt;<\/span>base content<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">strong<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">p<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>By using custom components in your layout you can replace these elements by more complex constructions, like a custom blockquote section.<\/p>\n<p>Let\u2019s create the custom blockquote first, this is basically a blockquote element that, when hover, will show a tweet button.<\/p>\n<p>You can check the source code and demo of the component <a href=\"https:\/\/svelte.dev\/repl\/904383078c13496f9eab293bf04debce?version=3.42.4\">directly in svelte REPL<\/a><\/p>\n<p>Save this component under <code>src\/lib\/components\/Quote.svelte<\/code> and now, let\u2019s use it as a custom component.<\/p>\n<p>In your <code>PostLayout<\/code> component, add a new script tag. Custom components are defined in the \u201ccompilation\u201d step, so to be able to use them you need to import them inside a  <code>context=&quot;module&quot;<\/code> script and export it.<\/p>\n<p>The export of this custom component has to be a <strong>named export<\/strong> each named expoer must be named after the actual element you want to replace,<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">context<\/span>=<span class=\"hljs-string\">\"module\"<\/span>&gt;<\/span><span class=\"javascript\">\n    <span class=\"hljs-keyword\">import<\/span> blockquote <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'$lib\/components\/Quote.svelte'<\/span>\n\t<span class=\"hljs-keyword\">export<\/span> { blockquote }\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Now, after compilation, MDsveX will generate new content using your custom <code>Quote<\/code> component each time a <code>blockqote<\/code> is required.<\/p>\n<h1>Media elements<\/h1>\n<p>Now that the setup part is done, is time to harness the power of MDsveX by adding media elements to your markdown content.<\/p>\n<p>Let\u2019s start by adding some video content, for that, you\u2019ll create a new component under <code>src\/lib\/Youtube.svelte<\/code><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n\t<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">let<\/span> videoId\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span> <span class=\"hljs-attr\">class<\/span>=<span class=\"hljs-string\">\"video-container\"<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">iframe<\/span> <span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">\"Youtube video\"<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{<\/span>`<span class=\"hljs-attr\">https:<\/span>\/\/<span class=\"hljs-attr\">www.youtube.com<\/span>\/<span class=\"hljs-attr\">embed<\/span>\/${<span class=\"hljs-attr\">videoId<\/span>}`} <span class=\"hljs-attr\">frameborder<\/span>=<span class=\"hljs-string\">\"0\"<\/span> <span class=\"hljs-attr\">allow<\/span>=<span class=\"hljs-string\">\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\"<\/span> <span class=\"hljs-attr\">allowfullscreen<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">iframe<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span>&gt;<\/span><span class=\"css\">\n<span class=\"hljs-selector-class\">.video-container<\/span> {\n    <span class=\"hljs-attribute\">overflow<\/span>: hidden;\n    <span class=\"hljs-attribute\">position<\/span>: relative;\n    <span class=\"hljs-attribute\">width<\/span>:<span class=\"hljs-number\">100%<\/span>;\n}\n\n<span class=\"hljs-selector-class\">.video-container<\/span><span class=\"hljs-selector-pseudo\">::after<\/span> {\n    <span class=\"hljs-attribute\">padding-top<\/span>: <span class=\"hljs-number\">56.25%<\/span>;\n    <span class=\"hljs-attribute\">display<\/span>: block;\n    <span class=\"hljs-attribute\">content<\/span>: <span class=\"hljs-string\">''<\/span>;\n}\n\n<span class=\"hljs-selector-class\">.video-container<\/span> <span class=\"hljs-selector-tag\">iframe<\/span> {\n    <span class=\"hljs-attribute\">position<\/span>: absolute;\n    <span class=\"hljs-attribute\">top<\/span>: <span class=\"hljs-number\">0<\/span>;\n    <span class=\"hljs-attribute\">left<\/span>: <span class=\"hljs-number\">0<\/span>;\n    <span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n    <span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">100%<\/span>;\n}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This component allows you to embed a youtube video by just passing the video identifier as a prop under <code>videoId.<\/code><\/p>\n<p>Now, in your markdown file, you can do<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">--- \ntitle: Svex up your markdown \ndescription: My first markdown content\nkeywords:\n - Keyword 1\n - Keyword 2\n--- \n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n<span class=\"hljs-keyword\">import<\/span> Youtube <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'$lib\/components\/Youtube.svelte'<\/span>\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n# { title }\n\nThis is more markdown **base content**\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Youtube<\/span> <span class=\"hljs-attr\">videoId<\/span>=<span class=\"hljs-string\">\"AdNJ3fydeao\"<\/span> \/&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Just like another svelte component, now you can import components into the markdown and render it!. MDsveX will take care of parse and transform the entire page and correctly render the content.<\/p>\n<p>Take a look at the result by running (in case you don\u2019t have it running) <code>npm run dev<\/code> and visiting <code>http:\/\/localhost:3000\/blog\/my-first-post<\/code><\/p>\n<p>Now you\u2019ll see the video content directly in your post.<\/p>\n<p>Now, let\u2019s create another component to embed codeSandbox examples.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n\t<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">let<\/span> sandboxId\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">iframe<\/span>\n\t<span class=\"hljs-attr\">data-testid<\/span>=<span class=\"hljs-string\">\"codesandbox\"<\/span>\n\t<span class=\"hljs-attr\">title<\/span>=<span class=\"hljs-string\">{<\/span>`<span class=\"hljs-attr\">codeSandbox-<\/span>${<span class=\"hljs-attr\">sandboxId<\/span>}`}\n\t<span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{<\/span>`<span class=\"hljs-attr\">https:<\/span>\/\/<span class=\"hljs-attr\">codesandbox.io<\/span>\/<span class=\"hljs-attr\">embed<\/span>\/${<span class=\"hljs-attr\">sandboxId<\/span>}`}\n\t<span class=\"hljs-attr\">allow<\/span>=<span class=\"hljs-string\">\"geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb\"<\/span>\n\t<span class=\"hljs-attr\">sandbox<\/span>=<span class=\"hljs-string\">\"allow-modals allow-forms allow-popups allow-scripts allow-same-origin\"<\/span>\n\/&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">style<\/span>&gt;<\/span><span class=\"css\">\n\t<span class=\"hljs-selector-tag\">iframe<\/span> {\n\t\t<span class=\"hljs-attribute\">width<\/span>: <span class=\"hljs-number\">100%<\/span>;\n\t\t<span class=\"hljs-attribute\">height<\/span>: <span class=\"hljs-number\">500px<\/span>;\n\t\t<span class=\"hljs-attribute\">border<\/span>: <span class=\"hljs-number\">0<\/span>;\n\t\t<span class=\"hljs-attribute\">border-radius<\/span>: <span class=\"hljs-number\">4px<\/span>;\n\t\t<span class=\"hljs-attribute\">overflow<\/span>: hidden;\n\t}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">style<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>As you can see, the process to create these embed media components is fairly simple with Svelte, just add the corresponding iframe element and the required custom properties, in this case, the prop <code>sandboxId<\/code>.<\/p>\n<p>Now, in your markdown content, you can use it like<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\">--- \ntitle: Svex up your markdown \ndescription: My first markdown content\nkeywords:\n - Keyword 1\n - Keyword 2\n--- \n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span>&gt;<\/span><span class=\"javascript\">\n<span class=\"hljs-keyword\">import<\/span> Youtube <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'$lib\/components\/Youtube.svelte'<\/span>\n<span class=\"hljs-keyword\">import<\/span> CodeSandbox <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'$lib\/components\/CodeSandbox.svelte'<\/span>\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n# { title }\n\nThis is more markdown **base content**\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Youtube<\/span> <span class=\"hljs-attr\">videoId<\/span>=<span class=\"hljs-string\">\"AdNJ3fydeao\"<\/span> \/&gt;<\/span>\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-markdown \"><pre class=\"js-syntax-highlighted\"><code>\n&gt; [Check this sandbox](https:\/\/codesandbox.io\/s\/wispy-tdd-3oq00?file=\/App.svelte)  to review how this component works\n\nNow let's create a Tweet component to embed a particular tweet into the markdown content.\n\nThis is a bit different the previous one since it requires loading an external script, but svelte give you simple tools to accomplish this.\n\n```html\n&lt;script&gt;\n  import { onMount } from &quot;svelte&quot;;\n  let mounted = false;\n  export let id;\n\n  onMount(() =&gt; {\n    \/\/ The payment-form is ready.\n    mounted = true;\n  });\n\n  function scriptLoaded() {\n    if (mounted) {\n      var tweet = document.getElementById(&quot;tweet&quot;);\n      window.twttr.widgets\n        .createTweet(id, tweet, {\n          conversation: &quot;none&quot;, \/\/ or all\n          cards: &quot;hidden&quot;, \/\/ or visible\n          linkColor: &quot;#cc0000&quot;, \/\/ default is blue\n          theme: &quot;light&quot; \/\/ or dark\n        });\n    }\n  }\n&lt;\/script&gt;\n\n&lt;svelte:head&gt;\n  &lt;script src=&quot;https:\/\/platform.twitter.com\/widgets.js&quot; on:load={scriptLoaded}&gt;&lt;\/script&gt;\n&lt;\/svelte:head&gt;\n    \n\n&lt;div id=&quot;tweet&quot; \/&gt;\n<\/code><\/pre>\n<p>First thing is to use the <code>svelte:head<\/code> component to add a script tag into the document head.<\/p>\n<p>This script tag point to the Twitter widget library and triggers a callback function when is loaded by using the <code>on:load<\/code> event.<\/p>\n<p>Then, in the <code>script<\/code> tag of this component, you can see that the callback function <code>scriptLoaded<\/code> function check if the component is already mounted and then run the twitter set up to show the tweet.<\/p>\n<p>To identify what tweet you want to render, just use the prop <code>id<\/code><\/p>\n<p>This way you have all you need to add external media components into your markdown files powered by MDsveX.<\/p>\n<h2>Create a list of markdown files<\/h2>\n<p>Something worth mentioning when working with MDsveX is about how to create a page to list your markdown files or posts, to do this you\u2019ll use the power of <a href=\"https:\/\/kit.svelte.dev\/docs#routing-endpoints\">endpoint routes<\/a> and <a href=\"https:\/\/vitejs.dev\/guide\/features.html#glob-import\">glob import<\/a> feature from Vite.<\/p>\n<p>First, let\u2019s create an API endpoint to gather the content; create a file under <code>src\/routes\/api\/blog\/index.json.ts<\/code><\/p>\n<p>Inside that file, create and export a <code>get<\/code> function, this function will load, parse and return a JSON object with the list of your files.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">getPosts<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\t<span class=\"hljs-keyword\">const<\/span> modules = <span class=\"hljs-keyword\">import<\/span>.meta.glob(<span class=\"hljs-string\">`..\/routes\/blog\/post\/*.svx`<\/span>);  <span class=\"hljs-comment\">\/\/ load all the svx files <\/span>\n\n\t<span class=\"hljs-keyword\">const<\/span> postPromises = &#91;];\n\t<span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">const<\/span> &#91;path, resolver] <span class=\"hljs-keyword\">of<\/span> <span class=\"hljs-built_in\">Object<\/span>.entries(modules)) {\n\t\t<span class=\"hljs-keyword\">const<\/span> promise = resolver().then(<span class=\"hljs-function\">(<span class=\"hljs-params\">post<\/span>) =&gt;<\/span> {\n\t\t\t<span class=\"hljs-keyword\">const<\/span> slug = path.match(<span class=\"hljs-regexp\">\/(&#91;\\w-]+)\\.(svelte\\.svx)\/i<\/span>)?.&#91;<span class=\"hljs-number\">1<\/span>] ?? <span class=\"hljs-literal\">null<\/span>; <span class=\"hljs-comment\">\/\/ Create the slug<\/span>\n\t\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t\tslug,\n\t\t\t\t...post.metadata\n\t\t\t};\n\t\t});\n\t\tpostPromises.push(promise);\n\t}\n\n\t<span class=\"hljs-keyword\">const<\/span> posts = <span class=\"hljs-keyword\">await<\/span> <span class=\"hljs-built_in\">Promise<\/span>.all(postPromises);\n\t<span class=\"hljs-keyword\">return<\/span> posts\n}\n\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">get<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n\t<span class=\"hljs-keyword\">const<\/span> posts = <span class=\"hljs-keyword\">await<\/span> getPosts();\n\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t<span class=\"hljs-attr\">body<\/span>: {\n\t\t\tposts\n\t\t}\n\t};\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>The key here is the <code>import.meta.glob<\/code> that will retrieve all the files that match the glob, in this case, that ends with the <code>.svx<\/code> extension<\/p>\n<p>Now, create the page to list this files under <code>src\/routes\/blog\/index.svelte<\/code><\/p>\n<p>This svelte component will use a <a href=\"https:\/\/kit.svelte.dev\/docs#loading\">loader function<\/a> to fetch the data from the previous API endpoint and then render that in the screen.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> <span class=\"hljs-attr\">lang<\/span>=<span class=\"hljs-string\">\"ts\"<\/span> <span class=\"hljs-attr\">context<\/span>=<span class=\"hljs-string\">\"module\"<\/span>&gt;<\/span><span class=\"javascript\">\n\t<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">async<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">load<\/span>(<span class=\"hljs-params\">{ fetch }<\/span>) <\/span>{\n\t\t<span class=\"hljs-keyword\">const<\/span> url = <span class=\"hljs-string\">'\/api\/blog.json'<\/span>;\n\t\t<span class=\"hljs-keyword\">const<\/span> res = <span class=\"hljs-keyword\">await<\/span> fetch(url);\n\t\t<span class=\"hljs-keyword\">if<\/span> (res.ok) {\n\t\t\t<span class=\"hljs-keyword\">const<\/span> { posts  } = <span class=\"hljs-keyword\">await<\/span> res.json();\n\t\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t\t<span class=\"hljs-attr\">props<\/span>: {\n\t\t\t\t\tposts\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\n\t\t<span class=\"hljs-keyword\">return<\/span> {\n\t\t\t<span class=\"hljs-attr\">status<\/span>: res.status,\n\t\t\t<span class=\"hljs-attr\">error<\/span>: <span class=\"hljs-keyword\">new<\/span> <span class=\"hljs-built_in\">Error<\/span>(<span class=\"hljs-string\">`Could not load <span class=\"hljs-subst\">${url}<\/span>`<\/span>)\n\t\t};\n\t}\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">script<\/span> &gt;<\/span><span class=\"javascript\">\n\t<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">let<\/span> posts; <span class=\"hljs-comment\">\/\/ The prop value comes from the module above<\/span>\n<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">script<\/span>&gt;<\/span>\n\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n{#each posts as post}\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n\t<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a<\/span> <span class=\"hljs-attr\">href<\/span>=<span class=\"hljs-string\">{<\/span>`\/<span class=\"hljs-attr\">blog<\/span>\/<span class=\"hljs-attr\">posts<\/span>\/${<span class=\"hljs-attr\">post.slug<\/span>}`}&gt;<\/span>\n\t\t{post.title}\n\t<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">a<\/span>&gt;<\/span>\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">li<\/span>&gt;<\/span>\n{\/each}\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">ul<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This component will just get the data returned by the API endpoint and create a list of titles from your <code>.svx<\/code> files.<\/p>\n<h1>Conclusion<\/h1>\n<p>Use markdown is an easy and simple way to create your content but it lacks interactivity and dynamism, that piece can be added by using the power of pre-processors and AST that enable the existence of tools like MDsveX.<\/p>\n<p>MDsveX lets you use the full power of Svelte components from inside your markdown content adding that dynamic layer.<\/p>\n<p>Anything that you can think and build as a Svelte component can be used inside MDsveX files.<\/p>\n<!-- Thank you for the fun build, no notes. All links are good, sandbox\/embeded & github are good as well. No errors in content. Thank you ! -->\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28248,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,175,376,371],"class_list":["post-28247","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-jamstack","tag-svelte","tag-under-review"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Embed Media Components using MDX<\/title>\n<meta name=\"description\" content=\"MDsveX is the answer from the Svelte world to the need of authoring rich media content using a powerful media like Markdown. This is a markdown pre-processor for Svelte components, this preprocessor allows you to use Svelte components in your markdown, or vice versa. It supports all Svelte syntax and almost all Markdown\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Embed Media Components using MDX\" \/>\n<meta property=\"og:description\" content=\"MDsveX is the answer from the Svelte world to the need of authoring rich media content using a powerful media like Markdown. This is a markdown pre-processor for Svelte components, this preprocessor allows you to use Svelte components in your markdown, or vice versa. It supports all Svelte syntax and almost all Markdown\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-03-23T22:24:38+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925030\/Web_Assets\/blog\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"4592\" \/>\n\t<meta property=\"og:image:height\" content=\"3448\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Embed Media Components using MDX\",\"datePublished\":\"2022-03-23T22:24:38+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/\"},\"wordCount\":5,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925030\/Web_Assets\/blog\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e.jpg?_i=AA\",\"keywords\":[\"Guest Post\",\"JAMStack\",\"Svelte\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/\",\"name\":\"Embed Media Components using MDX\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925030\/Web_Assets\/blog\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e.jpg?_i=AA\",\"datePublished\":\"2022-03-23T22:24:38+00:00\",\"description\":\"MDsveX is the answer from the Svelte world to the need of authoring rich media content using a powerful media like Markdown. This is a markdown pre-processor for Svelte components, this preprocessor allows you to use Svelte components in your markdown, or vice versa. It supports all Svelte syntax and almost all Markdown\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925030\/Web_Assets\/blog\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925030\/Web_Assets\/blog\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e.jpg?_i=AA\",\"width\":4592,\"height\":3448},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Embed Media Components using MDX\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Embed Media Components using MDX","description":"MDsveX is the answer from the Svelte world to the need of authoring rich media content using a powerful media like Markdown. This is a markdown pre-processor for Svelte components, this preprocessor allows you to use Svelte components in your markdown, or vice versa. It supports all Svelte syntax and almost all Markdown","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/","og_locale":"en_US","og_type":"article","og_title":"Embed Media Components using MDX","og_description":"MDsveX is the answer from the Svelte world to the need of authoring rich media content using a powerful media like Markdown. This is a markdown pre-processor for Svelte components, this preprocessor allows you to use Svelte components in your markdown, or vice versa. It supports all Svelte syntax and almost all Markdown","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-03-23T22:24:38+00:00","og_image":[{"width":4592,"height":3448,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925030\/Web_Assets\/blog\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e.jpg?_i=AA","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/"},"author":{"name":"","@id":""},"headline":"Embed Media Components using MDX","datePublished":"2022-03-23T22:24:38+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/"},"wordCount":5,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925030\/Web_Assets\/blog\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e.jpg?_i=AA","keywords":["Guest Post","JAMStack","Svelte","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/","name":"Embed Media Components using MDX","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925030\/Web_Assets\/blog\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e.jpg?_i=AA","datePublished":"2022-03-23T22:24:38+00:00","description":"MDsveX is the answer from the Svelte world to the need of authoring rich media content using a powerful media like Markdown. This is a markdown pre-processor for Svelte components, this preprocessor allows you to use Svelte components in your markdown, or vice versa. It supports all Svelte syntax and almost all Markdown","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925030\/Web_Assets\/blog\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925030\/Web_Assets\/blog\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e.jpg?_i=AA","width":4592,"height":3448},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/embed-media-components-using-mdx-and-sveltekit\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Embed Media Components using MDX"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925030\/Web_Assets\/blog\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e\/74765ee038783d4e76c07cb93f97094364d7f563-4592x3448-1_28248e3f7e.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28247","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28247"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28247\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28248"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28247"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28247"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28247"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}