<?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>DEV Community: Olga Urentseva</title>
    <description>The latest articles on DEV Community by Olga Urentseva (@olgaurentseva).</description>
    <link>https://dev.to/olgaurentseva</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%2F968166%2F6fe33da1-921d-4052-96ec-c9d6179ca41b.jpeg</url>
      <title>DEV Community: Olga Urentseva</title>
      <link>https://dev.to/olgaurentseva</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/olgaurentseva"/>
    <language>en</language>
    <item>
      <title>Two Color Schemes, Four Modes: Native CSS Theme Switching.</title>
      <dc:creator>Olga Urentseva</dc:creator>
      <pubDate>Tue, 24 Feb 2026 21:42:55 +0000</pubDate>
      <link>https://dev.to/olgaurentseva/two-color-schemes-four-modes-native-css-theme-switching-17fo</link>
      <guid>https://dev.to/olgaurentseva/two-color-schemes-four-modes-native-css-theme-switching-17fo</guid>
      <description>&lt;p&gt;Frontend is finally moving toward vanillaization and that is the best thing that has happened to frontend since Wes Bos published his first courses. Native browser support for themes works absolutely fine and that can be enough for many projects, but I just wanted to have fun. I didn't want just one color scheme with light and dark variants. I wanted two, each supporting light and dark. Four variants in total. And the key is using native browser features. And it worked.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Requirements:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Light and dark mode, handled by the browser natively&lt;/li&gt;
&lt;li&gt;A second "spring" (or whatever) color scheme with a completely different palette&lt;/li&gt;
&lt;li&gt;A toggle button to switch between default and spring&lt;/li&gt;
&lt;li&gt;No flash of wrong theme on reload&lt;/li&gt;
&lt;li&gt;No page reload needed to switch&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Specificity Hack:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root:root:root&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use styled-components, you've probably run into specificity wars where your global CSS variables get overridden by styled-components' injected styles. The fix is delightfully dumb, just repeat :root three times. Yes, I know, styled-components is outdated,  so my future desire would be to get rid of it, but for now it is not the main topic of the conversation :)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root:root:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;light-dark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.99&lt;/span&gt; &lt;span class="m"&gt;0.0105&lt;/span&gt; &lt;span class="m"&gt;320.98&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;13.709%&lt;/span&gt; &lt;span class="m"&gt;0.02553&lt;/span&gt; &lt;span class="m"&gt;268.319&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="py"&gt;--color-primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;light-dark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;70.61%&lt;/span&gt; &lt;span class="m"&gt;0.085&lt;/span&gt; &lt;span class="m"&gt;271.69&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.79&lt;/span&gt; &lt;span class="m"&gt;0.1233&lt;/span&gt; &lt;span class="m"&gt;266.14&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="c"&gt;/* ...etc */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The browser picks the right value automatically based on the user's system preference. No JavaScript involved. You do still need color-scheme declared for this to work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// index.html
&lt;span class="cp"&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"theme-color"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"#ffffff"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"color-scheme"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"light dark"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Title&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"/src/main.tsx"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Important thing. For browsers that don't support light-dark() yet, keep &lt;a class="mentioned-user" href="https://dev.to/media"&gt;@media&lt;/a&gt; (prefers-color-scheme) fallback blocks below. The cascade handles it gracefully.&lt;/p&gt;

&lt;p&gt;But you probably notice that I just mentioned 2 themes of 1 color-scheme. And the whole approach above is something that was highly used before. But let's add another one. And it's gonna be tricky (not really).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Spring Theme: One CSS File, A Class on HTML Tag
&lt;/h3&gt;

&lt;p&gt;For the second theme, I wanted to avoid dynamic CSS imports, because they're async, unreliable in production builds with Vite, and add complexity. I tried it, didn't work well. Instead, decided that both themes should be in one CSS file.&lt;br&gt;
The spring theme overrides default variables using a .spring class on the  element. The key insight is specificity: .spring:root:root:root beats :root:root:root because of the extra class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nd"&gt;:root:root:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;light-dark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.99&lt;/span&gt; &lt;span class="m"&gt;0.0105&lt;/span&gt; &lt;span class="m"&gt;320.98&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.21&lt;/span&gt; &lt;span class="m"&gt;0.037&lt;/span&gt; &lt;span class="m"&gt;271.06&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="py"&gt;--color-primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;light-dark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;70.61%&lt;/span&gt; &lt;span class="m"&gt;0.085&lt;/span&gt; &lt;span class="m"&gt;271.69&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.79&lt;/span&gt; &lt;span class="m"&gt;0.1233&lt;/span&gt; &lt;span class="m"&gt;266.14&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* this one wins when .spring is on &amp;lt;html&amp;gt; */&lt;/span&gt;
&lt;span class="nc"&gt;.spring&lt;/span&gt;&lt;span class="nd"&gt;:root:root:root&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;light-dark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.99&lt;/span&gt; &lt;span class="m"&gt;0.012&lt;/span&gt; &lt;span class="m"&gt;150&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.18&lt;/span&gt; &lt;span class="m"&gt;0.05&lt;/span&gt; &lt;span class="m"&gt;145&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="py"&gt;--color-primary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;light-dark&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;56.316%&lt;/span&gt; &lt;span class="m"&gt;0.10067&lt;/span&gt; &lt;span class="m"&gt;150.907&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;oklch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0.72&lt;/span&gt; &lt;span class="m"&gt;0.2&lt;/span&gt; &lt;span class="m"&gt;145&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Light and dark still work automatically inside both themes and light-dark() keeps doing its job regardless of which theme is active.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Toggle
&lt;/h3&gt;

&lt;p&gt;classList.toggle() flips the class and returns the new boolean state. That's the entire toggle logic. No React state (or whatever you use), no context, no re-renders. The CSS reacts instantly because the class change is reflected immediately in the DOM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// UI component&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleToggle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isSpring&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spring&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSpring&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spring&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Applying the Right Theme on Load
&lt;/h3&gt;

&lt;p&gt;This runs synchronously before the first paint. No flash, no layout shift, no useEffect timing issues.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// main.tsx&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./themes.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;savedTheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documentElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spring&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;savedTheme&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;spring&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What I Tried That Didn't Work
&lt;/h3&gt;

&lt;p&gt;Before landing on this decision, I experimented with @container style() queries — a newer CSS feature that lets you apply styles based on the value of a custom property on a parent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@container&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;--theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;spring&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="py"&gt;--color-background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And it worked! But in Chrome. Not even in Firefox Developer Edition. Don't even talk about Safari. So I dropped it. But it is worth keeping an eye on for the future.  It would have been a much more elegant approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Result
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;One CSS file with all four theme variants (light default, dark default, light spring, dark spring)&lt;/li&gt;
&lt;li&gt;Zero JavaScript for color values, all colors live in CSS&lt;/li&gt;
&lt;li&gt;No React context or state for theming&lt;/li&gt;
&lt;li&gt;No page reload on toggle&lt;/li&gt;
&lt;li&gt;No flash of wrong theme on load&lt;/li&gt;
&lt;li&gt;Native browser dark mode support throughout&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>css</category>
      <category>frontend</category>
      <category>ui</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Netlify, Vite, deploy and “Page Not Found” error</title>
      <dc:creator>Olga Urentseva</dc:creator>
      <pubDate>Mon, 07 Nov 2022 22:48:07 +0000</pubDate>
      <link>https://dev.to/olgaurentseva/netlify-vite-deploy-and-page-not-found-error-54aj</link>
      <guid>https://dev.to/olgaurentseva/netlify-vite-deploy-and-page-not-found-error-54aj</guid>
      <description>&lt;p&gt;I know that a lot of people struggling with the problem when their web app works perfectly on localhost, but on Netlify server after refreshing page they got error “Page Not Found”. Why and how it should be fixed?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_kLVm45_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/toefn5qlee5irjx2afe6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_kLVm45_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/toefn5qlee5irjx2afe6.png" alt='"Page not found" netlify error' width="880" height="624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The key of this problem is not how Netlify works. Actually Netlify or something else is not matters, because it can be another server. The problem is the fact, that your server doesn’t know how to respond on your requests properly. Despite the fact that I’ll will refer to Netlify, you should keep in mind that it could be something else.&lt;/p&gt;

&lt;p&gt;How Netlify [server] saves your files? — There is a &lt;code&gt;dist&lt;/code&gt; directory with similar files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dist
  index.html
  hash.js
  icon.svg
  favicon.ico
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have a Netlify server and we don’t have access to it, we cannot directly code that if a request comes to a specific address, server must give this specific file. We simply don’t have such an opportunity. But all that our Netlify server has is &lt;code&gt;dist&lt;/code&gt; directory with bunch of files. So if there is a request to &lt;code&gt;https://netlify.app/icon.svg&lt;/code&gt;, our Netlify server should respond with a file icon.svg from dist as well. But what if we want to get &lt;code&gt;https://netlify.app/example/1&lt;/code&gt;? We do have this route in our SPA and everything works well on &lt;code&gt;localhost&lt;/code&gt;, but we we’ll get “Not Found Page” error. Why? Just because there is no that file in our &lt;code&gt;dist&lt;/code&gt; directory. Only thing that we have is &lt;code&gt;index.html&lt;/code&gt; so we have to set up &lt;code&gt;redirects&lt;/code&gt;, because we want to give responsibility of taking care of routes to SPA. So our server has to respond with &lt;code&gt;index.html&lt;/code&gt; if there is no file in &lt;code&gt;dist&lt;/code&gt; with matched name.&lt;/p&gt;

&lt;p&gt;There is a bunch of ways to do it and of course as I want you to remember, there is nothing specific to Netlify till next approach. But if you’re using Vite I also recommend you read this &lt;a href="https://vitejs.dev/guide/assets.html#the-public-directory"&gt;Public Folder Documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Well, if we’re considering Netlify, all I need is create &lt;code&gt;netlify.toml&lt;/code&gt; in project directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// netlify.toml
[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that’s it! Error is gone.&lt;/p&gt;

&lt;p&gt;Honestly I don’t really like this idea when I can not control the server and creating files such as &lt;code&gt;netlify.toml&lt;/code&gt; is the only way to hook “our” (not really our) server makes me awkward. But I guess this is another indicator that we need to move to something more low-level than Netlify, although it is really good for pet-projects.&lt;/p&gt;

&lt;p&gt;And thanks for reading :)&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
