Overriding a styled-component with new styled-component? - css

I have a three styled-components StyledBanner and StyledTitle and WarningBanner.
I am looking to overwrite StyledBanner color through WarningBanner but is is not working out and the return Component always fall back to the div color.
How can I restyle a styled-component?
const StyledBanner = styled.div`
background-color: ${theme.colors.blue_2};
padding: 15px;
display: flex;
flex-direction: column;
border-radius: 4px;
width: 100%;
`;
const StyledTitle = styled(PG)`
font-size: 1.125rem;
font-weight: bold;
padding: 0px 0px 15px 0px;
colors: ${theme.colors.blue_2}
`
const WarningBanner = styled(StyledBanner)`
background-color: ${theme.colors.banner_yellow}
${StyledTitle}{
colors: ${theme.colors.textColor}
`
...
return (<WarningBanner> //still showing theme.colors.blue_2
{title ? <StyledTitle> //still showing theme.colors.blue_2
{title}
</StyledTitle> : null}
</WarningBanner>)

You have a minor typo in your posted code (the CSS property you want to set is color, not plural). Otherwise, your approach is perfectly valid.
Working example: https://codepen.io/mattlubner/pen/XWrvQLP
const theme = {
colors: {
red: '#f00',
greed: '#0f0',
blue: '#00f',
yellow: '#ff0',
},
};
const StyledBanner = window.styled.div`
background-color: ${theme.colors.blue};
padding: 15px;
display: flex;
flex-direction: column;
border-radius: 4px;
width: 100%;
`;
const StyledTitle = window.styled.h1`
font-size: 1.125rem;
font-weight: bold;
padding: 0px 0px 15px 0px;
color: ${theme.colors.blue};
`;
const WarningBanner = window.styled(StyledBanner)`
background-color: ${theme.colors.yellow};
${StyledTitle} {
color: ${theme.colors.green};
`;
ReactDOM.render(
<WarningBanner>
<StyledTitle>Example Title</StyledTitle>
</WarningBanner>,
document.getElementById('root'),
);

Related

CSS using styled-components and color themes messing up

Image of the problem.
So i have themes and colors defined in my React app.
Everything works well except these labels. When i change the theme to green and then change it back to blue and then when i focus on the input, the color again changes to the opposite theme. I don't understand what I'm doing wrong. Also this problem only occurs after i change the theme. Initially when i focus on the input the label remains blue.
This is my code for the theme part.
{
type: "light",
primaryColor1: "#33b2ff", //lightest
primaryColor2: themeColor === "blue" ? "#009fff" : "#00b05d", //ChangeColor()
primaryColor3: "#007fcc", //darkest
textColor1: "#111", //darkest
textColor2: "#555",
textColor3: "#888", //lightest
backgroundColor1: "#fcfcfc", //lightest
backgroundColor2: "#e3e3e3",
backgroundColor3: "#cacaca", //darkest
borderColor: "009fff",
white: "#fff",
black: "000",
}
This object returns all my theming colors but the primary color part is where it checks a state called themeColor which when set to blue, returns blue as the primary color for the entire app or green if otherwise. The entire app is wrapped with useContext's Provider and the Theme is passed via styled-components' ThemeProvider like so:
import { ThemeProvider } from "styled-components";
<ThemeContext.Provider value={{theme,themeToggler,themeColor,setThemeColor}}>
<ThemeProvider theme={themeStyle}>
{children}
</ThemeProvider>
</ThemeContext.Provider>
This is the CSS part using styled-components for the Input and Label elements:
export const Input = styled.input( ({theme}) => `
border-radius: 10px;
width: 100%;
font-size: 1rem;
background: ${theme.backgroundColor3};
border: 0;
color: ${theme.textColor1};
line-height: 50px;
padding: 5px 20px;
box-sizing: border-box;
font-family: Montserrat;
&:focus
{
outline: none;
}
&[type=password]
{
font-size: 1.75rem;
}
`);
export const Label = styled.label( ({theme}) => `
font-size: 1rem;
font-family: Montserrat;
color: ${theme.textColor3};
cursor: text;
position: absolute;
top: 30%;
left: 5.5%;
border: 1px solid ${theme.borderColor};
transition: 0.2s ease all;
background: none;
${Input}:focus + &,
${Input}:not(:placeholder-shown) + &
{
background: ${theme.primaryColor2};
padding: 0.2rem 0.5rem 0.2rem;
border-radius: 0.5rem;
top: -15%;
left: 3%;
font-size: 0.9rem;
color: #fff;
}
`);
Maybe !important rule solve your problem. You can try write !important after your css properties.
Example:
background: ${theme.primaryColor2} !important;

How to concate two styled div using props in styled component

I want to concate two div in a styled component using prop value
import styled, { css } from 'styled-components';
interface Props {
isValue: boolean;
}
export const sample = css`
display: flex;
justify-content: space-between;
padding: 20px 0 0 16px;
`;
export const sample1 = styled.div<Props>`
border-bottom: 1px solid red;
padding-bottom: 20px;
overflow: hidden;
${(props) => (props.isValue ? sample : '')};
`;
I have tried the above code , it is not working
Requirement: If isValue is true sample should get added to sample1 as shown below
so sample1 should contain
padding-bottom: 12px;
overflow: hidden;
display: flex;
justify-content: space-between;
padding: 12px 0 0 16px;
If isValue is false it should show only sample1 values

How to add a css property only when condition true using styled components and react?

i wanted to add border property only when isOpen condition true using styled components and react.
below is my code,
const Wrapper = styled.div<{ $isOpen: boolean }>`
border: 1px solid black;
display: flex;
`;
How to apply border only when isOpen is true?
could someone help me with this. thanks.
You can try like this:
const Wrapper = styled.div`
display: flex;
${({isOpen}) =>
isOpen &&
css`
{
border: 1px solid black;
}`
}
`;
Grabbing an example from the home page of styled-components:
import styled, { css } from 'styled-components'
const Button = styled.button`
background: transparent;
border-radius: 3px;
border: 2px solid palevioletred;
color: palevioletred;
margin: 0 1em;
padding: 0.25em 1em;
${props =>
props.primary &&
css`
background: palevioletred;
color: white;
`};
`
How you would use it in the react renderer:
render(
<Container>
<Button>Normal Button</Button>
<Button primary>Primary Button</Button>
</Container>
);

React: Caret icon keeps moving outside of dropdown menu whenever page is resized to iPad or smaller

I have a styled react component that features a hand rolled dropdown menu including a caret icon and every time I test the responsiveness of the dropdown the caret icon pops outside. I've wrapped the dropdown inside of a larger component to place everything on the same line and then included the icon inside of the styled select component. I've used this methodology in another app and the dropdown is completely responsive and doesn't have any issues with icon placement so I'm completely scratching my head with this one. Any help/suggestions would be great
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'
import { FaCaretDown } from 'react-icons/fa'
import Table from '../core/Table'
import SubHeader from '../elements/SubHeader'
import EligibleOffer from './EligibleOffer'
import { tableDataProps, tableColumnProps } from '../../propTypes'
const BUNDLE_KEY = 'bundle'
const rowKey = 'id'
class OfferBundlesTable extends Component {
static propTypes = {
bundles: PropTypes.arrayOf(tableDataProps),
columns: tableColumnProps,
viewedOfferIds: PropTypes.arrayOf(PropTypes.string),
onBundleSelect: PropTypes.func
}
static defaultProps = {
viewedOfferIds: []
}
renderCell = (cell = {}) => (
<div>
{cell.title && <SubHeader>{cell.title}</SubHeader>}
<p>{cell.details}</p>
</div>
)
renderBundle = bundle => (
<StyledOffer
offer={bundle}
onOfferSelect={this.props.onBundleSelect}
viewed={this.props.viewedOfferIds.includes(bundle.OfferId)}
/>
)
getColumns = columns =>
Object.entries(columns).reduce(
(cols, [key, value]) => ({
...cols,
[key]: {
...value,
renderCell: key === BUNDLE_KEY ? this.renderBundle : this.renderCell
}
}),
{}
)
render() {
const { bundles = [], columns = [] } = this.props
return (
<div>
<DropdownRow>
<StyledSelect>
<StyledStrong>SORT BY: </StyledStrong>
<select>
<option>Default</option>
<option>Promo Price (High to Low)</option>
<option>Promo Price (Low to High)</option>
<option>Alphabetically (A-Z)</option>
<option>Alphabetically (Z-A)</option>
<option>Internet Tier (High to Low)</option>
<option>Internet Tier (Low to High)</option>
</select>
<StyledSelectIcon size="1.5rem" />
</StyledSelect>
<StyledSelect>
<StyledStrong>CONTRACT TERMS (MONTHS):</StyledStrong>
<select>
<option>36</option>
<option>24</option>
<option>12</option>
</select>
<StyledSelectIcon size="1.5rem" />
</StyledSelect>
</DropdownRow>
<StyledTable
rowKey={rowKey}
rows={bundles}
columns={this.getColumns(columns)}
/>
</div>
)
}
}
const StyledTable = styled(Table)`
th:first-child {
width: 25%;
}
`
const StyledOffer = styled(EligibleOffer)`
margin-bottom: 15px;
`
const DropdownRow = styled.div`
th:first-child {
width: 25%;
}
flex: 1;
display: flex;
align-items: stretch;
padding: 20px 30px 20px 10px;
width: 60%;
margin-left: 42%;
`
const StyledSelectIcon = styled(FaCaretDown)`
position: absolute;
top: 0;
right: 10px;
bottom: 0;
margin: auto;
color: black;
pointer-events: none;
`
const StyledSelect = styled.div`
position: relative;
margin-left: auto;
select {
padding: 5px 45px 5px 10px;
font-size: 1.2rem;
line-height: 1.4rem;
font-weight: 500;
color: black;
border: 2px solid black;
height: 36px;
appearance: none;
background: transparent;
border-radius: 0;
}
`
const StyledStrong = styled.strong`
padding-right: 5px;
`
export default OfferBundlesTable
After looking at your code, I would suggest an alternative approach, including the caret in the css for your select. This makes it impossible for it to move away from the select, as it's now part of it. Run the snippet below to see it work--of course you would want to put that stuff into the styled-component css definition, and remove the <StyledSelectIcon/> altogether (here's a forked stackblitz).
Styled component definition:
const StyledSelect = styled.div`
position: relative;
margin-left: auto;
select {
padding: 5px 45px 5px 10px;
font-size: 1.2rem;
line-height: 1.4rem;
font-weight: 500;
color: black;
border: 2px solid black;
height: 36px;
background-color: transparent;
border-radius: 0;
-moz-appearance: none;
-webkit-appearance:none;
appearance: none;
background-image: url('data:image/svg+xml;utf8,<svg fill="black" viewBox="0 0 320 512" height="1.5rem" width="1.5rem" xmlns="http://www.w3.org/2000/svg"><path d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"></path></svg>');
background-repeat: no-repeat;
background-position: right 8px center;
}
`
Snippet to run here:
.customselect{
padding: 5px 45px 5px 10px;
font-size: 1.2rem;
line-height: 1.4rem;
font-weight: 500;
color: black;
border: 2px solid black;
height: 36px;
background-color: transparent;
border-radius: 0;
-moz-appearance: none;
-webkit-appearance:none;
appearance: none;
background-image: url('data:image/svg+xml;utf8,<svg fill="black" viewBox="0 0 320 512" height="1.5rem" width="1.5rem" xmlns="http://www.w3.org/2000/svg"><path d="M31.3 192h257.3c17.8 0 26.7 21.5 14.1 34.1L174.1 354.8c-7.8 7.8-20.5 7.8-28.3 0L17.2 226.1C4.6 213.5 13.5 192 31.3 192z"></path></svg>');
background-repeat: no-repeat;
background-position: right 8px center;
}
<select class="customselect">
<option>Option A</option>
<option>Option B</option>
<option>Option C</option>
<option>Option D</option>
</select>

Is there a way to modify '&:before/:after' to give a dynamic property?

A styled-component that has &:before attribute that I want to give access to a dynamic color property. But I'm lost to how to apply that.
I've Tried passing the props to <Hover /> and it works. But the Triangle in &:before cannot access that.
const Hover = styled.div`
padding:7px;
margin: -102px auto;
border-style: solid;
border-radius: 15px;
border-width: 3px;
text-align: left;
font-weight: 400;
font-size: 19px;
color: #000000;
font-family: sans-serif;
position: absolute;
left:-15px;
z-index:10;
&:before {
content: "";
width: 0px;
height: 0px;
position: absolute;
border-left: 10px solid ;
border-right: 10px solid transparent;
border-top: 10px solid ;
border-bottom: 10px solid transparent;
left: 19px;
bottom: -19px;
z-index:10;
}
`;
As a single styled-component the following class is:
class MarkerHover extends Component {
render() {
const {color, children}= this.props
return (
<Hover style={{backgroundColor: color }}>
{...children}
</Hover>
);
}
}
export default MarkerHover;
I expect to have a whole colored Window after successfully passing the color props to the &:before division.
As the documentation of Styled Components states (see https://www.styled-components.com/docs/basics#passed-props) you can read passed props:
const Hover = styled.div`
color: ${props => props.color};
`;
when you pass them like this:
<Hover color="#f00" />
You can use that same prop in your pseudo-element as well:
const Hover = styled.div`
color: ${props => props.color};
&::before {
background: ${props => props.color};
}
`;
So don't use the style attribute on your styled component, but pass regular props.
If you want to apply a CSS rule only after a certain condition, you can do that like this:
const Hover = styled.div`
color: #ccc;
&::before {
content: "";
padding: 16px;
${props => props.withBg ? `background-color: ${props.withBg}` : ''}
}
`;
With background:
<Hover withBg="#f00" />
Without background:
<Hover />

Resources