4

Before making it duplicate question please make sure you read my question

I am asking this question in 2019, Where React Js documentation specify we can use SASS in our react project here's link

I want to switch between light theme and dark theme using dynamic variable which is control by user click

My React Code

import React from 'react';
import './App.scss';

class App extends React.Component {
    render() {
        return (
            <div className="Home">
                I’m slow and smooth
                <button onClick={() => console.log()}>Change theme</button>
            </div>
        );  
    }
}

export default App;

My SASS code:

$theme: light;  // I want to control this variable

$bgcolor: #222222;

@if($theme== light) {
    $bgcolor: white;    
}
@else {
    $bgcolor: black;    
}

.Home {
    background-color: $bgcolor;
    height: 100vh;
}
5
  • You can't change CSS variables dynamically with JavaScript. Commented Apr 29, 2019 at 12:30
  • any other way to switch between themes like this nelo.is person did Commented Apr 29, 2019 at 12:33
  • 3
    Instead of trying to manipulate a SASS variable from React, you could instead add/remove a class on your React root element and use this class to set your SASS variables: #root.dark { $bgcolor: black; ... } Commented Apr 29, 2019 at 12:34
  • 2
    You could change className(different classname different theme) based on state, and you could change state when user clicks button. You could also use styled-components to change css based on javascript logic instead of plain scss. Commented Apr 29, 2019 at 12:34
  • yes that is better way got it ! Thank you very much Commented Apr 29, 2019 at 12:37

1 Answer 1

7

in case you are still interested, you can kind of change a sass variable by instead using css variables

:root {
    --app-primaryColor: #f49ad1;
    --app-secondaryColor: #211f1e;
}

Then use these variables in your scss files

.button {
    background-color: var(--app-primaryColor);
    color: var(--app-secondaryColor);
}

and update them using React

document.documentElement.style.setProperty('--app-primaryColor', '#ffae00')

Here is a (almost) full example using react and redux. A setTheme action is used to update colors from the document root element. This way you can also configure your theme directly from your react root tag props. These props will be set as the initial state.

// index.html
<div
    id="app"
    primaryColor="red"
    secondaryColor="#f2f2f2"
/>

// css-variables.scss
:root {
    --app-primaryColor: #f49ad1;
    --app-secondaryColor: #211f1e;
}

// app.module.scss
.button {
    background-color: var(--app-primaryColor);
    color: var(--app-secondaryColor);
}

// index.js
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'

import './css-variables'

import App from './app'
import configureStore from './configureStore'

const rootElement = document.getElementById('app')

//Here you could extract your theme variables from your rootElement props and set it as an initial redux state
const initialProps = {}
const store = configureStore(initialProps)

ReactDOM.render(
    <Provider store={store}>
        <App />
    </Provider>,
rootElement)

// app.js
import React from 'react'
import { connect } from 'react-redux'

import { setTheme } from './actions'
import styles from './app.module'

class App extends React.Component {
    componentDidMount() {
        //In case you have an initial state set from your rootElement
        const { theme, setTheme } = this.props
        setTheme(theme)
    }
    
    generateTheme() {
        const primaryColors = ['#ffae00', '#f49ad1', '#d0666b', '#7c6cd0', '#6cd09d', '#d0ba6c']
        const secondaryColors = ['#4c4c4e', '#2f2f2f', '#dcdcdc', '#fff']

        return {
            primaryColor: primaryColors[Math.floor(Math.random() * primaryColors.length)]
            secondaryColor: secondaryColors[Math.floor(Math.random() * secondaryColors.length)]
        }
    }

    onButtonClick() {
        const theme = this.generateTheme()
        this.props.setTheme(theme)
    }

    render() {
        return (
            <div className="{styles.button}" onClick={this.onButtonClick.bind(this)}>
                Change theme
            </div>
        )
    }
}

const mapStateToProps = (state) => ({
    theme: state.theme,
})

export default connect(mapStateToProps, { setTheme })(App)

// actions.js
export const setTheme = theme => dispatch => {
    //You change your theme vars directly from the root element
    Object.keys(theme)
        .filter(prop => typeof theme[prop] !== 'undefined' && theme[prop] !== null)
        .forEach(prop => document.documentElement.style.setProperty(`--app-${prop}`, theme[prop]))
    
    dispatch({
        type: 'THEME/SET',
        payload: theme
    })
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.