Skip to content

Commit

Permalink
set theme data- attributes on the body (github#30054)
Browse files Browse the repository at this point in the history
* set theme data- attributes on the body

* Color mode back on body tag

* unconflicted

Co-authored-by: Kevin Heis <heiskr@users.noreply.github.com>
  • Loading branch information
peterbe and heiskr authored Aug 18, 2022
1 parent 4d6dbc3 commit 5d83a12
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 12 deletions.
44 changes: 34 additions & 10 deletions pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,37 @@ const MyApp = ({ Component, pageProps, languagesContext }: MyAppProps) => {
initializeExperiments()
}, [])

useEffect(() => {
// The CSS from primer looks something like this:
//
// @media (prefers-color-scheme: dark) [data-color-mode=auto][data-dark-theme=dark] {
// --color-canvas-default: black;
// }
// body {
// background-color: var(--color-canvas-default);
// }
//
// So if that `[data-color-mode][data-dark-theme=dark]` isn't present
// on the body, but on a top-level wrapping `<div>` then the `<body>`
// doesn't get the right CSS.
// Normally, with Primer you make sure you set these things in the
// `<body>` tag and you can use `_document.tsx` for that but that's
// only something you can do in server-side rendering. So,
// we use a hook to assure that the `<body>` tag has the correct
// dataset attribute values.
const body = document.querySelector('body')
if (body) {
// Note, this is the same as setting `<body data-color-mode="...">`
// But you can't do `body.dataset['color-mode']` so you use the
// camelCase variant and you get the same effect.
// Appears Next.js can't modify <body> after server rendering:
// https://stackoverflow.com/a/54774431
body.dataset.colorMode = theme.css.colorMode
body.dataset.darkTheme = theme.css.darkTheme
body.dataset.lightTheme = theme.css.lightTheme
}
}, [theme])

return (
<>
<Head>
Expand Down Expand Up @@ -56,16 +87,9 @@ const MyApp = ({ Component, pageProps, languagesContext }: MyAppProps) => {
nightScheme={theme.component.nightScheme}
preventSSRMismatch
>
{/* Appears Next.js can't modify <body> after server rendering: https://stackoverflow.com/a/54774431 */}
<div
data-color-mode={theme.css.colorMode}
data-light-theme={theme.css.lightTheme}
data-dark-theme={theme.css.darkTheme}
>
<LanguagesContext.Provider value={languagesContext}>
<Component {...pageProps} />
</LanguagesContext.Provider>
</div>
<LanguagesContext.Provider value={languagesContext}>
<Component {...pageProps} />
</LanguagesContext.Provider>
</ThemeProvider>
</SSRProvider>
</>
Expand Down
12 changes: 10 additions & 2 deletions pages/_document.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Document, { DocumentContext, Html, Head, Main, NextScript } from 'next/document'

import { ServerStyleSheet } from 'styled-components'

import { defaultCSSTheme } from 'components/hooks/useTheme'

export default class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
const sheet = new ServerStyleSheet()
Expand Down Expand Up @@ -32,7 +33,14 @@ export default class MyDocument extends Document {
return (
<Html>
<Head />
<body>
<body
// These values are always the SSR rendereding defaults.
// The will get updated later in a useEffect hook, in the client,
// in the MyApp component.
data-color-mode={defaultCSSTheme.colorMode}
data-light-theme={defaultCSSTheme.lightTheme}
data-dark-theme={defaultCSSTheme.darkTheme}
>
<Main />
<NextScript />
</body>
Expand Down

0 comments on commit 5d83a12

Please sign in to comment.