<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Snappy Web Design</title>
    <description>The latest articles on Forem by Snappy Web Design (@snappywebdesign).</description>
    <link>https://forem.com/snappywebdesign</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F649606%2F6b56d422-62a1-40b5-aaad-9959ba914469.png</url>
      <title>Forem: Snappy Web Design</title>
      <link>https://forem.com/snappywebdesign</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/snappywebdesign"/>
    <language>en</language>
    <item>
      <title>The Dysfunctional Back Button</title>
      <dc:creator>Snappy Web Design</dc:creator>
      <pubDate>Sun, 29 Aug 2021 22:58:46 +0000</pubDate>
      <link>https://forem.com/snappywebdesign/the-dysfunctional-back-button-4552</link>
      <guid>https://forem.com/snappywebdesign/the-dysfunctional-back-button-4552</guid>
      <description>&lt;p&gt;Visit this &lt;a href="https://www.searchenginewatch.com/2013/08/09/10-google-analytics-custom-events-that-track-the-untrackable/" rel="nofollow noreferrer"&gt;website&lt;/a&gt; and you’ll be infiltrated by three separate popup modals and two banners urging you to sign up for something. You’ll be forced to sequentially close the popups and banners to actually see the text on the page. One modal, fine - but three of them? &lt;em&gt;And&lt;/em&gt; two banners? A bit excessive. The worst is yet to come though - reserved for when you try to hit the &lt;em&gt;back&lt;/em&gt; button to return to whatever page you were previously on. No, it’s not an alert box asking you to confirm that you want to leave, or a case of the infinitely-refreshing page. This site decided to opt for a far more bold and dubious infringement of good UX. Potentially the “holy-grail” of annoying website practices: hitting back on this site will scroll you up about a ¼ of a centimeter. &lt;/p&gt;

&lt;p&gt;If you clicked on this site from a Google search and were hoping to go back to the results, you can kiss that dream goodbye. You’ll be clicking the back button for at least five minutes, potentially years. If you dare stay on the site in a last-ditch attempt to salvage your tab, you’ll be solicited once again with a popup requesting permission to send you push notifications. Which, I can only assume would lead to never-ending push notifications, too. Either way, the authors of this site have clearly chosen &lt;em&gt;one&lt;/em&gt; method of retaining users: through force.&lt;/p&gt;

&lt;p&gt;With all jokes aside, this site is a great example of web developers going too far in the name of conversions. Like, way too far. This site is so intrusive I thought I accidentally clicked on a satirical site made to highlight frustrating UX by reddit user ...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Keep Reading: &lt;a href="https://snappywebdesign.net/blog/the-dysfunctional-back-button/"&gt;https://snappywebdesign.net/blog/the-dysfunctional-back-button/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ux</category>
      <category>design</category>
    </item>
    <item>
      <title>How to style the Active Drawer ListItem in Material-UI</title>
      <dc:creator>Snappy Web Design</dc:creator>
      <pubDate>Fri, 06 Aug 2021 23:28:56 +0000</pubDate>
      <link>https://forem.com/snappywebdesign/how-to-style-the-active-drawer-listitem-in-material-ui-en7</link>
      <guid>https://forem.com/snappywebdesign/how-to-style-the-active-drawer-listitem-in-material-ui-en7</guid>
      <description>&lt;p&gt;Wondering how to set or style the active link in Material-UI? This Material-UI tutorial will teach you how to style an active drawer / tab item with simplest code possible. &lt;/p&gt;

&lt;p&gt;The Mui AppBar and Drawer provide a great starting point - but they don't provide a solid foundation for highlighting the active tab. As a result, many developers end up with 'hacky' methods of setting active nav items. Fortunately, there's a better way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Demo
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://snappywebdesign.github.io/csb-h8lqf/"&gt;Live Site&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://codesandbox.io/s/github/SnappyWebDesign/Material-UI_Active_ListItem_Tutorial/tree/main/?file=/src/components/DrawerDemo.js"&gt;Codesandbox Demo&lt;/a&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/SnappyWebDesign/Material-UI_Active_ListItem_Tutorial"&gt;Github Repo&lt;/a&gt;  &lt;/p&gt;
&lt;h3&gt;
  
  
  Preview:
&lt;/h3&gt;

&lt;p&gt;&lt;a href="//images.contentful.com/z7pyyvho21dm/2JmGSRe0zSQC2x5p9k8GPC/0598e1d60204f4e7cc8cfa670c7afce8/Screenshot_2021-08-03_155528.jpg" class="article-body-image-wrapper"&gt;&lt;img src="//images.contentful.com/z7pyyvho21dm/2JmGSRe0zSQC2x5p9k8GPC/0598e1d60204f4e7cc8cfa670c7afce8/Screenshot_2021-08-03_155528.jpg" alt="Screenshot 2021-08-03 155528"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Boilerplate (Starting Point)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react"
import { Link } from "gatsby" OR "@material-ui/core/Link"
import Drawer from "@material-ui/core/Drawer"
import List from "@material-ui/core/List"
import ListItem from "@material-ui/core/ListItem"
import ListItemText from "@material-ui/core/ListItemText"

export default function MuiDrawer() {
  return (
      &amp;lt;Drawer variant="permanent" anchor="left"&amp;gt;
        &amp;lt;List&amp;gt;
          &amp;lt;ListItem button component={Link} to="/"&amp;gt;
            &amp;lt;ListItemText primary="Home" /&amp;gt;
          &amp;lt;/ListItem&amp;gt;
          &amp;lt;ListItem button component={Link} to="/404"&amp;gt;
            &amp;lt;ListItemText primary="404" /&amp;gt;
          &amp;lt;/ListItem&amp;gt;
        &amp;lt;/List&amp;gt;
      &amp;lt;/Drawer&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  The Solution:
&lt;/h2&gt;

&lt;p&gt;To set the Active ListItem in the Material-UI Drawer, we can use the &lt;code&gt;selected&lt;/code&gt; prop. To make this as clean as possible, we should make a custom ListItem. Here's what it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  let CustomListItem = ({ to, primary }) =&amp;gt; (
    &amp;lt;ListItem
      button
      component={Link}
      to={to}
      selected={to === location.pathname}
    &amp;gt;
      &amp;lt;ListItemText primary={primary} /&amp;gt;
    &amp;lt;/ListItem&amp;gt;
  )
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can render our CustomListItem as follows, which will automatically set the Drawer ActiveItem based on the browser's location.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;CustomListItem to="/" primary="Home Page" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Code
&lt;/h2&gt;

&lt;p&gt;Here's how the Drawer looks in its final form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react"
import { Link } from "gatsby"
import { useLocation } from "@reach/router"
import Drawer from "@material-ui/core/Drawer"
import List from "@material-ui/core/List"
import ListItem from "@material-ui/core/ListItem"
import ListItemText from "@material-ui/core/ListItemText"

export default function BarebonesDrawer({ children }) {
  const location = useLocation()

  let CustomListItem = ({ to, primary }) =&amp;gt; (
    &amp;lt;ListItem
      button
      component={Link}
      to={to}
      selected={to === location.pathname}
    &amp;gt;
      &amp;lt;ListItemText primary={primary} /&amp;gt;
    &amp;lt;/ListItem&amp;gt;
  )

  return (
      &amp;lt;Drawer variant="permanent" anchor="left"&amp;gt;
        &amp;lt;List&amp;gt;
          &amp;lt;CustomListItem to="/" primary="Home Page" /&amp;gt;
          &amp;lt;CustomListItem to="/404" primary="404 Page" /&amp;gt;
        &amp;lt;/List&amp;gt;
      &amp;lt;/Drawer&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Finished Product
&lt;/h2&gt;

&lt;p&gt;Link: &lt;a href="https://codesandbox.io/s/github/SnappyWebDesign/Material-UI_Active_ListItem_Tutorial/tree/main/?file=/src/components/DrawerDemo.js"&gt;https://codesandbox.io/s/github/SnappyWebDesign/Material-UI_Active_ListItem_Tutorial/tree/main/?file=/src/components/DrawerDemo.js&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Styled Material-UI Drawer
&lt;/h2&gt;

&lt;p&gt;Need a quick copy and paste? Here's the code for the styled Drawer in the demo above:&lt;br&gt;&lt;br&gt;
&lt;a href="https://github.com/SnappyWebDesign/Material-UI_Active_ListItem_Tutorial/blob/main/src/components/DrawerDemo.js"&gt;View on Github&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Did you find this article helpful?
&lt;/h3&gt;

&lt;p&gt;If you did, would you take a second to share the article by clicking below? It helps our cause immensely!  &lt;/p&gt;

&lt;p&gt;Make sure to also click the follow button to get notified when new posts go live 🔔&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>react</category>
      <category>webdev</category>
      <category>materialui</category>
    </item>
    <item>
      <title>Gatsby Code Splitting</title>
      <dc:creator>Snappy Web Design</dc:creator>
      <pubDate>Mon, 05 Jul 2021 20:22:45 +0000</pubDate>
      <link>https://forem.com/snappywebdesign/gatsby-code-splitting-399h</link>
      <guid>https://forem.com/snappywebdesign/gatsby-code-splitting-399h</guid>
      <description>&lt;p&gt;Modern web apps are now thought of as &lt;em&gt;bundles of modules&lt;/em&gt; interacting with each other to create functions/features. &lt;em&gt;Bundling&lt;/em&gt; is the process of merging code into one "bundle" (think: script/file) to deliver to the user. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Splitting&lt;/strong&gt; converts these 'bundles' from one file to many, which can further dramatically improve performance by &lt;strong&gt;lazy-loading&lt;/strong&gt; just the parts of your site that the user needs. &lt;/p&gt;

&lt;h4&gt;
  
  
  Code Bundling Example (before code splitting):
&lt;/h4&gt;

&lt;p&gt;Raw Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /pages/Index.js
import { add } from '../components/math.js'

console.log(add(15, 15)); // 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// /components/math.js
export function add(a, b) {
  return a + b;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bundled Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function add(a, b) {
  return a + b;
}

console.log(add(15, 15)); // 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, &lt;em&gt;bundling&lt;/em&gt; is the process of merging your imported files/"modules" into one "bundle". While this is great, it can lead to long load times as your as your application grows in size with added pages and functions.&lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Code Splitting&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can speed up your site by only loading what the user needs rather than delivering the entire application at once.&lt;br&gt;
E.g., by only loading the components that are ON the page the user is viewing. &lt;/p&gt;

&lt;p&gt;One thing that makes Gatsby powerful is that it does this for you. Gatsby automatically and intelligently code-splits bundles when you run &lt;code&gt;gatsby build&lt;/code&gt;. However, it does so in a specific manner. For example:&lt;/p&gt;

&lt;p&gt;Imagine your website has two pages: a Landing Page and a Contact Page. Each page has 2 unique components; 4 in total:&lt;/p&gt;

&lt;p&gt;-- &lt;strong&gt;Landing Page&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hero.js (Component)&lt;/li&gt;
&lt;li&gt;Services.js (Component)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;-- &lt;strong&gt;Contact Page&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ContactInfo.js (Component)&lt;/li&gt;
&lt;li&gt;ContactForm.js (Component)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a traditional React app, a user who visits the Landing page will download a bundle containing &lt;em&gt;all&lt;/em&gt; of the components -- Hero, Services, ContactInfo and ContactForm -- despite only needing the Hero and Services components to correctly display the landing page. &lt;/p&gt;

&lt;p&gt;Multiply this by say, 10 pages, and you've got an issue on your hands - you're serving a 10 MB payload for a 1 MB page.&lt;/p&gt;

&lt;p&gt;This is how Gatsby approaches code-splitting: &lt;strong&gt;on a page-by-page basis.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This strength of Gatsby can also be a real downside when creating a &lt;strong&gt;single-page site&lt;/strong&gt;. Since Gatsby splits bundles up by page, you'll end up delivering an unnecessarily massive payload to the client, slowing down your Largest Contentful Paint / initial load times.&lt;/p&gt;

&lt;p&gt;So...the solution?&lt;/p&gt;


&lt;h3&gt;
  
  
  &lt;strong&gt;Code Splitting Components instead of Pages&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Code-splitting helps you lazy-load only what the user needs and reduce initial load times without modifying the quantity of code you've written.&lt;/p&gt;

&lt;p&gt;The React team created React.lazy and Suspense for implementation of this but, unfortunately, neither are compatible with server side rendering/Gatsby. &lt;/p&gt;

&lt;p&gt;Instead, they recommend using a library called &lt;a href="https://github.com/gregberge/loadable-components"&gt;Loadable Components&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Using Loadable-Components with Gatsby&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Code-splitting components with &lt;a href="https://loadable-components.com/docs/getting-started/"&gt;Loadable-Components&lt;/a&gt; in Gatsby is simple. Start by installing dependencies&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @loadable/component
# or use yarn
yarn add @loadable/component
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, on any page you wish to lazy-load a component:&lt;/p&gt;

&lt;p&gt;Change:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import Hero from '../components/Hero'
import Services from '../components/Services'

export default function LandingPage() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Hero /&amp;gt;
      &amp;lt;Services /&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import loadable from '@loadable/component'

import Hero from '../components/Hero'
const Services = loadable(() =&amp;gt; import('../components/Services'))

export default function LandingPage() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Hero /&amp;gt;
      &amp;lt;Services /&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's all! &lt;code&gt;Services.js&lt;/code&gt; will now be loaded in its own bundle, separate from the one containing &lt;code&gt;Hero.js&lt;/code&gt;. As you see in this example, one method of using loadable-components for a single page site is importing content &lt;em&gt;above the fold&lt;/em&gt; normally, and lazy loading content below it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bonus: Specifying a Fallback without Suspense&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you lazy-load a component, you're deferring it on the initial page load. Therefore, there will be a short period of time where your content is not visible. You can display a placeholder during that period:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import loadable from '@loadable/component'

import Hero from '../components/Hero'
const Services = loadable(() =&amp;gt; import('../components/Services'), {
  fallback: &amp;lt;div&amp;gt;Loading...&amp;lt;/div&amp;gt;,
})

export default function LandingPage() {
  return (
    &amp;lt;div&amp;gt;
      &amp;lt;Hero /&amp;gt;
      &amp;lt;Services /&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The word "Loading..." will now display until your component is rendered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Did you find this article helpful?
&lt;/h3&gt;

&lt;p&gt;If you did, would you take a second to share the article by clicking below? It helps our cause immensely!  &lt;/p&gt;

&lt;p&gt;Make sure to also click the follow button to get notified when new posts go live 🔔&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>webpack</category>
    </item>
    <item>
      <title>Add a "Copy Link to Clipboard" button to your website in 10 lines of code</title>
      <dc:creator>Snappy Web Design</dc:creator>
      <pubDate>Sat, 03 Jul 2021 14:55:09 +0000</pubDate>
      <link>https://forem.com/snappywebdesign/add-a-copy-link-to-clipboard-button-to-your-website-in-10-lines-of-code-3l75</link>
      <guid>https://forem.com/snappywebdesign/add-a-copy-link-to-clipboard-button-to-your-website-in-10-lines-of-code-3l75</guid>
      <description>&lt;p&gt;Providing your users an easy way to share your blog posts is an SEO no brainer. Using the default &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Navigator"&gt;Navigator api&lt;/a&gt; &lt;code&gt;[navigator.clipboard.writeText]&lt;/code&gt; is a common approach, but lacks mobile support.&lt;/p&gt;

&lt;p&gt;The best way to copy selected text to the clipboard is by creating a hidden textarea. Luckily, all you need to do is copy the following code:&lt;/p&gt;

&lt;h3&gt;
  
  
  HTML/JSX:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Button
  variant="contained"
  size="large"
  onClick={() =&amp;gt; {
    CopyToClipboard(window.location.href)
  }}
&amp;gt;
  Copy Link to Clipboard
&amp;lt;/Button&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Javascript:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const CopyToClipboard = toCopy =&amp;gt; {
  const el = document.createElement(`textarea`)
  el.value = toCopy
  el.setAttribute(`readonly`, ``)
  el.style.position = `absolute`
  el.style.left = `-9999px`
  document.body.appendChild(el)
  el.select()
  document.execCommand(`copy`)
  document.body.removeChild(el)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Demo:
&lt;/h2&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/copy-link-to-clipboard-button-8zlrs"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;You can easily extend this by displaying an alert to give users success feedback. An example of how this could be done in Material-UI is with a Snackbar and a piece of state to control the snackbar.&lt;br&gt;
Check out the &lt;a href="https://snappywebdesign.net/blog/how-to-code-a-copy-link-to-clipboard-button"&gt;full post&lt;/a&gt; on &lt;a href="https://snappywebdesign.net"&gt;https://snappywebdesign.net&lt;/a&gt; to see how.&lt;/p&gt;




&lt;h3&gt;
  
  
  Did you find this article helpful?
&lt;/h3&gt;

&lt;p&gt;If you did, would you take a second to share the article? It helps our cause immensely!&lt;br&gt;
Make sure to also click the follow button to get notified when new posts go live 🔔&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
      <category>gatsby</category>
    </item>
    <item>
      <title>How to Code a Dark Theme with Material UI</title>
      <dc:creator>Snappy Web Design</dc:creator>
      <pubDate>Tue, 15 Jun 2021 23:43:56 +0000</pubDate>
      <link>https://forem.com/snappywebdesign/how-to-code-a-dark-theme-with-material-ui-1iim</link>
      <guid>https://forem.com/snappywebdesign/how-to-code-a-dark-theme-with-material-ui-1iim</guid>
      <description>&lt;p&gt;&lt;strong&gt;Dark mode&lt;/strong&gt; is a feature that users &lt;a href="https://www.searchenginewatch.com/2020/09/30/why-dark-mode-web-designs-are-gaining-popularity/"&gt;can't get enough of&lt;/a&gt;. It saves battery life, reduces eye strain, and minimizes blue light emissions. It's a simple feature that as a developer (all else equal), will set you apart far and wide from your competition. To boot, &lt;a href="https://material-ui.com/getting-started/installation/"&gt;Material-UI&lt;/a&gt; supports dark/light themes out of the box, making it a great framework to build on. Despite this, due to dark mode's relative infancy in the web development world, there is a distinct lack of documentation and tutorials on how to &lt;em&gt;actually&lt;/em&gt; code dark &amp;amp; light modes.  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article was originally published on &lt;a href="https://snappywebdesign.net/blog/how-to-code-a-dark-theme-with-material-ui"&gt;Snappy Web Design&lt;/a&gt;&lt;/em&gt;  &lt;/p&gt;

&lt;h2&gt;
  
  
  In this Material-UI tutorial, you'll learn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;How to use localStorage to save a user's theme preference&lt;/li&gt;
&lt;li&gt;How to use Material-UI to apply a dark theme and light theme&lt;/li&gt;
&lt;li&gt;How to use &lt;a href="https://www.gatsbyjs.com/docs/reference/config-files/"&gt;Gatsby's&lt;/a&gt; &lt;code&gt;gatsby-browser&lt;/code&gt; and &lt;code&gt;gatsby-ssr&lt;/code&gt; to avoid css style conflicts on rehydration with server side rendering (SSR) &lt;/li&gt;
&lt;li&gt;How to use a single Mui Theme file to serve both dark/light theme variants ("&lt;a href="https://en.wikipedia.org/wiki/Single_source_of_truth"&gt;single source of truth&lt;/a&gt;")&lt;/li&gt;
&lt;li&gt;How to use &lt;a href="https://reactjs.org/docs/hooks-reference.html"&gt;React's&lt;/a&gt; &lt;code&gt;useReducer&lt;/code&gt;, &lt;code&gt;useContext&lt;/code&gt;, &lt;code&gt;createContext&lt;/code&gt;, and &lt;code&gt;Context.Provider&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why this Tutorial?
&lt;/h3&gt;

&lt;p&gt;Although there are other tutorials on the web and the documentation for Material-UI is normally stout, you've probably found while researching tutorials on dark modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most tutorials show impractical / unorderly code that's difficult to reuse in your own project&lt;/li&gt;
&lt;li&gt;Material-UI's documentation falls short of demonstrating how to update the theme live - it only briefly touches on 'dark' and 'light' theme types&lt;/li&gt;
&lt;li&gt;Incomplete examples lead to &lt;strong&gt;Flashes of Unstyled Content&lt;/strong&gt; (&lt;a href="https://en.wikipedia.org/wiki/Flash_of_unstyled_content"&gt;FOUC&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Gatsby's &lt;strong&gt;Server Side Rendering&lt;/strong&gt; (&lt;a href="https://www.gatsbyjs.com/docs/glossary/server-side-rendering/"&gt;SSR&lt;/a&gt;) leads to FOUC&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What's the finished product?
&lt;/h3&gt;

&lt;p&gt;You can view the final code here:   &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://mui-dark-mode.vercel.app/"&gt;Live Deployed Site&lt;/a&gt;&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://codesandbox.io/s/material-ui-dark-mode-with-gatsby-and-usereducer-cr5ml?file=/src/pages/index.js"&gt;View on CodeSandbox&lt;/a&gt;&lt;/strong&gt;   &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/SnappyWebDesign/material-ui-dark-mode"&gt;View the Github Repo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;...and here's how the final product will look and behave:  &lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/z7pyyvho21dm/BGict8bOTyxk77VE629Kr/13a4d9d7344a18a62d183441c4092c3c/2021-06-15_15-17-41_3.gif" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/z7pyyvho21dm/BGict8bOTyxk77VE629Kr/13a4d9d7344a18a62d183441c4092c3c/2021-06-15_15-17-41_3.gif" alt="2021-06-15 15-17-41 3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Structure
&lt;/h3&gt;

&lt;p&gt;Before we dive into the code, let's first look at the project structure (which is available on CodeSandbox).  &lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/z7pyyvho21dm/334oLglfK6VNU3dEsHYCFW/5ed8dbcd00a3ed36c278a8711f5f5f27/filestructure.jpg" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/z7pyyvho21dm/334oLglfK6VNU3dEsHYCFW/5ed8dbcd00a3ed36c278a8711f5f5f27/filestructure.jpg" alt="filestructure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You'll notice it looks similar to a typical Gatsby.js project with the exception of the &lt;code&gt;ThemeHandler.js&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ThemeHandler&lt;/strong&gt; will...well, handle whether to display a light or dark theme. It'll contain our useContext and useReducer functions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;gatsby-browser&lt;/strong&gt; wraps our application with our Context Provider. It allows our Gatsby site to have dynamic state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;gatsby-ssr&lt;/strong&gt; serves the same purpose: wrapping our application with our Context Provider to make it accessible everywhere in our app. It prevents &lt;strong&gt;flashes of unstyled content&lt;/strong&gt; with server-side rendering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layout&lt;/strong&gt; is where we'll initially check the user's local storage to see if they have a previously set theme. If not, we'll set it to the default of our choosing. We'll wrap our application with our Theme using the &lt;a href="https://material-ui.com/styles/api/#themeprovider"&gt;Material-UI ThemeProvider.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Index&lt;/strong&gt; does the least amount of work but the most important. It contains the button to toggle the dark/light theme and does so with an onClick function. This dispatches a function via our reducer to change the theme and sets the local storage to the user's newly-preferred theme.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Theme&lt;/strong&gt; contains our:&lt;br&gt;&lt;br&gt;
&lt;strong&gt;1. Base theme&lt;/strong&gt;, styles to be applied globally across both light &lt;em&gt;and&lt;/em&gt; dark modes.&lt;br&gt;&lt;br&gt;
&lt;strong&gt;2. Dark theme&lt;/strong&gt;, styles applied when dark mode is active, and lastly, our&lt;br&gt;&lt;br&gt;
&lt;strong&gt;3. Light theme&lt;/strong&gt;, containing styles to be applied when the light mode is active.&lt;/p&gt;

&lt;p&gt;&lt;a href="//images.ctfassets.net/z7pyyvho21dm/4E2usnlx5XXU2uJBRrqj04/6457dd94a150ed34290c20169b3cfe98/Untitled_Diagram.jpg" class="article-body-image-wrapper"&gt;&lt;img src="//images.ctfassets.net/z7pyyvho21dm/4E2usnlx5XXU2uJBRrqj04/6457dd94a150ed34290c20169b3cfe98/Untitled_Diagram.jpg" alt="Untitled Diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're a visual learner, I hope that diagram gives you a mental picture of where we're headed.&lt;/p&gt;


&lt;h3&gt;
  
  
  Theme.js
&lt;/h3&gt;

&lt;p&gt;One of the reasons why I think this approach is the best is because it has a &lt;em&gt;single source of truth.&lt;/em&gt; Unlike other tutorials, we only use &lt;strong&gt;one theme&lt;/strong&gt;, yet we provide multiple styles. We do it by nesting our themes: we define our global styles for both light and dark modes, and then spread that across our styles for our separate light and dark themes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { createMuiTheme } from "@material-ui/core/styles"

const baseTheme = createMuiTheme({
  typography: {
    fontFamily: "'Work Sans', sans-serif",
    fontSize: 14,
    fontFamilySecondary: "'Roboto Condensed', sans-serif"
  }
})

const darkTheme = createMuiTheme({
  ...baseTheme,
  palette: {
    type: "dark",
    primary: {
      main: "#26a27b"
    },
    secondary: {
      main: "#fafafa"
    }
  }
})
const lightTheme = createMuiTheme({
  ...baseTheme,
  palette: {
    type: "light",
    primary: {
      main: "#fafafa"
    },
    secondary: {
      main: "#26a27b"
    }
  }
})

export { darkTheme, lightTheme }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now our theme is set up for us to later import it like&lt;br&gt;&lt;br&gt;
&lt;code&gt;import { darkTheme, lightTheme } from "./Theme"&lt;/code&gt;&lt;br&gt;&lt;br&gt;
Eventually, we'll make use of Material-UI's theme provider and pass in our theme dynamically:&lt;br&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;ThemeProvider theme={darkMode ? darkTheme : lightTheme}&amp;gt;&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;For now though, let's work on our ThemeHandler.&lt;/p&gt;


&lt;h3&gt;
  
  
  ThemeHandler.js
&lt;/h3&gt;

&lt;p&gt;Our objective is simple: create a state value for &lt;code&gt;darkMode&lt;/code&gt;, set it false initially, and be able to access and update our state from anywhere within our Gatsby application.  &lt;/p&gt;

&lt;p&gt;For this, we make use of React's createContext, useReducer, and ContextProvider.  &lt;/p&gt;

&lt;p&gt;First up, we need to import &lt;code&gt;createContext&lt;/code&gt; and &lt;code&gt;useReducer&lt;/code&gt;, assign a variable as our action type which we'll use in our Reducer, and initialize our new Context:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { createContext, useReducer } from "react"
let SET_THEME

export const darkModeContext = createContext()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we'll create our &lt;strong&gt;useReducer&lt;/strong&gt; function. Essentially, we'll be calling a function to set darkMode either true or false. The reducer is a switch statement to feed this value to our global state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { createContext, useReducer } from "react"
let SET_THEME

export const darkModeContext = createContext()

export const darkModeReducer = (state, action) =&amp;gt; {
  switch (action.type) {
    case SET_THEME:
      return {
        ...state,
        darkMode: action.payload
      }
    default:
      return state
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we'll create and export our DarkModeState function. We'll set our initial state (set dark mode to false on first load) in addition to initializing our dispatch function using the reducer we just created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { createContext, useReducer } from "react"
let SET_THEME

export const darkModeContext = createContext()

export const darkModeReducer = (state, action) =&amp;gt; {
  switch (action.type) {
    case SET_THEME:
      return {
        ...state,
        darkMode: action.payload
      }
    default:
      return state
  }
}

export const DarkModeState = props =&amp;gt; {
  const initialState = {
    darkMode: "false"
  }
  const [state, dispatch] = useReducer(darkModeReducer, initialState)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we'll create our function (&lt;code&gt;setDarkMode&lt;/code&gt;) to update our state. It uses the dispatch function which feeds into our reducer's switch statement.&lt;br&gt;&lt;br&gt;
We return our &lt;code&gt;darkModeContext.Provider&lt;/code&gt; which makes both the &lt;strong&gt;darkMode&lt;/strong&gt; state, and the &lt;strong&gt;setDarkMode&lt;/strong&gt; function available globally across our app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { createContext, useReducer } from "react"
let SET_THEME

export const darkModeContext = createContext()

export const darkModeReducer = (state, action) =&amp;gt; {
  switch (action.type) {
    case SET_THEME:
      return {
        ...state,
        darkMode: action.payload
      }
    default:
      return state
  }
}

export const DarkModeState = props =&amp;gt; {
  const initialState = {
    darkMode: "false"
  }
  const [state, dispatch] = useReducer(darkModeReducer, initialState)

  const setDarkMode = async bool =&amp;gt; {
    dispatch({
      type: SET_THEME,
      payload: bool
    })
  }

  return (
    &amp;lt;darkModeContext.Provider
      value={{
        darkMode: state.darkMode,
        setDarkMode
      }}
    &amp;gt;
      {props.children}
    &amp;lt;/darkModeContext.Provider&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🔧 Fixing Gatsby's Rehydration Issue
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;WARNING:&lt;/strong&gt; Do not skip this step or you will waste hours of your life debugging. I wasted two days debugging flashes of unstyled content the first time I implemented dark mode - learn from my mistakes.  &lt;/p&gt;

&lt;p&gt;Because Gatsby builds pages long before they're rendered and served to the end-user's web browser, we have to take a couple additional steps when using dynamic state values.   &lt;/p&gt;

&lt;p&gt;If you want to read more about server-side rendering and Gatsby's webpack -- be my guest. In fact, you probably should read about Gatsby's &lt;a href="https://www.gatsbyjs.com/docs/reference/config-files/gatsby-browser/"&gt;Browser APIs&lt;/a&gt;. But for sake of brevity, let me sum it up like this:  &lt;/p&gt;

&lt;p&gt;You need to wrap every page with your React.useState component in Gatsby. Luckily, we can use Gatsby's built in API via the &lt;code&gt;gatsby-browser.js&lt;/code&gt; and &lt;code&gt;gatsby-ssr.js&lt;/code&gt; files. The syntax and content of the files are the exact same:  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;gatsby-browser.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react"
import { DarkModeState } from "./src/components/UI/ThemeHandler"

export function wrapRootElement({ element, props }) {
  return &amp;lt;DarkModeState {...props}&amp;gt;{element}&amp;lt;/DarkModeState&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;gatsby-ssr.js&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react"
import { DarkModeState } from "./src/components/UI/ThemeHandler"

export function wrapRootElement({ element, props }) {
  return &amp;lt;DarkModeState {...props}&amp;gt;{element}&amp;lt;/DarkModeState&amp;gt;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Layout.js
&lt;/h3&gt;

&lt;p&gt;We're almost to the end! The Layout provides our styles to the rest of our app via &lt;a href="https://material-ui.com/styles/api/#themeprovider"&gt;Material-UI's ThemeProvider.&lt;/a&gt;. Our approach (from a high-level) is:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Import our light/dark themes&lt;/li&gt;
&lt;li&gt;Import our theme handler (&lt;code&gt;darkModeContext&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Check the users localStorage to see if a preferred theme is already set in a &lt;code&gt;useEffect&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;If not, set the users preferred theme to the default (darkMode: false)&lt;/li&gt;
&lt;li&gt;Wrap our component with our dynamic theme (either light or dark) via the &lt;code&gt;ThemeProvider&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Importantly, we need to also import and include the &lt;code&gt;&amp;lt;CssBaseline /&amp;gt;&lt;/code&gt; component from Material-UI for the ThemeProvider to work.  &lt;/p&gt;

&lt;p&gt;The code for this is hardly worth elaborating on, so I'll let it speak for itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useContext, useEffect } from "react"
import CssBaseline from "@material-ui/core/CssBaseline"
import { ThemeProvider } from "@material-ui/core/styles"
import { darkTheme, lightTheme } from "./Theme"
import { darkModeContext } from "./ThemeHandler"

const Layout = ({ children }) =&amp;gt; {
  const DarkModeContext = useContext(darkModeContext)
  const { darkMode, setDarkMode } = DarkModeContext

  useEffect(() =&amp;gt; {
    const theme = localStorage.getItem("preferred-theme")
    if (theme) {
      const themePreference = localStorage.getItem("preferred-theme")
      if (themePreference === "dark") {
        setDarkMode(true)
      } else {
        setDarkMode(false)
      }
    } else {
      localStorage.setItem("preferred-theme", "light")
      setDarkMode(true)
    }
  }, [])

  return (
    &amp;lt;ThemeProvider theme={darkMode ? darkTheme : lightTheme}&amp;gt;
      &amp;lt;CssBaseline /&amp;gt;
      &amp;lt;main&amp;gt;{children}&amp;lt;/main&amp;gt;
    &amp;lt;/ThemeProvider&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Index.js (The final step!)
&lt;/h3&gt;

&lt;p&gt;If you've made it this far, pat yourself on the back. This is the final (and simplest) step before you'll have a functioning dark mode toggle.   &lt;/p&gt;

&lt;p&gt;Let's not waste any more time.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;First, we need to wrap our Index Page with our Layout component.&lt;/li&gt;
&lt;li&gt;Then, we need to create a button to toggle the theme&lt;/li&gt;
&lt;li&gt;We need to create an onClick function for the button, &lt;code&gt;handleThemeChange&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Inside the function, we update &lt;code&gt;localStorage&lt;/code&gt; and &lt;code&gt;setDarkMode&lt;/code&gt; either true or false using our Context Provider:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React, { useContext } from "react"
import Layout from "../components/UI/Layout"
import Button from "@material-ui/core/Button"
import { darkModeContext } from "../components/UI/ThemeHandler"

const IndexPage = () =&amp;gt; {
  const DarkModeContext = useContext(darkModeContext)
  const { darkMode, setDarkMode } = DarkModeContext

  const handleThemeChange = () =&amp;gt; {
    if (darkMode) {
      localStorage.setItem("preferred-theme", "light")
      setDarkMode(false)
    } else {
      localStorage.setItem("preferred-theme", "dark")
      setDarkMode(true)
    }
  }

  return (
    &amp;lt;Layout&amp;gt;
        &amp;lt;Button
          variant="contained"
          color="secondary"
          size="medium"
          onClick={handleThemeChange}
        &amp;gt;
          Toggle {darkMode ? "Light" : "Dark"} Theme
        &amp;lt;/Button&amp;gt;
    &amp;lt;/Layout&amp;gt;
  )
}

export default IndexPage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Boom! Just like that, you have a toggleable dark/light mode with Gatsby and Material-UI.&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Finished Product
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://mui-dark-mode.vercel.app/"&gt;Live Deployed Site&lt;/a&gt;&lt;/strong&gt;  &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://codesandbox.io/s/material-ui-dark-mode-with-gatsby-and-usereducer-cr5ml?file=/src/pages/index.js"&gt;View on CodeSandbox&lt;/a&gt;&lt;/strong&gt;   &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/SnappyWebDesign/material-ui-dark-mode"&gt;View the Github Repo&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Did you find this article helpful?
&lt;/h3&gt;

&lt;p&gt;If you read this whole article, &lt;strong&gt;thank you&lt;/strong&gt;. I hope you learned something valuable.  &lt;/p&gt;

&lt;p&gt;If you did, would you take a second to share the article by clicking below? It helps our cause immensely!  &lt;/p&gt;

&lt;p&gt;Make sure to also click the follow button to get notified when new posts go live 🔔&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>react</category>
      <category>design</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
