React, Styled-component: Override child component style - reactjs

I would like to override Button component style but it doesn't work. Could you tell me how to override it or should I give all style to the child button component?
Button.js
const StyledButton = styled.button`
color: white;
background-color: yellow;
`;
const Button = ({text}) => {
return <StyledButton>{text}</StyledButton>;
};
export default Button;
Parent.js
import Button from "./Button";
const OverrideButton = styled(Button)`
&& {
color: blue;
background-color: green;
}
`;
const Parent = () => {
return <OverrideButton text="Parent" />;
};

your class is created but not applied. You need to pass it on.
const Button = ({text, className}) => {
return <StyledButton className={className}>{text}</StyledButton>;
};
It was answered here: https://stackoverflow.com/a/54113434/12959556
Example: https://stackblitz.com/edit/react-a5mdpo?embed=1&file=index.js

Related

Override them with styled components

I want to creare a template theme in React for my software suite and allow developers to customize the theme for each software they develop.
The theme will be shipped in a library using styled components
Here is an example of the code:
import styled from 'styled-components'
const ButtonStyled = styled.button`
font-size: 1.5em;
text-align: center;
color: green;
`;
const TomatoButton = styled(ButtonStyled)`
color: tomato;
`;
//This is the default template
const DefaultTemplate = () => {
return <div>
<ButtonStyled className='button'>Button</ButtonStyled>
<TomatoButton className='tomato-button'>Button II</TomatoButton>
</div>
}
//This is the template styled by developers
const DefaultTemplateStyled = styled(DefaultTemplate)`
color: white;
&.button{
color: violet
}
&.tomato-button{
color: black;
}
`;
function App() {
return (<DefaultTemplateStyled />);
}
export default App;
In this app I cannot see the override of the styles, am I missing something?
In styled-components what you should do is pass the className propm like this:
//This is the default template
const DefaultTemplate = ({ className }) => {
return (
<div>
<ButtonStyled className={`button ${className}`}>Button</ButtonStyled>
<TomatoButton className={`tomato-button ${className}`}>
Button II
</TomatoButton>
</div>
);
};
All the other code is fine

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)``;

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

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} />;
};

Animation not working in styled-component using {keyframes}

I have a base component - Emoji.jsx
import styled from 'styled-components';
const StyledEmoji = styled.div`
font-size: 6rem;
cursor: pointer;
&:not(:last-child) {
margin-right: 3rem;
}
`;
function Emoji({ content, handleClick }) {
return (
<StyledEmoji onClick={() => handleClick(content)}>{content}</StyledEmoji>
);
}
export default Emoji;
I am extending this component and applying anmimation to it in EmojiBubble.jsx
import Emoji from './Emoji';
import styled, { keyframes } from 'styled-components';
const Bubble = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`;
const EmojiBubble = styled(Emoji)`
animation: ${Bubble} 6s ease-in-out;
`;
export default EmojiBubble;
But, the animation is not working when I am using EmojiBubble component
<EmojiBubble content={emoji} /> //Emoji not rotating
What the issue here?
function Emoji({ content, handleClick })... doesn't pass the class name down to StyledEmoji, that's why styles created by EmojiBubble are not applied. All you need to do: pass the class name:
function Emoji({ content, handleClick, className }) {
return (
<StyledEmoji className={className} onClick={() => handleClick(content)}>
{content}
</StyledEmoji>
);
}
Working example

Resources