Switching Themes
Yamada UI provides the functionality for users to switch themes.
To enable this feature, you need to prepare multiple themes.
Setup
To switch themes, users must do the following two things:
- Prepare multiple themes
- Add
ThemeSchemeScript
to the application.
Prepare multiple themes
This time, we will prepare several themes with colors changed from the default theme.
If you don't know how to customize themes, please check here.
Pass an object to themeSchemes
. The keys of this object will be the themeScheme
required to switch themes.
themeSchemes
overrides custom properties
using CSS's attribute selectors
. The custom properties
within the corresponding attribute selector
are referenced each time the themeScheme
switches.
import { extendTheme } from "@yamada-ui/react"export const theme = extendTheme({themeSchemes: {pink: {semantics: {colors: { primary: "pink.500" },colorSchemes: { primary: "pink" },},},purple: {semantics: {colors: { primary: "purple.500" },colorSchemes: { primary: "purple" },},},green: {semantics: {colors: { primary: "green.500" },colorSchemes: { primary: "green" },},},},})()
If you want to use any of the themes passed in themeSchemes
by default, set the initial value in the config's initialThemeScheme
.
import { extendTheme, extendConfig } from "@yamada-ui/react"export const theme = extendTheme({themeSchemes: {pink: {semantics: {colors: { primary: "pink.500" },colorSchemes: { primary: "pink" },},},purple: {semantics: {colors: { primary: "purple.500" },colorSchemes: { primary: "purple" },},},green: {semantics: {colors: { primary: "green.500" },colorSchemes: { primary: "green" },},},},})()export const config = extendConfig({initialThemeScheme: "pink",})
Add ThemeSchemeScript
To switch themes correctly, you need to add ThemeSchemeScript
within the head
or body
.
The reason is that theme switching is implemented using localStorage
or cookies
, and it is necessary to synchronize correctly at the time of page loading.
For Create React App
index.tsx
import { createRoot } from "react-dom/client"import { App } from "./app"import { UIProvider, getThemeSchemeScript } from "@yamada-ui/react"import { theme, config } from "./theme"const injectThemeSchemeScript = () => {const scriptContent = getThemeSchemeScript({initialThemeScheme: config.initialThemeScheme,})const script = document.createElement("script")script.textContent = scriptContentdocument.head.appendChild(script)}injectThemeSchemeScript()const container = document.getElementById("app")const root = createRoot(container!)root.render(<UIProvider theme={theme} config={config}><App /></UIProvider>,)
Please pass the same initialThemeScheme
to props
as in the config.
For Next.js
_document.tsx
import { Html, Head, Main, NextScript } from "next/document"import { ThemeSchemeScript } from "@yamada-ui/react"import { config } from "../theme"export default function Document() {return (<Html lang="en"><Head /><body><ThemeSchemeScript initialThemeScheme={config.initialThemeScheme} /><Main /><NextScript /></body></Html>)}
Depending on the project, you may need to retrieve values from cookies
. In that case, use createThemeSchemeManager("cookie")
.
_document.tsx
import { Html, Head, Main, NextScript } from "next/document"import { ThemeSchemeScript } from "@yamada-ui/react"import { config } from "../theme"export default function Document() {return (<Html lang="en"><Head /><body><ThemeSchemeScripttype="cookie"nonce="testing"initialThemeScheme={config.initialThemeScheme}/><Main /><NextScript /></body></Html>)}
_app.tsx
import type { AppProps } from "next/app"import { UIProvider, createThemeSchemeManager } from "@yamada-ui/react"import { config } from "../theme"const themeSchemeManager = createThemeSchemeManager("cookie")export default function App({ Component, pageProps }: AppProps) {return (<UIProvidertheme={theme}config={config}themeSchemeManager={themeSchemeManager}><Component {...pageProps} /></UIProvider>)}
Please pass the same initialThemeScheme
to props
as in the config.
Add themeSchemeManager
For sites rendered on the server side, such as Next.js, you may want to include the theme schema in the request to avoid changing the theme during hydration.
If you are not using server-side rendering, you do not need to follow this step. Yamada UI uses localStorage
by default.
Prepare getServerSideProps
To standardize getServerSideProps
across multiple pages, define getServerSideCommonProps
.
import { GetServerSidePropsContext } from "next"export const getServerSideCommonProps = ({req,}: GetServerSidePropsContext) => {return {props: {cookies: req.headers.cookie ?? "",},}}
Set cookies
in themeSchemeManager
Set ssr
and cookies
in createThemeSchemeManager
.
_app.tsx
import type { AppProps } from "next/app"import { UIProvider, createThemeSchemeManager } from "@yamada-ui/react"export default function App({ Component, pageProps }: AppProps) {const { cookies } = pagePropsconst themeSchemeManager = createThemeSchemeManager("ssr", cookies)return (<UIProvider themeSchemeManager={themeSchemeManager}><Component {...pageProps} /></UIProvider>)}
Add getServerSideProps
Add the previously created getServerSideCommonProps
to each page.
index.tsx
import { getServerSideCommonProps } from "../get-server-side-props.ts"import { Button } from "@yamada-ui/react"export default function Index() {return <Button>Click me!</Button>}export const getServerSideProps = getServerSideCommonProps
Switching Themes
To switch themes, use changeThemeScheme
. If you want to revert to the original themeScheme
, pass base
.
Editable example
const { themeScheme, changeThemeScheme } = useTheme() return ( <> <Text>The current scheme is "{themeScheme}"</Text> <Wrap mt="md" gap="md"> <Button onClick={() => changeThemeScheme("base")}>Base Theme</Button> <Button colorScheme="pink" onClick={() => changeThemeScheme("pink")}> Pink Theme </Button> <Button colorScheme="purple" onClick={() => changeThemeScheme("purple")}> Purple Theme </Button> <Button colorScheme="green" onClick={() => changeThemeScheme("green")}> Green Theme </Button> </Wrap> </> )
Edit this page on GitHub