How to add "active" class to styled components in React - reactjs

I'm learning React and i just founded about styled-components and i would like to refactor my code into styled components.
Maybe i didn't understand it at all but i'm trying to make add/remove class on "toggle"
For example:
button--active
Here is what i've tried so far:
render() {
const {active, toggleHamburgerActive } = this.props;
return (
<div>
<HamburgerButtonContainer active={active} onClick={toggleHamburgerActive}/>
</div>
styles:
const buttonStyles = css`
border: 1px solid red;
`;
const getButtonStyles = active => {
if (active) {
return hamburgerActiveStyles;
}
return buttonStyles;
};
const hamburgerActiveStyles = css`
border: 10px solid green;
`;
export const HamburgerButtonContainer = styled.button`
${getButtonStyles}
`;
#EDIT
To make it more clear. active is changing on click but styles are not.

I think you just forgot to destructure your props:
const getButtonStyles = /* this here ---> */({active}) => {
if (active) {
return hamburgerActiveStyles;
}
return buttonStyles;
};
const getButtonStyles = /* props is passed here, not only active ---> */props =>
You can access props by passing a callback in an expression as you did.
styled.button`
${props => ...} // you passed the callback here, so props is passed to it, not only active
`
Or if you prefer
styled.button`
${props => getButtonStyles(props.active)}
`

You haven't called your function using active as a param. And You should organise your code like below to pass the active as a prop.
const HamburgerButtonContainer = ({ onClick, active }) => {
const buttonStyles = `
border: 1px solid red;
`;
const getButtonStyles = (active) => {
if (active) {
return hamburgerActiveStyles;
}
return buttonStyles;
};
const hamburgerActiveStyles = `
border: 10px solid green;
`;
const StyledHamburgerButtonContainer = styled.button`
${getButtonStyles(active)}
`;
return <StyledHamburgerButtonContainer onClick={onClick} />;
};

Related

handling events on custom components

I have these files:
button.module.css
.base {
display: flex;
font-size: 16px;
font-family: "Helvetica Neue";
align-items: center;
justify-content: center;
padding: 6px 12px 6px 12px;
width: 50px;
border-radius: 6px;
}
.normal {
composes: base;
color:black;
background-color: #aeeeb7;
border: 1px solid #42924d;;
}
.danger {
composes: base;
color:black;
background-color: rgb(253, 128, 128);
border: 1px solid rgb(196, 108, 108);
}
button.js
import classes from './button.module.css';
const ButtonTypes = {
'normal': classes.normal,
'danger': classes.danger
};
const Button = (props) => {
const className = ButtonTypes[props.type] ? ButtonTypes[props.type] : classes.normal;
return <div role="button" className={className} ...props>{text}</div>;
}
export default Button;
app.js
import Button from './button';
const App = () => {
const handleClick = () => {
console.log('app');
}
const handleMouseOver = () => {
console.log('mouse-over');
}
...
return (
<div>
<Button type="normal" onClick=(handleClick) onMouseOver={handleMouseOver} ...>
</div>
);
}
export default Button;
I am changing the class of the button depending on the "type" property. (It could be other components not just a button)
How should I handle events on the custom component? Is the way I am passing them right now to that div inside fine or I should do it differently?
I want to create some custom components and I am trying to verify I am doing it the right way.
One suggestion here. Instead of spreading all props in button. You can destructure out the required props and then spread the rest props.
import classes from "./button.module.css";
const ButtonTypes = {
normal: classes.normal,
danger: classes.danger
};
const Button = ({ type, ...rest }) => {
const className = ButtonTypes[type] ? ButtonTypes[type] : classes.normal;
return (
<div role="button" className={className} {...rest}>
{text}
</div>
);
};
export default Button;

Styling Components (styled-components) | Superimposing one on top of the other

The problem is this:
There is a created UiInput React component using styled-components, above it there is also a UiInputExt React component, which should override some of the styles defined in UiInput, but for some reason this does not happen, apparently it does not even add the corresponding class...
I attach the code below:
const StyledInput = styled.input`
color: ${(props) => props.styles.color};
::placeholder,
::-webkit-input-placeholder {
color: ${(props) => props.styles.color};
}
:-moz-placeholder {
color: ${(props) => props.styles.color};
opacity: 1;
}
::-moz-placeholder {
color: ${(props) => props.styles.color};
opacity: 1;
}
:-ms-input-placeholder {
color: ${(props) => props.styles.color};
}
`;
<StyledInput
id={id}
className={cn(styles.input, classes)}
type={type}
placeholder={placeholder}
styles={isTheme.styles}
>
</StyledInput>
And the corresponding override (which doesn't work!)
import UiInput from '../';
const StyledUiInputExt = styled(UiInput)`
color: ${(props) => props.styles.color_uiinputext};
::placeholder,
::-webkit-input-placeholder {
color: ${(props) => props.styles.color_uiinputext};
}
:-moz-placeholder {
color: ${(props) => props.styles.color_uiinputext};
opacity: 1;
}
::-moz-placeholder {
color: ${(props) => props.styles.color_uiinputext};
opacity: 1;
}
:-ms-input-placeholder {
color: ${(props) => props.styles.color_uiinputext};
}
`;
<StyledUiInputExt classes={cn(styles.input, classes)} {...props} styles={isTheme.styles}></StyledUiInputExt>
You are not exporting the styled component StyledInput, rather you are exporting a plain React component that is rendering StyledInput.
const StyledInput = styled.input`
color: blue;
`;
const UiInput = () => {
return <StyledInput />;
};
export default UiInput;
UiInputExt
import UiInput from "./UiInput";
const StyledInputExt = styled(UiInput)`
color: green;
`;
const UiInputExt = () => {
return <StyledInputExt />;
};
The style you are applying to UiInput isn't applied to the JSX it renders, i.e. it isn't passed through to StyledInput.
You can only override other styled-components. For this you should export/import StyledInput (renamed to UiInput) directly.
const UiInput = styled.input`
color: blue;
`;
export default UiInput;
An alternative would be to export UiInput as a styled component and ensure that the className prop is passed through to the StyledInput component.
const StyledInput = styled.input`
color: blue;
`;
const UiInput = ({ className }) => {
return <StyledInput className={className} />;
};
export default styled(UiInput)``;

React with TS can't see any contect inside background wrapper component

Here is the register component code -
const RegisterView = () => {
return (
<Background>
<h1>ddd</h1>
</Background>
);
};
The background scss -
.mainContainer {
display: flex;
flex-direction: row;
min-height: 80vh;
min-width: 140vh;
align-items: center;
justify-content: center;
background-color: map-get($colors, primary);
padding: 100px;
position: relative;
z-index: 10;
&:after {
background-color: #fff;
border-radius: 15px;
content: '';
position: absolute;
top: 90px;
left: 140px;
right: 140px;
bottom: 90px;
z-index: -1;
}
}
Background component view.tsx -
import classes from './Background.module.scss';
const BackgroundView = () => {
return (
<div className={classes['mainContainer']}></div>
);
};
BackgroundView.displayName = 'Background';
BackgroundView.defaultProps = {};
export default BackgroundView;
Background component tsx -
import BackgroundView from './Background.view';
const Background = () => {
return (
<BackgroundView />
);
};
Background.displayName = 'Background';
Background.defaultProps = {};
export default Background;
The Background component should be a wrapper for all other components. Here is what I'm getting right now -
I can't get any content inside the component, what is the problem?
You've wrapped BackgroundView in a Background component you've written like this:
const Background = () => {
return (
<BackgroundView />
);
};
That throws away any children you've provided to the Background component. If you want to put those children in the BackgroundView, you have to do that explicitly:
const Background = ({children}) => {
return (
<BackgroundView>{children}</BackgroundView>
);
};
You have the same problem with BackgroundView, so:
const BackgroundView = ({children}) => {
return (
<div className={classes['mainContainer']}>{children}</div>
);
};
It's also not clear why you have Background at all. You could just use BackgroundView directly.
Just as a side note, there's no need for the () around JSX elements (provided you start the JSX element on the line with the return, not the next line):
const Background = ({children}) => {
return <BackgroundView>{children}</BackgroundView>;
};
and in fact, if you like, you can use the concise form of the arrow function:
const Background = ({children}) => <BackgroundView>{children}</BackgroundView>;
but those are both just style things, you may prefer to do it differently.

Adding A button before the previousLabel Props and after the nextLabel Props in React-Paginate Not Working

Please I needed to add a button before the previousLabel property details and after the nextLabel prop details in React-Paginate but what I have below is not working. I have also tried to read the documentation and check all the prop details but still couldn't achieve the result below.
I want a first button to come before one button and a last button to come after the next button.
what the code below looks like above.
what I want to achieve below
```
import React, { useState, useEffect } from 'react'
import axios from 'axios'
import ReactPaginate from 'react-paginate';
import './styles.css'
export default function App() {
const [postsPerPage] = useState(5);
const [offset, setOffset] = useState(1);
const [posts, setAllPosts] = useState([]);
const [pageCount, setPageCount] = useState(0)
const getPostData = (data) => {
return (
data.map(post => <div className="container" key={post.id}>
<p>User ID: {post.id}</p>
<p>Title: {post.title}</p>
</div>)
)
}
const getAllPosts = async () => {
const res = await axios.get(`https://jsonplaceholder.typicode.com/posts`)
const data = res.data;
const slice = data.slice(offset - 1 , offset - 1 + postsPerPage)
// For displaying Data
const postData = getPostData(slice)
// Using Hooks to set value
setAllPosts(postData)
setPageCount(Math.ceil(data.length / postsPerPage))
}
const handlePageClick = (event) => {
const selectedPage = event.selected;
setOffset(selectedPage + 1)
};
useEffect(() => {
getAllPosts()
}, [offset])
return (
<div className="main-app">
{/* Display all the posts */}
{posts}
{/* Using React Paginate */}
<ReactPaginate
previousLabel={"previous"}
nextLabel={"next"}
breakLabel={"..."}
breakClassName={"break-me"}
pageCount={pageCount}
onPageChange={handlePageClick}
containerClassName={"pagination"}
subContainerClassName={"pages pagination"}
activeClassName={"active"} />
</div>
);
}
```
Below is the css
.main-app {
margin: 2% 10%;
border: 1px ridge #464141;
padding: 5%;
font-family: Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;
font-size: 20px;
color: #464141;
}
.container {
border-bottom: #fff 2px ridge;
}
.pagination {
margin-top: 45px;
margin-left: -40px;
display: flex;
list-style: none;
outline: none;
}
.pagination>.active>a {
background-color: #47ccde;
color: #fff;
}
.pagination>li>a {
border: 1px solid #47ccde;
padding: 5px 10px;
outline: none;
cursor: pointer;
}
.pagination>li>a, .pagination>li>span {
color: #47ccde;
background-color: azure;
}

Explain example from Material UI v5 [duplicate]

Is it possible to use the spread operator with a styled component in React Native?
I have this component:
const StyledHeaderText = styled.Text`
fontFamily: ${props => props.theme.font};
fontSize: ${props => props.theme.fontSizeSubtitle};
color: ${props => (props.lightMode) ? props.theme.fontColor : props.theme.fontPrimaryColor}
`;
But lets say that in my theme, I have an object that has both the fontFamily and the fontSize, and I re use all over the app. I would like to be able to know if I can do something like this, which currently it is not working:
const StyledHeaderText = styled.Text`
...${props => props.theme.fontHeader};
color: ${props => (props.lightMode) ? props.theme.fontColor : props.theme.fontPrimaryColor}
`;
This would be useful too setting up elevation in iOS for example, since I have to setup 4 styles.
Thanks
You can use the css helper function to generate the specific css and return it as a template literal.
import styled, {css} from 'styled-components/native'
const GlobalStyles = css`
fontFamily: ${props => props.theme.font};
fontSize: ${props => props.theme.fontSizeSubtitle};
`
const StyledHeaderText = styled.Text`
${GlobalStyles}
// Other Styles
`
or conditionally as
const StyledHeaderText = styled.Text`
${props => props.theme.fontHeader ? GlobalStyles : 'fontSize: 14'}
// Other Styles
`
In React.js you can use the spread operator override multiple styles
Here is a link to a code example
const StyledText = styled.div`
/* Normal styles */
color: blue,
background-color: white,
/* Fields to override with object from props */
${({ styleOverrides }) => ({ ...styleOverrides })}
`;
You can also return objects directly from interpolations function, and they'll be treated as inline styles.
const StyledHeaderText = styled.Text`
${props => ({...props.theme.fontHeader})};
color: ${props => (props.lightMode) ? props.theme.fontColor props.theme.fontPrimaryColor}
`;
or
const StyledHeaderText = styled.Text`
${props => props.theme.fontHeader};
color: ${props => (props.lightMode) ? props.theme.fontColor props.theme.fontPrimaryColor}
`;
for more details : reference
To expand on previous answers you can also do the following:
import styled, {css} from 'styled-components/native'
// with theme
const GlobalStyles = css`
fontFamily: ${ ({theme}) => theme.font };
fontSize: ${ ({theme}) => theme.fontSizeSubtitle };
`
// Without theme using inherited props
const GlobalStyles = css`
fontFamily: ${ ({font}) => font };
fontSize: ${ ({fontSizeSubtitle}) => fontSizeSubtitle };
`
// if you wanted it to be conditional
const GlobalStyles = css`
fontFamily: ${ ({font}) => font || 'roboto' };
fontSize: ${ ({fontSizeSubtitle}) => fontSizeSubtitle || '14px' };
`
const StyledHeaderText = styled.Text`
${GlobalStyles}
// Other Styles
`
// same can also be done with regular styled components:
export const HeaderText = styled.p`
fontSize: ${ ({fontSizeSubtitle}) => fontSizeSubtitle || '14px' };
`
// Useage would be in your component would be like:
import react from react;
import { HeaderText } from '../component/styles'
export const FooComponent = memo(({ destructuredProps }) => {
// some other code
return (
<>
<HeaderText className={fooClass} fontSize='18px'> Here's my sample text! </HeaderText>
<>
)});

Resources