Next JS styled components dark mode themeing - javascript

This probably has answer, but I was unable to find it
I am using styled components with next js and use-dark-mode hook to trigger theme change/detect
global styles switch before loading
import { createGlobalStyle } from "styled-components";
export const GlobalStyles = createGlobalStyle`
body {
background: ${props => props.theme.background};
color: ${props => props.theme.color};
font-family: Roboto, sans-serif;
margin: 0;
padding: 0;
}
`
but having simple styled component like this one
const BackgroundTopAppBar = styled.header`
background-color: ${props => props.theme.appBarHeaderBackground};
`;
doesnt change upon page loading and remains light theme colored
also inside _document.js is implemented next-js team example of how to use styled components for SSR and it works well, but for styled components that are not global dark mode is not activated after page is refreshed
thank you

For anybody looking for a solution, use GlobalStyles and in there modify current color of element because GlobalStyles will apply it before loading
export const GlobalStyles = createGlobalStyle`
body {
background: ${props => props.theme.background};
color: ${props => props.theme.color};
font-family: Roboto, sans-serif;
margin: 0;
padding: 0;
}
${BackgroundTopAppBar} {
background-color: ${props => props.theme.appBarHeaderBackground};
}
`

Related

How can I customize the checked state of a checkbox when using svgr in React?

I'm working on a React project and I'm using styled-component and typescript.
I'm customizing the checkbox like this:
Source
import React, { ReactElement } from 'react';
import styled from 'styled-components';
import IconChecked from '#assets/Icons/ico_checked.svg';
interface Props {
id: string;
}
const StyledCheckBox = styled.input`
box-sizing: border-box;
width: 20px;
height: 20px;
background: #ffffff;
border: 1px solid #d4dae4;
border-radius: 4px;
appearance: none;
&:checked {
background-image: url(${IconChecked});
background-repeat: no-repeat;
background-color: #ffffff;
background-position: 50%;
}
`;
const CheckBox = ({ id }: Props): ReactElement => (
<StyledCheckBox type="checkbox" id={id} />
);
export default CheckBox;
Question
To use the svg icon without the <img> tag, I installed the svgr package and set it as an svg type loader through webpack.
The problem is that svgr has the logic to convert svg to component, so I can't set the checked icon in the following way.
&:checked {
background-image: url(${IconChecked});
...
}
As a result, the check icon(IconChecked) does not appear when I click the checkbox after using svgr. How can I solve this?
You can move your ico_checked.svg file to public folder and use the svg directly from the url like this:
&:checked {
background-image: url("/ico_checked.svg");
...
}
You can take a look at this sandbox for a live working example of this approach.

Logic to render a component only once

I need help with creating a logic for my React component. If the divider line appears once on the page it should not be rendered again.
So, if I add the component to the page it styles the text underneath. But if I try to add the component again to the page, the divider line/styling should be ignored. I should only be able to add it once
This is my code:
import React from 'react';
const Divider = () => (
<>
<hr className="divider"/>
</>
);
/* Seperate css file */
hr.divider {
height: 0;
border: 0;
border-top: solid 1px #cdcdcd;
}
hr.divider ~ p.story-text {
font-size: 0.90rem;
font-weight: normal;
font-stretch: normal;
font-style: normal;
letter-spacing: normal;
line-height: 1.75rem;
color:#707174;
#include text-styles(.75rem, 1.75em, "Gordita");
#include breakpoint(tablet) {
#include text-styles(.90rem, 2em, "Gordita");
}
}
hr.divider ~ p.story-text:last-of-type {
border-top: solid 1px red;
}
You need to use the component LifeCycle tools provided by ReactJS. ComponenDidMount() loads the only once when the class is loaded but the render() function is called on each action of the user or the app. Here is a link to ReactJS docs telling how to use ComponentDidMount(): https://reactjs.org/docs/react-component.html#componentdidmount
It may be better to add a condition in the parent component (the one that calls Divider), but given the current snippets:
const Divider = () => (
let dividers = document.getElementsByClassName('divider')
if (dividers.length > 0) {
return null
} else {
return <hr className="divider"/>
}
);
This will not stop your component from rendering. It will only stop more than one hr from rendering.

How to change the style of a single component within an other component with styled-components?

I'm working on an react app with styled-components and I have a component 'Navigation'. In this component are more components like , , etc.
Header for example is declared like this:
const Header = styled.div`
height: 48px;
width: 100%;
transition: all 0.5s ease-in;
Thing is that I have this Navigation component in different files and for all of them the styling is good but now I want to change the background color of the Header component in just one of those files, which is within(?) the Navigation component. How can I do that?
I know that it's possible to change the styling from the Navigation component with something like const NewNav = styled(Navigation)`` but what about the Header?
Thank you in advance.
You can pass props through your navigation component to your header.
<NavigationExample secondary />
import styled, { css } from 'styled-components';
function NavigationExample(props) {
const { secondary } = props;
return (
<Navigation>
<Header secondary={secondary}>
...
</Header>
<Profile>
username
<Profile>
</Navigation>
);
}
const Navigation = styled.nav;
const Header = styled.header`
/* Base styles */
width: 100%;
height: 60px;
background: #222;
color: #fff;
${props => props.secondary && css`
background: #fff;
color: #000;
`;
`;
const Profile = styled.div``;
export default NavigationExample;
Alternatively, you can inline props in your css.
<NavigationExample backgroundColor="#222" />
const Header = styled.header`
/* Base styles */
width: 100%;
height: 60px;
background: ${props => props.backgroundColor || '#222'};
color: ${props => props.backgroundColor ? '#000' : '#fff'}; /* Adjusting text so it's legible like the previous example */
`;

Styled components interpolation

I am wondering why everybody use styled components like this
export const Title = styled.div`
margin-top: 48px;
font-family: ${({ theme }) => theme.font};
font-size: ${({ theme }) => theme.sizeBig};
color: ${({ theme }) => theme.dark};
font-weight: ${({ theme }) => theme.fontWeight}
`
Rather than something like
export const Title = styled.div`
margin-top: 48px;
${({ theme }) => css`
font-family: ${theme.font};
font-size: ${theme.sizeBig};
color: ${theme.dark};
font-weight: ${theme.fontWeight}
`}
`
Is there any reason to create arrow function on every line?
Comes down to personal preference. I actually go a little bit further in my apps:
export const Title = styled.div(({ theme }) => css`
margin-top: 48px;
font-family: ${theme.font};
font-size: ${theme.sizeBig};
color: ${theme.dark};
font-weight: ${theme.fontWeight}
`)
I like it this way since each style is defined in a single template literal.
Styled Components marks some components as static as an optimisation step, if there's nothing to interpolate. Reading this, it seems like this approach would have no performance impact, since having just one property being interpolated marks the whole styled component as not static.

Material-UI: Overriding style classes

I was trying to follow the MUI guide on overriding MUI styles, but using styled-components instead of JSS. In particular, I could not get the first two approaches to work:
Using className
Using classes
I have made sure the injection order in head is correct, so that is not the issue. My problem is that the classes I need are not added to the DOM.
Also note: I managed to get normal styled-components to work well with MUI. I.e. the following works fine:
import React from 'react';
import Button from '#material-ui/core/Button';
import Typography from '#material-ui/core/Typography';
import styled from 'styled-components';
import { darken, fade } from '#material-ui/core/styles/colorManipulator';
const StyledButton = styled(Button)`
color: ${props => props.theme.palette.primary.contrastText };
background: linear-gradient(45deg, #fe6b8b 30%, #ff8e53 90%);
border-radius: ${props => props.theme.shape.borderRadius}px;
height: 48px;
padding: 0 30px;
box-shadow: 0 3px 5px 2px rgba(255, 105, 135, 0.3);
&:hover {
background: ${props => {
return `linear-gradient(45deg, ${darken(`#fe6b8b`, 0.2)} 30%, ${darken(`#ff8e53`, 0.2)} 90%)`;
}};
};
font-size: 1.2rem;
${props => props.theme.breakpoints.up('md')} {
font-size: 1rem;
}
`;
// In render:
<StyledButton>Hello World</StyledButton>
The following however, does not work:
styled(Typography)`
&.my-class {
margin-bottom: 5rem;
}
`;
// In render:
<Typography className="my-class" component="h2" variant="h2">
Dev Tools does show that my-class is indeed added, but, the class does not get added to the DOM. I followed this guide (Third Method).
Any idea why?
PS: I do not want to turn Typography into a StyledTypography component. I know that works (see first example above). Instead, I want to follow the override guide in the MUI docs.
Edit
Relevant installed packages:
"#material-ui/core": "^3.9.3"
"styled-components": "^4.2.0",
Edit 2:
I got it to work if I import an external style sheet:
// style.css
.my-class2 {
margin-bottom: 3rem;
}
// index.js
import React from 'react';
import Typography from '#material-ui/core/Typography';
import './style.css';
const IndexPage = () => (
<>
<Typography className="my-class2" component="h2" variant="h2">
Testing h2 (MUI)
</Typography>
</>
);
<Typography className="my-class2" component="h2" variant="h2">
Testing h2 (MUI)
</Typography>
However, I would like to keep it all inside the component.
Thus, my problem boils down to:
How can I add locally scoped styles to the DOM from within a component, without for instance creating a new component tag / variable with styled-components?

Categories

Resources