Change button bgcolor depends on props - reactjs

I want to change the background color of a button based on the props. Assume that I have 4 different names of background colors; primary, secondary, info, and warning. I inspect the code in chrome but no background show:
This what I did:
import React, { useState } from "react";
import styled from "styled-components";
import { Button } from "../assets/styles/GlobalStyles";
const Navbar = () => {
const [button, setButton] = useState(true);
return (
<>
{button ? (
<NavBtnLink to="/">
<Button primary>SIGN UP</Button>
</NavBtnLink>
) : (
<NavBtnLink to="/">
<Button secondary>SIGN UP</Button>
</NavBtnLink>
)}
</>
);
};
GlobalStyles.js (Button)
export const Button = styled.button`
padding: 8px 20px;
background-color: ${({ primary, secondary }) =>
primary ? ("#007bff" ? secondary : "#242424") : "transparent"};
color: #fff;
font-size: 18px;
border-radius: 4px;
outline: none;
border: none;
cursor: pointer;
white-space: nowrap;
&:hover {
}
`;

Change background-colors condition and try this:
background-color: ${({ primary, secondary }) =>
primary ? "#007bff" : secondary ? "#242424" : "transparent"};

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;

Styled-components extends props

I have a ready button like this , These are the features I want every button to have.
If I send props for the icon, I don't want the icon to be created, if I don't, I don't want it to be created.
import Icon from 'components/icons/Icon';
import styled from 'styled-components';
const Button = styled.button`
border-radius: 8px;
color: white;
cursor: pointer;
outline: none;
border: none;
display: flex;
font-family: 'DM Sans', sans-serif;
font-weight: 700;
`;
const DefaultButton = ({ name, children }) => {
return (
<Button>
{name && <Icon name={name}></Icon>}
{children}
</Button>
);
};
export default DefaultButton;
I have a button component that I have customized like this.
I want it to inherit its properties from the default button.
But Primary's features do not appear on my button.
I wonder what should I fix, thanks friend
import styled from 'styled-components';
import { sizes } from 'constants/components/button';
import { colors } from 'theme';
import DefaultButton from './DefaultButton';
const PrimaryButton = styled(DefaultButton)`
padding: ${({ size }) => sizes[size]} 48px;
background-color: ${colors.primary.color};
font-size: 14px;
font-style: bold;
&:focus {
border: 1px solid #ffffff;
box-sizing: border-box;
box-shadow: 0px 0px 0px 3px rgba(24, 207, 152, 1);
}
&:hover {
background-color: ${colors.primary.pressed};
box-shadow: 0px 14px 24px rgba(23, 207, 151, 0.3);
color: white;
}
&:disabled {
background-color: ${colors.primary.disabled};
cursor: not-allowed;
pointer-events: none;
color: white;
}
`;
export default PrimaryButton;
This is how I use my component and I want it to be like this
<PrimaryButton size="md" name="test">
Sign in
</PrimaryButton>
If you want to extend/override the styles of another component, you need to pass down the className prop, as mentioned in the docs.
The styled method works perfectly on all of your own or any third-party component, as long as they attach the passed className prop to a DOM element.
const DefaultButton = ({ name, children, className }) => {
return (
<Button className={className}>
{name && <Icon name={name}></Icon>}
{children}
</Button>
);
};
I find #svrbst solution very effective. I extended it to add other dependencies as shown is the question and it works fine. Here is the forked codesandbox

How can I add custom CSS to my React component and override the default CSS value?

I have a component for my button with its own css file, but I'm trying to figure out how to add a className directly to the component and change the CSS for mobile view. Right now, the Button.css file overrides everything and my new className added to the component doesn't even show up in the html.
Here is the Button.js file
import React from 'react';
import './Button.css'
const STYLES = [
'btn--primary',
'btn--outline'
]
const SIZES = [
'btn--medium',
'btn--large'
]
export const Button = ({
children,
type,
onClick,
buttonStyle,
buttonSize
}) => {
const checkButtonStyle = STYLES.includes(buttonStyle) ? buttonStyle : STYLES[0]
const checkButtonSize = SIZES.includes(buttonSize) ? buttonSize : SIZES[0]
return (
<button className={`btn ${checkButtonStyle} ${checkButtonSize}`} onClick={onClick} type={type}>
{children}
</button>
)
}
Here is the Button.css
:root {
--primary: #3acbf7;
}
.btn {
padding: 8px 20px;
border-radius: 4px;
outline: none;
border: none;
cursor: pointer;
}
.btn:hover {
background-color: transparent;
color: #fff;
padding: 8px 20px;
border-radius: 4px;
border: solid 2px var(--primary);
transition: all 0.3s ease-out;
}
.btn--primary {
background-color: var(--primary);
}
.btn--outline {
background-color: transparent;
color: #fff;
padding: 8px 20px;
border-radius: 4px;
border: solid 1px var(--primary);
transition: all 0.3s ease-out;
}
.btn--medium {
padding: 8px 20px;
border-radius: 4px;
font-size: 18px;
color: #fff;
}
.btn--large {
padding: 12px 26px;
border-radius: 4px;
font-size: 20px;
color: #fff;
}
And here is the main component where I'm trying to add a custom className to override the code above. Note this code is inside of a Navbar component.
import React, { Component } from 'react';
import { MenuItems } from "./MenuItems"
import { Button } from "../Button"
import './Navbar.css'
class Navbar extends Component {
render() {
return (
<nav className="NavbarItems">
<Button className="btn-mobile">Sign Up</Button>
</nav>
)
}
}
If I try to add .btn-mobile to my Navbar.css, none of the properties show up in the html. I tried to add an id and still didn't work. Not sure how to custom the button since it's a component with preset properties
The way that I generally accomplish this is to accept className as a prop and spread it into the default classes of the element, like so:
const Button = ({className='', text, ...rest}) => (
<button className={`my-button-class ${className}`} {...rest}>{text}</button>
)
Then you could use it like so:
<Button className="my-custom-class" text="press me" id="my-id" />
and it will render as
<button class="my-button-class my-custom-class" id="my-id">press me</button>
By defaulting the className prop to an empty string, it won't be added as the string of "undefined" if the implementation doesn't pass a className. Note that we also spread in any other props that were passed.

Styled-components: Styles are not applied when trying to style already styled component

I'm trying to style my component which was styled already. But styles in the new rules are not applied in output CSS.
Can I style component that I already styled?
Thanks you in advance for your help.
EDIT: Add rest of LanugageChooser definition
// COMPONENT THAT I'M TRYING TO STYLE
const LanguageChooser = () => {
const Container = styled.div`
display: flex;
align-items: center;
height: 36px;
& > div:not(:last-child) {
margin-right: 5px;
}
`;
return (
<Container>
<Flag { ...languages.pl }/>
<Flag { ...languages.en }/>
</Container>
)
}
const Flag = ({ flag, language }) => {
const { i18n } = useTranslation();
const Button = styled.div`
cursor: pointer;
font-size: 24px;
transition: .2s all;
&:hover {
font-size: 36px;
}
`;
return (
<Button onClick={ () => i18n.changeLanguage(language) }>{ flag }</Button>
)
}
// TRYING ADD MARGIN LEFT, BUT THERE IS NO RESULT.
// ANY OTHER CSS PROPERTY ARE NOT APPLYING
const Navbar = ({ color }) => {
...
const StyledLanguageChooser = styled(LanguageChooser)`
margin-left: auto;
`;
const Nav = styled.nav`
display: flex;
align-content:center;
background: ${ color };
padding: 2px 3px;
`;
return (
<Nav className="navbar">
<StyledNavLink to="/home">...</StyledNavLink>
<StyledNavLink to="/maps">...</StyledNavLink>
<StyledNavLink to="/charts">...</StyledNavLink>
<StyledLanguageChooser/>
</Nav>
)
}
First, move the styled component outside of function scope or your style will reset on every render and you will get heavy performance issues.
Secondly, in order to apply styles, you need to pass className property.
See Styling normal React components
If you use the styled(MyComponent) notation and MyComponent does not render the passed-in className prop, then no styles will be applied.
const Container = styled.div`
display: flex;
align-items: center;
height: 36px;
& > div:not(:last-child) {
margin-right: 5px;
}
`;
const LanguageChooser = ({ className }) => {
return (
<Container className={className}>
<Flag {...languages.pl} />
<Flag {...languages.en} />
</Container>
);
};
const Button = styled.div`
cursor: pointer;
font-size: 24px;
transition: 0.2s all;
&:hover {
font-size: 36px;
}
`;
const Flag = ({ flag, language }) => {
const { i18n } = useTranslation();
return <Button onClick={() => i18n.changeLanguage(language)}>{flag}</Button>;
};

React Styled-Components passing props issue

Trying to create a nested component that accepts multiple arguments, eg. styles for the button, styles for text and a possible icon. Everything (passing props) works fine if I directly render the button.
Below is the code I've written
import React from "react";
import styled from "styled-components";
import _ from "lodash";
import { hexToRgb } from "../styles/helpers";
import * as MaterialIcons from "styled-icons/material";
const StyledButton = styled.button`
text-align: center;
border: ${props =>
props.outline ? `1px solid ${props.outlineColor}` : "none"};
background: ${props => (props.background ? props.background : "#000")};
border-color: ${props =>
props.outlineColor ? props.outlineColor : "transparent"};
min-width: 120px;
width: ${props => (props.width ? props.width : "auto")};
min-height: 40px;
border-radius: 25px;
color: ${props => (props.color ? props.color : "#FFF")};
transition: all ease 0.5s;
&:hover {
cursor: pointer;
background: ${props =>
props.background ? hexToRgb(props.background) : "#FFF"};
}
`;
const StyledText = styled.span`
font-size: 16px;
font-weight: ${props => (props.fontWeight ? props.fontWeight : 400)};
`;
const StyledIcon = styled(MaterialIcons.Lock)`
font-size: 15;
padding: 10px;
`;
const Button = props => {
let _icon = null;
const { children, icon } = props;
console.log("props", props);
if (icon) {
_icon = <StyledIcon size="48" title="Test icon" />;
}
console.log("StyledButton", StyledButton);
return (
<StyledButton>
<StyledText>{children}</StyledText>
{_icon}
</StyledButton>
);
};
export default Button;
If I directly export default StyledButton it works fine.
For some odd reason props were not passed onto the StyledComponent, however directly stating what I want works.
return (
<StyledButton
outlineColor={outlineColor}
background={background}
width={width}
color={color}
outline={outline}
>
<StyledText>{children}</StyledText>
{_icon}
</StyledButton>
);

Resources