Open shuding opened 2 years ago
You can set theme-color
to a CSS variable, which will update correctly on Safari! On iOS it will update instantly alongside changes to the CSS variable, on macOS it will only update when you refocus the tab.
<meta name="theme-color" content="var(--bg)">
If we were to add it to next-themes (and not use the CSS variable trick above), how we would determine which color to set? Maybe consumers could provide a --theme-color
CSS variable, which next-themes would read the current value of (getComputedStyle
) and update the meta tag accordingly.
Oh I didn’t know that it works with variables, then it almost solves my problem.
If building this into the lib, I can see a themeColor
option with these possible values:
themeColor: { dark: '#000', light: '#fff' }
: provide the theme color for each themethemeColor: 'red'
: always use this theme colorthemeColor: 'var(—-bg)'
: if using a variable, we can compute the color upon every theme change. The variable needs to be specified at the root level themeColor: { dark: 'var(—-bg)', reduced: '#fff' }
: mixed use case too@pacocoursey Using the meta tag method you mentioned doesn't seem to be working in the latest Safari/iOS. I still need to refresh the page to see the browser theme change.
I'm setting the css variable like this (I use class mode with Tailwind):
html { --bg: white; }
html.dark { --bg: black; }
Any suggestions?
Facing the same thing myself.
Since the CSS variable trick no longer seems to work, I'd recommend implementing this manually in your code with something like this:
const { resolvedTheme } = useTheme();
return (
<Head>
<meta name="theme-color" value={resolvedTheme === 'dark' ? '#000' : '#fff'}
</Head>
)
I plan to add this for v1 of next-themes though, and I like the API that @shuding suggested above!
<ThemeProvider
themeColor={{ dark: '#000', light: '#fff' }}
// or
themeColor="var(--theme-color)" // vars must be on the same element as data-theme is applied, which right is now always html aka :root
// or
themeColor={{ dark: 'var(--dark-bg)', light: '#fff' }}
/>
This is available in the v1 beta:
yarn add next-themes@beta
Hi @pacocoursey , when v1 release? like this feature.
@pacocoursey v1 is not published on NPM.
i solve this problem using this approach:
const { resolvedTheme } = useTheme();
useEffect(() => {
let themeColorMeta = document.querySelector(
'meta[name="theme-color"]',
) as HTMLMetaElement;
if (!themeColorMeta) {
themeColorMeta = document.createElement('meta');
themeColorMeta.name = 'theme-color';
document.head.appendChild(themeColorMeta);
}
themeColorMeta.content = resolvedTheme === 'dark' ? '#171717' : '#fff';
}, [resolvedTheme]);
may this help!
For Next.js 13 app router
app/layout.tsx
export const metadata = {
// ...
themeColor: '#f8fafc',
}
export default RootLayout() {
<html suppressHydrationWarning className="dark">
<head>
<script
dangerouslySetInnerHTML={{
__html: `
try {
if (localStorage.theme === 'dark' || ((!('theme' in localStorage) || localStorage.theme === 'system') && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0B1120')
}
} catch (_) {}
`,
}}
/>
</head>
</html>
}
components/toggle-theme.tsx
const { resolvedTheme } = useTheme()
useEffect(() => {
if (resolvedTheme === 'dark') {
document
.querySelector('meta[name="theme-color"]')!
.setAttribute('content', '#0B1120')
} else {
document
.querySelector('meta[name="theme-color"]')!
.setAttribute('content', '#f8fafc')
}
}, [resolvedTheme])
refer https://github.com/tailwindlabs/tailwindcss.com/blob/master/src/pages/_document.js#L31
Is a fix being worked on for this so we don’t need to add custom logic to ensure automatic color switching on Safari?
@shawnlong636 Could you elaborate? Do you have the issue with the v1 branch?
confirming this is working for me with the 1.0.0-beta.0
release
is there any plan to release that as a full version? happy to help test, it looks like the changes are fairly small
Any timeline on when v1 will be released?
This one did not make it to v0.3.0? 🤔 I'm still targeting the beta in my project ( "next-themes": "1.0.0-beta.0", ) which is not ideal. Hoping to see v1 soon! Or just this particular very needed feature in v0.3.1 😉
Planning to add this in v1, which is still upcoming.
@pacocoursey Hi there! How to achieve the proposed themeColor
solution? I've installed next-themes@beta, current version 0.3.0-beta.1
, but it seems <ThemeProvider />
has no themeColor
props.
@monecchi you can do something like this:
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider
attribute="class"
themes={[
"light",
"dark",
]}
themeColor={{
light: "hsl(0 0% 100%)",
dark: "hsl(216 13% 15%)",
}}
>
<SidebarLeftMobileProvider>
<SidebarRightMobileProvider>
<UserProvider>{children}</UserProvider>
</SidebarRightMobileProvider>
</SidebarLeftMobileProvider>
</ThemeProvider>
);
}
I'm using "next-themes": "1.0.0-beta.0",
Thanks @spacecat! I'll give it a try! It seems the beta version I installed 0.3.0-beta.1
might be the issue...
Also, thanks @NavOrange! I've tested your solution and it worked flawlessly! While developing a PWA with the Window Controls Overlay feature enabled in manifest.json
(on Desktop), the window native controls background color inherits the theme-color
value, so switching the theme (light / dark) was breaking the UI. That saved my day!
@spacecat yes, most likely it has got to do with the npm package version.
Hi @pacocoursey ,
just following up on this issue as I'm currently upgrading all of my npm packages in my project.
I was just wondering if you see this feature included in a stable release some time in the near future?
Thanks!
Safari 15 uses this meta tag to indicate the UI color of the address bar etc., and usually we need to switch it upon theme changes. The media query only works with the system preferences rather than per-site settings via next-themes, so it might be a good add-on for this lib to automatically update it.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta/name/theme-color