Introduction
I was building a fresh website for my local church group recently. Naturally, I went with Next.js. Between the free hosting on Vercel, the clean Hero UI components, and what I genuinely believe is the best CMS available, Payload CMS, it just made sense. Chef’s kiss 🤌.
As I moved through the build, I hit a small but annoying detail. The favicon I used looked decent in light mode, but in dark mode it lost contrast and became practically invisible. That led me to a simple but effective solution: dynamic favicons based on the user's theme.
TLDR
- Generate two favicons, one for light mode and one for dark mode. Real Favicon Generator worked great for me.
- Place them somewhere like
/public/images/seo/
. Generally anywhere within the public directory will do. Just take note of where you put them - Dynamically assign them using
prefers-color-scheme
in the metadata
export in your layout.(jsx | tsx) file. See the code snippet below
Assumptions
You're already familiar with Next.js, using the App Router, and you’ve got theme toggle logic in place. If you're still setting up Hero UI, check their installation docs.
Step-by-Step Setup
1. Generate the Icons
Go to Real Favicon Generator and create two sets. One optimized for light backgrounds, the other for dark. I renamed mine to favicon-light.svg
and favicon-dark.svg
so I wouldn’t mix them up.
2. Organize Your Files
I dropped both icons in the /public/images/seo/
folder, but use whatever directory you like as long as its within the public directory.
3. Add to the Metadata
In your layout.tsx
(or .js
), where you export the metadata
, add the following:
Next.js meta config
1export const metadata = {
2 title: "My Website",
3 icons: [
4 {
5 rel: "icon",
6 url: "/images/seo/favicon-light.svg",
7 media: "(prefers-color-scheme: light)",
8 },
9 {
10 rel: "icon",
11 url: "/images/seo/favicon-dark.svg",
12 media: "(prefers-color-scheme: dark)",
13 },
14 ],
15};
The media
attribute checks whether the user prefers a light or dark theme, then loads the right icon. You get automatic theme awareness without touching extra JavaScript.
Final Thoughts
It's a small change, but it makes your site feel much more thoughtful. Especially when building for a group like a church or community project, that level of detail shows care.
If this helped, you might enjoy some of the other things I’m building: