{
    "componentChunkName": "component---src-templates-post-js",
    "path": "/blog/handling-external-links-for-mdx-files-in-gatsby/",
    "result": {"data":{"site":{"siteMetadata":{"title":"Danniel Hansel"}},"mdx":{"id":"b86814e4-5866-5e31-91ff-d0a8b9ea363b","excerpt":"Typically, when you’re writing markdown files, you’d sometimes want to include a link that takes the user from your current page to some other page. Sometimes…","body":"const _excluded = [\"components\"];\n\nfunction _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nfunction _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }\n\nfunction _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }\n\n/* @jsxRuntime classic */\n\n/* @jsx mdx */\nconst _frontmatter = {\n  \"slug\": \"handling-external-links-for-mdx-files-in-gatsby\",\n  \"title\": \"Handling External Links for MDX files in Gatsby\",\n  \"date\": \"2021-12-10\",\n  \"author\": \"Danniel Hansel\",\n  \"description\": \"The easiest way to open links in a new tab when using gatsby-plugin-mdx.\",\n  \"published\": true,\n  \"featured\": true,\n  \"categories\": [\"web-development\"],\n  \"tags\": [\"ssg\", \"react\", \"gatsby\"],\n  \"bannerUrl\": \"https://res.cloudinary.com/dehanz-dev/image/upload/v1640453751/dannielhansel.com/content/blog/external-link_roctbf.webp\",\n  \"bannerCredit\": \"Photo by [Eric Mclean](https://unsplash.com/photos/sxiSod0tyYQ) on [Unsplash](https://unsplash.com)\"\n};\nconst layoutProps = {\n  _frontmatter\n};\nconst MDXLayout = \"wrapper\";\nreturn function MDXContent(_ref) {\n  let {\n    components\n  } = _ref,\n      props = _objectWithoutProperties(_ref, _excluded);\n\n  return mdx(MDXLayout, _extends({}, layoutProps, props, {\n    components: components,\n    mdxType: \"MDXLayout\"\n  }), mdx(\"p\", null, `Typically, when you’re writing markdown files, you’d sometimes want to include a link that takes the user from your current page to some other page. Sometimes, these links can be internal (i.e. redirects user to a page on your site) or external (i.e. `, mdx(\"a\", {\n    parentName: \"p\",\n    \"href\": \"https://www.twitter.com\"\n  }, `https://www.twitter.com`), `). What is the best way to set this up globally so that you don’t have to manually configure it on every markdown files?`), mdx(\"h2\", null, `Option #1: Creating the Link component`), mdx(\"p\", null, `This component basically checks if the link is prefixed with your site’s url or “/”. Then decides if it should open in a new tab or not:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `const ExternalLink = props => {\n  if (\n    props.href.includes(\"https://dannielhansel.com/\") ||\n    props.href[0] === \"/\"\n  ) {\n    return (\n      <a {...props} href={props.href}>\n        {props.children}\n      </a>\n    )\n  }\n  return (\n    <a {...props} href={props.href} target=\"_blank\" rel=\"noopener noreferrer\">\n      {props.children}\n    </a>\n  )\n}\n`)), mdx(\"h2\", null, `Pass the component object into MDXProvider`), mdx(\"p\", null, `Then, you can pass it into the MDXProvider so every markdown link syntax can be controlled:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `const components = {\n    a: ExternalLink,\n}\n\nconst ExampleLayout = ({children}) => (\n    <>\n        <MDXProvider components={components}>\n            <MDXRenderer>{body}</MDXRenderer>\n        </MDXProvider>\n    <>\n)\n`)), mdx(\"h2\", null, `Option #2: Using DRY principle`), mdx(\"p\", null, `Another way is to create a reusable component and just import it whenever you need it. You can also use this outside of your markdown files (i.e. your social links on your site).`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// inside /src/components/link.js\nimport * as React from \"react\"\nimport { Link as GatsbyLink } from \"gatsby\"\n\n// Since DOM elements <a> cannot receive activeClassName\n// and partiallyActive, destructure the prop here and\n// pass it only to GatsbyLink\nconst Link = ({ children, to, activeClassName, partiallyActive, ...other }) => {\n  // Tailor the following test to your environment.\n  // This regex assumes that any internal link (intended for Gatsby)\n  // will start with exactly one slash, and that anything else is external.\n  const internal = /^\\\\/(?!\\\\/)/.test(to)\n\n  // Use Gatsby Link for internal links, and <a> for others\n  if (internal) {\n    return (\n      <GatsbyLink\n        to={to}\n        activeClassName={activeClassName}\n        partiallyActive={partiallyActive}\n        {...other}\n      >\n        {children}\n      </GatsbyLink>\n    )\n  }\n\n  return (\n    <a href={to} {...other} target=\"_blank\" rel=\"noopener noreferrer\">\n      {children}\n    </a>\n  )\n}\n\nexport default Link\n`)), mdx(\"p\", null, `Then you can import this component in your markdown file just like a regular javascript file.`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// inside /content/handling-external-links-for-mdx-files-in-gatsby.mdx\n\nimport Link from \"../../src/components/link\"\n\n// ---\n// ... frontmatter stuff\n// ---\n;<Link to=\"https://twitter.com\">Twitter</Link>\n`)), mdx(\"h2\", null, `Option #3: Use the component as shortcode`), mdx(\"p\", null, `Another way is to kind of combine option 1 and 2, or known as “shortcode”. It’s basically a component that is available in every markdown file without you having to import it every time.`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `import Link from '../components/link'\n\nconst components = {\n    Link: ({children, to, ...props}) => (\n        <Link to={href} {...props}>\n            {children}\n        </Link>\n    ),\n}\n\nconst ExampleLayout = ({children}) => (\n    <>\n        <MDXProvider components={components}>\n            <MDXRenderer>{body}</MDXRenderer>\n        </MDXProvider>\n    <>\n)\n`)), mdx(\"p\", null, `Then in your markdown file:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// inside /content/handling-external-links-for-mdx-files-in-gatsby.mdx\n\n// ---\n// ... frontmatter stuff\n// ---\n\n<Link to=\"https://twitter.com\">Twitter</Link>\n`)), mdx(\"h2\", null, `Recap:`), mdx(\"p\", null, `Here’s what your Post template would look like:`), mdx(\"pre\", null, mdx(\"code\", {\n    parentName: \"pre\",\n    \"className\": \"language-jsx\"\n  }, `// in your templates/post.js\n\nconst ExternalLink = props => {\n  if (\n    props.href.includes(\"https://dannielhansel.com/\") ||\n    props.href[0] === \"/\"\n  ) {\n    return (\n      <a\n        {...props}\n        href={props.href}\n        className=\"font-semibold text-accent hover:underline hover:underline-offset-4 cursor-pointer\"\n      >\n        {props.children}\n      </a>\n    )\n  }\n  return (\n    <a\n      {...props}\n      href={props.href}\n      className=\"font-semibold text-accent hover:underline hover:underline-offset-4 cursor-pointer\"\n      target=\"_blank\"\n      rel=\"noopener noreferrer\"\n    >\n      {props.children}\n    </a>\n  )\n}\n\nconst components = {\n    // other components ...\n    a: ExternalLink,\n}\n\nconst BlogPostTemplate = ({children}) => {\n    const { frontmatter, body, timeToRead, excerpt, fields } = data.mdx\n    return (\n        <>\n            <MDXProvider components={components}>\n                <MDXRenderer>{body}</MDXRenderer>\n            </MDXProvider>\n        <>\n    )\n}\n\nexport const pageQuery = graphql\\`\n  query BlogPostQuery($id: String) {\n\n    mdx(id: { eq: $id }) {\n      id\n      excerpt(pruneLength: 160)\n      body\n      timeToRead\n      fields {\n        slug\n      }\n      frontmatter {\n        slug\n        title\n        author\n        tags\n        description\n        date(formatString: \"Do MMM YYYY\")\n      }\n    }\n  }\n\\`\nexport default blogPost\n`)));\n}\n;\nMDXContent.isMDXComponent = true;","timeToRead":1,"fields":{"slug":"/blog/handling-external-links-for-mdx-files-in-gatsby/"},"frontmatter":{"slug":"handling-external-links-for-mdx-files-in-gatsby","title":"Handling External Links for MDX files in Gatsby","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1640453751/dannielhansel.com/content/blog/external-link_roctbf.webp","bannerCredit":"Photo by [Eric Mclean](https://unsplash.com/photos/sxiSod0tyYQ) on [Unsplash](https://unsplash.com)","tags":["ssg","react","gatsby"],"description":"The easiest way to open links in a new tab when using gatsby-plugin-mdx.","date":"December 10, 2021"}},"relatedMdxs":{"posts":[{"id":"f2db5aef-b482-532f-9a92-f93463cc0a26","timeToRead":2,"slug":"blog/the-debate-between-library-vs-package-vs-framework-vs-module","frontmatter":{"title":"The Debate between Module vs Package vs Library vs Framework","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1640453749/dannielhansel.com/content/blog/package-library_xqm8ix.webp","bannerCredit":"Photo by [Bench Accounting](https://unsplash.com/photos/MGaFENpDCsw) on [Unsplash](https://unsplash.com)","slug":"the-debate-between-library-vs-package-vs-framework-vs-module","tags":["software-engineering","tools"],"description":"One of the most frequent asked question in Software Engineering.","date":"January 10, 2021"}},{"id":"1bd58e0e-11af-50e2-b16f-1284d82c7cea","timeToRead":7,"slug":"blog/7-basic-rules-for-self-improvement","frontmatter":{"title":"7 Basic Rules for Self Improvement","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639602245/dannielhansel.com/content/blog/7-basic-rules-for-self-improvement_vhqngn.jpg","bannerCredit":"Photo by [Alif Ngoylung](https://unsplash.com/photos/-A_Sx8GrRWg) on [Unsplash](https://unsplash.com)","slug":"7-basic-rules-for-self-improvement","tags":["personal","productivity"],"description":"What I have learned from doing self-development work.","date":"November 27, 2020"}},{"id":"6716a85b-6801-525e-b2ea-5448c01bf60d","timeToRead":6,"slug":"blog/rebuilding-my-portfolio-site-with-tailwind-css","frontmatter":{"title":"Rebuilding my portfolio site with Tailwind CSS","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1640453752/dannielhansel.com/content/blog/rebuild-portfolio_s7cuq0.webp","bannerCredit":"Photo by [Aziz Acharki](https://unsplash.com/photos/6YpwRf0iUa4) on [Unsplash](https://unsplash.com)","slug":"rebuilding-my-portfolio-site-with-tailwind-css","tags":["javascript","react","gatsby","tailwind-css","bootstrap"],"description":"My experience with Tailwind CSS.","date":"May 13, 2021"}},{"id":"607bdcda-0d6c-5f06-9a34-7c59aca6989d","timeToRead":1,"slug":"blog/initial-setup-for-cloud-firestore-database","frontmatter":{"title":"Initial setup for Cloud Firestore database","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639602371/dannielhansel.com/content/blog/initial-setup-for-cloud-firestore-database_p8rflb.jpg","bannerCredit":"Photo by [Jan Antonin Kolar](https://unsplash.com/photos/lRoX0shwjUQ) on [Unsplash](https://unsplash.com)","slug":"initial-setup-for-cloud-firestore-database","tags":["react","ssr","backend","nextjs","database"],"description":"This quick guide shows you how to set up Cloud Firestore for your React application.","date":"November 01, 2021"}},{"id":"edc10d92-c4e5-58c7-a0ec-e0a4fb636181","timeToRead":5,"slug":"blog/powerful-morning-routines-that-will-change-your-life","frontmatter":{"title":"Powerful Morning Routines that Will Change Your Life","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639601696/dannielhansel.com/content/blog/rebuilding-my-portfolio-site-with-tailwind-css_rqnsbb.jpg","bannerCredit":"Photo by [lucas Favre](https://unsplash.com/photos/JnoNcfFwrNA) on [Unsplash](https://unsplash.com)","slug":"powerful-morning-routines-that-will-change-your-life","tags":["personal","productivity"],"description":"Killer morning routines to better your life and reach your full potential.","date":"February 03, 2021"}},{"id":"b15e2892-c0b8-5bbc-966d-3bfb10cac6c2","timeToRead":2,"slug":"blog/fetching-data-from-firestore","frontmatter":{"title":"Fetching data from Firestore","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639602322/dannielhansel.com/content/blog/fetching-data-from-firestore_zalbof.jpg","bannerCredit":"Photo by [Tobias Fischer](https://unsplash.com/photos/PkbZahEG2Ng) on [Unsplash](https://unsplash.com)","slug":"fetching-data-from-firestore","tags":["react","ssr","database","nextjs","database"],"description":"This quick guide shows you how to create a React custom hook to fetch data from Cloud Firestore.","date":"November 08, 2021"}},{"id":"f3c648a6-01ba-585b-99f5-85cf76a54f73","timeToRead":1,"slug":"testimonial/testimonial","frontmatter":{"title":"Testimonial 1","author":"Maggie","bannerUrl":null,"bannerCredit":null,"slug":null,"tags":null,"description":null,"date":null}},{"id":"f5e43818-6b9e-539f-b958-b022a7c84719","timeToRead":2,"slug":"blog/image-types-vector-vs-pixel","frontmatter":{"title":"Image types: Vector vs. Pixel","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1644037300/dannielhansel.com/content/blog/pixal-vs-vector_dkaxg1.jpg","bannerCredit":"Photo by [Umberto](https://unsplash.com/photos/deb2EnbWPr8) on [Unsplash](https://unsplash.com)","slug":"image-types-vector-vs-pixel","tags":["performance"],"description":"Why you should go for Vector vs. Pixel.","date":"December 03, 2021"}},{"id":"cf047db2-ca90-5b7d-85d4-62dd9bec16bd","timeToRead":2,"slug":"about/about-me","frontmatter":{"title":"About Danniel Hansel","author":"Danniel Hansel","bannerUrl":null,"bannerCredit":null,"slug":null,"tags":null,"description":"Learn about Danniel Hansel and how he got to where he is","date":null}},{"id":"4e777b1c-f8d9-57f8-9799-cfd6f1af27a2","timeToRead":1,"slug":"about/about","frontmatter":{"title":"About Me","author":"Danniel Hansel","bannerUrl":null,"bannerCredit":null,"slug":null,"tags":null,"description":"Learn about Danniel Hansel and what he does","date":null}},{"id":"c63edb7e-453e-5bac-ab79-6514bfcc5983","timeToRead":1,"slug":"project/project10/project10","frontmatter":{"title":"Book List Tracker","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}},{"id":"23fb515e-31a0-5407-b16b-d9b688f2b5af","timeToRead":1,"slug":"blog/updating-data-from-firestore","frontmatter":{"title":"Updating data from Firestore","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1639602451/dannielhansel.com/content/blog/updating-data-from-firestore_zvsbav.jpg","bannerCredit":"Photo by [Piron Guillaume](https://unsplash.com/photos/U4FyCp3-KzY) on [Unsplash](https://unsplash.com)","slug":"updating-data-from-firestore","tags":["react","ssr","database","nextjs","backend"],"description":"This quick guide shows you how to handle CRUD operations from Firestore database.","date":"November 27, 2021"}},{"id":"57e4f42a-2bfd-5fde-b040-2907d11a5ea5","timeToRead":1,"slug":"hero/hero","frontmatter":{"title":"Danniel Hansel","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":null,"description":null,"date":null}},{"id":"57c19c65-eeb5-5d52-ae1f-c83b4caef2ff","timeToRead":1,"slug":"project/project2/project2","frontmatter":{"title":"Smart POS Web App","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["React","NextJS","Tailwind","Firebase","Firestore","NodeJS","OpenShift"],"description":null,"date":null}},{"id":"6f5b7bcc-efa4-5084-8b34-cec1b0506f16","timeToRead":1,"slug":"blog/my-favorite-tech-podcasts","frontmatter":{"title":"My Favorite Tech Podcasts","author":"Danniel Hansel","bannerUrl":"https://res.cloudinary.com/dehanz-dev/image/upload/v1644037050/dannielhansel.com/content/blog/my-favorite-podcasts_ksnqce.jpg","bannerCredit":"Photo by [Mohammad Metri](https://unsplash.com/photos/1oKxSKSOowE) on [Unsplash](https://unsplash.com)","slug":"my-favorite-tech-podcasts","tags":["personal","productivity"],"description":"I've compiled a list of my favorite tech and non-tech podcasts.","date":"January 15, 2022"}},{"id":"63959d00-7675-5872-abd4-3ace45480a22","timeToRead":1,"slug":"project/project9/project9","frontmatter":{"title":"Budget Calculator","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}},{"id":"a4e7f4fe-a19d-5cf5-86fd-149edddafdc3","timeToRead":1,"slug":"project/project6/project6","frontmatter":{"title":"Todos App","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}},{"id":"e8a491a4-73b5-5be8-b294-49362cf66dc0","timeToRead":1,"slug":"project/project3/project3","frontmatter":{"title":"E-Commerce Web App","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["React","Material UI","Commerce.js","Stripe"],"description":null,"date":null}},{"id":"6563d4b8-ff14-5280-8e20-7f7b930b8f73","timeToRead":1,"slug":"project/project1/project1","frontmatter":{"title":"The Crab Station & Oyster Bar","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["React","GatsbyJS","Bootstrap","Contentful","Netlify","AWS"],"description":null,"date":null}},{"id":"1811b711-5e38-548f-ad4e-5e774b0f2a00","timeToRead":1,"slug":"project/project11/project11","frontmatter":{"title":"Accordion UI","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}},{"id":"0f9e61b3-88a9-5ea1-b965-0098a1061015","timeToRead":1,"slug":"project/project4/project4","frontmatter":{"title":"Type Racer","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","Bootstrap"],"description":null,"date":null}},{"id":"875cf1c0-a200-5715-9d26-d0cdd74aea7b","timeToRead":1,"slug":"project/project8/project8","frontmatter":{"title":"Quote Generator v2","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}},{"id":"c34b3f70-bf92-5a5f-9d18-90fb40c407aa","timeToRead":1,"slug":"project/project5/project5","frontmatter":{"title":"Tic Tac Toe","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}},{"id":"d6c51e86-ed84-5489-a9f8-0f38e78963b2","timeToRead":1,"slug":"project/project7/project7","frontmatter":{"title":"Quote Generator v1","author":null,"bannerUrl":null,"bannerCredit":null,"slug":null,"tags":["Vanilla JS","HTML/CSS"],"description":null,"date":null}}]}},"pageContext":{"id":"b86814e4-5866-5e31-91ff-d0a8b9ea363b"}},
    "staticQueryHashes": ["2744905544","3145194271","3970664207"]}