Adding themes to Next.js with styled-components, mobx, and typescript

Adding themes to Next.js with styled-components, mobx, and typescript

Let your users decide. Provide the option to switch seamlessly between themes with styled-components and mobx .

Getting Started

  1. Installing dependencies
  2. Creating the theme constants
  3. Configuring styled-components with Next.js
  4. Adding styled-components’ server-side functionality
  5. Persisting data
  6. Creating a mobx store
  7. Create a global style
  8. Creating the StyleProvider
  9. Adding types to the theme
  10. Making sure it works

1. Install

  • The dependencies: yarn add styled-components mobx mobx-react
  • The dev-dependencies: yarn add -D @types/styled-components
Читайте также:  Hyperlink Example

2. Create a file for the theme constants

themes.constants.ts
In this file, we’re going to define the themes and other relavant constants.

export const DEFAULT_THEME = 'dark' 

3. Add styled-components to the next.config.js file

In the nextConfig object, add the key-pair values:

4. Add ServerStyleSheet to _document.tsx

Add the getInitialProps method to the MyDocument class shown below.

If you haven’t already created _document.tsx , add it to your pages folder. And paste the following:

import Document, < Html, Head, Main, NextScript, DocumentContext, >from 'next/document'; import < ServerStyleSheet >from 'styled-components'; class MyDocument extends Document < static async getInitialProps(ctx: DocumentContext) < const sheet = new ServerStyleSheet(); const originalRenderPage = ctx.renderPage; try < ctx.renderPage = () =>originalRenderPage( < enhanceApp: (App) =>(props) => sheet.collectStyles( />), >); const initialProps = await Document.getInitialProps(ctx); return < . initialProps, styles: [ <>  , ], >; > finally < sheet.seal(); >> render() < return (      ); > > export default MyDocument; 

5. Create utility functions to allow persisting data with localStorage

export const setStorage = (key: string, value: unknown) => < window.localStorage.setItem(key, JSON.stringify(value)); >; export const getStorage = (key: string) => < const value = window.localStorage.getItem(key); if (value) < return JSON.parse(value); >>; 

6. Create a UI Store with mobx

import < action, makeAutoObservable, observable >from 'mobx'; import < setStorage >from './utils'; type Themes = 'dark' | 'light'; class UiStore < @observable private _theme: Themes = 'light'; @observable private _initializing: boolean = true; constructor() < makeAutoObservable(this); >get theme() < return this._theme; >get initializing() < return this._initializing; >@action toggleTheme() < this._theme = this._theme === 'light' ? 'dark' : 'light'; setStorage('theme', this._theme); >@action changeTheme(nameOfTheme: Themes) < this._theme = nameOfTheme; >@action finishInitializing() < this._initializing = false; >> export const uiStore = new UiStore(); 

7. Create a global style with styled-components

We’ll soon be able to access the theme in the styled-components in the following manner.
global-styles.ts

export const GlobalStyle = createGlobalStyle` * < margin: 0; padding: 0; box-sizing: border-box; >html < background: $<(< theme >) => theme.colors.body>; > `; 

8. Creating the StyleProvider

import < observer >from 'mobx-react'; import < useEffect, ReactNode >from 'react'; import < ThemeProvider >from 'styled-components'; import < uiStore >from './uiStore'; import < DEFAULT_THEME, THEMES >from './theme.constants'; import < GlobalStyle >from './global-styles` import < getStorage, setStorage >from './utils'; interface OnlyChildren < children: ReactNode >const StyleProviderComponent = (props: OnlyChildren) => < const < children >= props; const < theme >= uiStore; useEffect(() => < if (!getStorage('theme')) < setStorage('theme', DEFAULT_THEME); >const storageThemeName = getStorage('theme'); uiStore.changeTheme(storageThemeName); uiStore.finishInitializing(); >, []); return ( > ); >; export const StyleProvider = observer(StyleProviderComponent); 

9. Add typing to the theme

import 'styled-components'; declare module 'styled-components' < export interface DefaultTheme < name: string; colors: < primary: string; textPrimary: string; >; > > 

10. Wrap the provider around pages/_app.tsx

import type < AppProps >from 'next/app'; import < StyleProvider >from './style-provider'; function MyApp(< Component, pageProps >: AppProps) < return (  /> ); > export default MyApp; 

Test that it works in pages/index.tsx

import type < NextPage >from 'next'; import Head from 'next/head'; import < uiStore >from './uiStore'; const Home: NextPage = () => < const < initializing >= uiStore; if (!initializing) < return 

Loading.

; > return ( <> ) > export default Home

You can access the theme in styled-components by adding a callback function (ex: $<(< theme >) => theme.colors.textPrimary> ) in between the back ticks.

const Button = styled.button` background: $<(< theme >) => theme.colors.body>; border: 1px solid $<(< theme >) => theme.colors.accent>; color: $<(< theme >) => theme.colors.textPrimary>; ` 

Источник

How to create a Theme in React/Typescript (Context API) with styled-components

Hello everyone, in this super fast tutorial, I’ll teach you how to create a theme in a React/Typescript application with styled-components, let’s go?

Create a new project

yarn create react-app *your-application-name* --template=typescript 

styled-components

yarn add styled-components 
yarn add @types/styled-components -d 

Create theme variables and ThemeProps interface:

export interface ThemeProps  background: string; text: string; > export const darkTheme: ThemeProps =  background: 'var(--dark-background)', text: 'var(--dark-text)', >; export const lightTheme: ThemeProps =  background: 'var(--light-background)', text: 'var(--light-text)', >; 

Create a global styles with createGlobalStyle from styled-components and set the theme variables:

import  createGlobalStyle, withTheme > from 'styled-components'; import  ThemeProps > from './themes'; type GlobalThemeProps =  theme: ThemeProps; >; const globalStyle = createGlobalStyle` :root < //dark-mode --dark-background: #1A1B27; --dark-text: #F5F5F7; //light-mode --light-background: #f2f2f2; --light-text: #2E0509; >* < margin: 0; padding: 0; box-sizing: border-box; outline: 0; >body < -webkit-font-smoothing: antialiased; height: 100vh; width: 50vw; margin: 0 auto; background-color: $ <(theme >: GlobalThemeProps) => theme.background>; display: flex; justify-content: center; align-items: center; > h1 < font-size: 3.375rem; color: $ <(theme >: GlobalThemeProps) => theme.text>; > `; export default withTheme(globalStyle); 

In the h1 and body styles we can already see an example of applying the themes, but we still need to create the context and hook function.

Create a Theme context:

import React from 'react'; import  ThemeProvider > from 'styled-components'; import  useThemeMode > from '../../hooks/useThemeMode'; import  lightTheme, darkTheme > from '../../styles/themes'; const ThemeContext: React.FC = ( children >) =>  const  theme > = useThemeMode(); const themeMode = theme === 'dark' ? darkTheme : lightTheme; return ThemeProvider theme=themeMode>>children>/ThemeProvider>; >; export default ThemeContext; 

Context they are ways to save the value of states outside the component’s scope.

Create a hook function to switch the theme:

import  useEffect, useState > from 'react'; export const useThemeMode = () =>  const [theme, setTheme] = useState('dark'); const setMode = (mode: string) =>  window.localStorage.setItem('theme', mode); setTheme(mode); >; const themeToggler = () => (theme === 'dark' ? setMode('light') : setMode('dark')); useEffect(() =>  const localTheme = window.localStorage.getItem('theme'); localTheme && setTheme(localTheme); >, []); return  theme, themeToggler >; >; export default useThemeMode; 

Here we are creating a theme state, fetching its initial value from the browser’s storage and changing its value when the setMode function is called.

Create a TogglerButton component to use hook function and switch the theme when clicked:

import  HiMoon > from 'react-icons/hi'; import  FaSun > from 'react-icons/fa'; import * as S from './styles'; interface ThemeTogglerProps  themeToggler: () => void; > function TogglerButton( themeToggler >: ThemeTogglerProps)  return ( S.Container> label htmlFor="checkbox" className="switch"> input id="checkbox" type="checkbox" onClick=themeToggler> onChange= => false> checked=window.localStorage.getItem('theme') === 'light'> /> S.Icons className="slider round"> window.localStorage.getItem('theme') !== 'light' ? ( <> HiMoon style= <marginLeft: '6.3px', height: '10px' >> /> /> ) : ( <> FaSun size=0> style= <marginLeft: '41px', height: '10px' >> /> /> )> /S.Icons> /label> /S.Container> ); > export default TogglerButton; 
  • When creating this component we use an outside library for the icons, so we need to install that too, it’s called React Icons:

And create the styles to TogglerButton:

import styled from 'styled-components'; export const Container = styled.div` .switch  position: relative; display: inline-block; width: 4rem; height: 1.5rem; > .switch input  opacity: 0; width: 0; height: 0; > .slider  position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: $( theme >) => theme.background>; -webkit-transition: 0.2s; transition: 0.2s; box-shadow: 0 0 2px $( theme >) => theme.text>; > .slider:before  position: absolute; content: ''; height: 14px; width: 14px; left: 7px; bottom: 5px; background-color: $( theme >) => theme.background>; -webkit-transition: 0.2s; transition: 0.2s; > input:checked + .slider  background-color: $( theme >) => theme.background>; > input:checked + .slider:before  -webkit-transform: translateX(35px); -ms-transform: translateX(35px); transform: translateX(35px); > /* Rounded sliders */ .slider.round  border-radius: 34px; > .slider.round:before  border-radius: 50%; > `; export const Icons = styled.span` width: 100%; display: flex; justify-content: space-between; top: 25%; align-items: center; svg  color: $( theme >) => theme.text>; z-index: 11; > `; 

Here in this style we can see the theme usage in some properties.

Like in this code snippet below:

.slider  position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: $( theme >) => theme.background>; -webkit-transition: 0.2s; transition: 0.2s; box-shadow: 0 0 2px $( theme >) => theme.text>; > 

We are changing the background-color according to the theme’s background variable.

And finally, we need to add the Context, ThemeProvider, GlobalStyle and ThemeToggler components to App.tsx:

import  ThemeProvider > from 'styled-components'; import TogglerButton from './components/TogglerButton'; import GlobalStyle from './styles/global'; import ThemeContext from './contexts/ThemeContext'; import  lightTheme, darkTheme > from './styles/themes'; import useThemeMode from './hooks/useThemeMode'; function App()  const  theme, themeToggler > = useThemeMode(); const themeMode = theme === 'light' ? lightTheme : darkTheme; return ( ThemeContext> ThemeProvider theme=themeMode>> GlobalStyle /> header> TogglerButton themeToggler=themeToggler> /> /header> h1>theme>/h1> /ThemeProvider> /ThemeContext> ); > export default App; 

Run yarn and then yarn start in your terminal and it’s done!

if you want to add more colors, you need to set it in the global.ts file and then reference it to a variable in the themes.ts file.

The goal with this article was to make a more direct tutorial, but any questions just send there in the comments that, I’ll be answering. If you need more references, I have some examples of usage in repositories on my Github.
That’s it for today, guys, I hope you enjoyed the article and that it can help you and your team in some way.

Источник

How to Configure Theming or Theme Switching with React and TypeScript

sidebar

I had a project requirement to support theming in react-based applications. So there I have come up with a simple and quick solution to build an application with a pre-defined theme (mainly background color, text color, fonts, etc). Let’s check how I have approached solving the problem.

React typescript theme using styled component

Themeing & Theme Swtiching

* leverage styled-componet (npm library)

* define a theme model (holds the property I want to change — such as background color, text color)

* create multiple theme & apply switch function

* leveraged React Context API to store theme value

react theme green

react theme light

react theme dark

Above I have three different colors and based on theme value, I can change the background color and text color.

Setup React with TypeScript

Let’s set up an application with React, TypeScript and styled-component. I will be using create-react-app command to build the application.

npx create-react-app redux-demo-app --template typescript

npm install --save @types/react-router-dom

npm install --save bootstrap react-bootstrap

npm install --save node-sass

npm install --save styled-components @types/styled-components

Also, import @import «~bootstrap/scss/bootstrap»; as well as your scss file. All project is now setup and it will run the application on your web browser.

What is styled-component & what it is being used?

styled-components: A flexible way to style React components with CSS. It provides out-of-the-box theming support using a wrapper component called, . This component is responsible for providing the theme to all other React components that are wrapped within it.

Folder structure and multiple theme file creations

Before implementing a theme file, let’s create some folder structure for which I can keep respective files (.tsx, .ts, and .scss) files to configure my codebase.

react theme code structure

Create styled.d.ts file for TypeScript and here we will be defining our theming properties.

declare module 'styled-components'

export interface DefaultTheme

Источник

Оцените статью