React Styled Components Extend - reactjs

i'm trying to re-use and extend a styled-component with no luck. I suspect i haven't quite grasped how to properly use styled-components
I have a component that renders a chevron icon, based on what icon prop is passed to it. What i want to be able to do is export this component, then import it and extend its styles. ie - in this example remove its padding in Header.jsx:
Chevron.jsx
import React from 'react'
import styled from 'styled-components'
const StyledChevron = styled.i`
display: flex;
align-items: center;
justify-content: center;
padding: 14px;
cursor: pointer;
border-left: 1px solid #efefef;
transition: all .1s linear;
transform: rotate(0deg);
${props=>props.closed && ``};
&:hover {
background: #f7f4f4;
}
`
const Chevron = (props) => {
return (
<StyledChevron closed={props.item.closed} onClick={()=>{props.openSubMenu(props.item.id)}} className={props.icon}/>
)
}
export default Chevron
Header.jsx
import React from 'react'
import styled from 'styled-components'
import cssvars from '../../js/style/vars'
import Chevron from './Chevron'
const StyledHeader = styled.div`
display: flex;
align-items: center;
padding: 11px;
justify-content: space-between;
background: ${cssvars.primaryColor};
h2 {
font-size: 19px;
color: #fff;
display: flex;
align-items: center;
}
`
const BackChevron = Chevron.extend`
padding: 0
`
const Header = (props) => {
return (
<StyledHeader>
<h2>{props.item.title}</h2>
<BackChevron {...props} icon="icon-arrow-left"/>
</StyledHeader>
)
}
export default Header
With the above code, im getting console error: Uncaught TypeError: _Chevron2.default.extend is not a function

styled-components has some kind of inheritance
Chevron.jsx
import React from 'react'
import styled from 'styled-components'
const StyledChevron = styled.i`
display: flex;
align-items: center;
justify-content: center;
padding: 14px;
cursor: pointer;
border-left: 1px solid #efefef;
transition: all .1s linear;
transform: rotate(0deg);
${props => props.closed && ``};
&:hover {
background: #f7f4f4;
}
`
const Chevron = (props) => (
<StyledChevron
closed={props.item.closed}
onClick={() => props.openSubMenu(props.item.id)}
className={props.icon}
/>
)
export default Chevron
Header.jsx
import React from 'react'
import styled from 'styled-components'
import cssvars from '../../js/style/vars'
import Chevron from './Chevron'
const StyledHeader = styled.div`
display: flex;
align-items: center;
padding: 11px;
justify-content: space-between;
background: ${cssvars.primaryColor};
h2 {
font-size: 19px;
color: #fff;
display: flex;
align-items: center;
}
`
const BackChevron = styled(Chevron)`
padding: 0
`
const Header = (props) => (
<StyledHeader>
<h2>{props.item.title}</h2>
<BackChevron {...props} icon="icon-arrow-left"/>
</StyledHeader>
)
export default Header
as said in #yury-tarabanko comment

Related

Set Background Image using props in Styled Components

This is the Home Component. I am passing the Details as props to Main component
import React from 'react'
import Main from '../components/Main'
import Navbar from '../components/Navbar'
const Home = () => {
return (
<div>
<Navbar/>
<Main
title = "Model Y"
text = "Schedule a Demo Drive"
bgImg = "../assets/model-x.jpg"
leftBtnText = "Custom Order"
rightBtnText = "View Inventory"
/>
</div>
)
}
export default Home
This is the main components
import React from 'react';
import styled from 'styled-components';
import KeyboardArrowDownOutlinedIcon from '#mui/icons-material/KeyboardArrowDownOutlined';
const Container = styled.div`
height: 100vh;
width: 100%;
/* background-image: url('../assets/model-y.jpg'); */
background-image: ${props => `url(${props.bgImage})`};
background-size: cover;
background-position: center;
background-repeat: no-repeat;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
gap:15rem;
`;
const Heading = styled.div`
flex:3;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
`;
const Title = styled.h1`
font-size: 2.7rem;
font-weight: 700;
color:#202328;
`;
const Text = styled.p`
font-weight:500;
font-size: 1rem;
letter-spacing: 0.4px;
cursor: pointer;
color:#202328;
`;
const Line = styled.span`
height: 1.1px;
background-color: black;
width: 100%;
`;
const Buttons = styled.div`
display: flex;
align-items: center;
gap: 2rem;
`;
const Bottom = styled.div`
flex:1;
display:flex;
flex-direction: column;
align-items: center;
gap:2rem;
`;
const ButtonLeft = styled.button`
padding: 0.6rem 6rem;
border-radius: 0.5rem;
border: none;
font-size: 1rem;
font-weight: 900;
background-color: rgba(23,26,32,0.8);
color: white;
opacity:0.80;
cursor: pointer;
`;
const ButtonRight = styled(ButtonLeft)`
background-color: white;
color: #202328;
opacity:0.70;
`;
const DownArrow = styled.div`
animation:bounce infinite 1s;
color:white;
cursor:pointer;
`;
const Main = (props) => {
return (
<Container bgImage={props.bgImg}>
<Heading>
<Title>{props.title}</Title>
<Text>
{props.text}
</Text>
<Line/>
</Heading>
<Bottom>
<Buttons>
<ButtonLeft>{props.leftBtnText}</ButtonLeft>
<ButtonRight>{props.rightBtnText}</ButtonRight>
</Buttons>
<DownArrow>
<KeyboardArrowDownOutlinedIcon fontSize='large'/>
</DownArrow>
</Bottom>
</Container>
)
}
export default Main
The file structure (for Images path)
enter image description here
I want the background Image I am passing as props to be visible.
After using the above code it looks like this
enter image description here
As you can see the Image is not visible behind but in inspect you can clearly see the correct url for image is there.
Please Help.
You should import the background image.
import bg from '../assets/model-x.jpg';
and pass the imported bg to the bgImg props.
like this:
import React from 'react'
import Main from '../components/Main'
import Navbar from '../components/Navbar'
import bg from '../assets/model-x.jpg';
const Home = () => {
return (
<div>
<Navbar/>
<Main
title="Model Y"
text="Schedule a Demo Drive"
bgImg={bg}
leftBtnText = "Custom Order"
rightBtnText = "View Inventory"
/>
</div>
)
}
export default Home

React Component not loading in localhost

i am currently following a tutorial to build a react website, however, i am unable to load NavBar (code is below) on my localhost. the web pack is being complied successfully and i am able to load a normal header, just not NavBar. i have attached the codes below. appreciate all the helps and inputs. tia
video that i am following: https://www.youtube.com/watch?v=Nl54MJDR2p8&t=375s
App.js
import './App.css';
import Navbar from './components/NavBar';
import { BrowserRouter as Router } from 'react-router-dom';
function App() {
return (
<Router>
<Navbar />
</Router>
);
};
export default App;
index.js for NavBar
import React from 'react';
import { FaBars } from 'react-icons/fa';
import { Nav, NavbarContainer, NavLogo, MobileIcon, NavMenu, NavItem, NavLinks } from './NavBarElements';
const Navbar = () => {
return (
<>
<Nav>
<NavbarContainer>
<NavLogo to='/'>Blockchain Voting System</NavLogo>
<MobileIcon>
<FaBars />
</MobileIcon>
<NavMenu>
<NavItem>
<NavLinks to="about">About</NavLinks>
</NavItem>
</NavMenu>
</NavbarContainer>
</Nav>
</>
);
};
export default Navbar;
NavBarElements.js
import styled from 'styled-components'
import { Link as LinkR } from 'react-router-dom'
import { Link as LinkS } from 'react-scroll'
export const Nav = styled.nav`
background: #000;
height: 80px;
// margin-top: -80px;
display: flex;
justify-content: center;
align-items: center;
font-size: 1rem;
position: sticky;
top: 0;
z-index: 10;
#media screen and (max-width: 960px){
transition: 0.8s all ease;
}
`;
export const NavbarContainer = styled.div`
display: flex;
justify-content: space-between;
height: 80px;
z-index: 1;
width: 100%;
padding: 0 24px;
max-width: 1100px;
`;
export const NavLogo = styled(LinkR)`
color: red;
justify-self: flex-start;
cursor: pointer;
font-size: 1.5rem;
display: flex;
align-items: center;
margin-left: 24px;
font-weight: bold;
text-decoration: none;
`;
export const MobileIcon = styled.div`
display: none;
#media screen and (max-width: 768px) {
display: block;
position: absolute;
top: 0;
right: 0;
transform: translate(-100%, 60%);
font-size: 1.8rem;
cursor: pointer;
}
`;
export const NavMenu = styled.ul`
display: flex;
align-items: center;
list-style: none;
text-align: center;
margin-right: -22px;
#media screen and (max-width: 768px) {
display: none;
}
`;
export const NavItem = styled.li`
height: 80px;
`;
export const NavLinks = styled(LinkS)`
color: #fff;
display: flex;
align-items: center;
text-decoration: none;
padding: 0 1 rem;
height: 100%;
cursor: pointer;
&.active {
border-bottom: 3px solid #01bf71;
}
`;

Passing custom props to styled-component in typescript [duplicate]

This question already has answers here:
Using styled-components with props and TypeScript
(8 answers)
Closed 1 year ago.
I'm new to React with Typescript and Styled-Component and I came across this issue. I created a 'Header' component and I was trying to pass the state whenever the button is clicked into the HeaderStyled as a probs to change the CSS style depends on the state but I got error.
import React, {useState} from 'react'
import HeaderStyled from './Header_styled';
const Header = () => {
const [open,setOpen] = useState(false);
return (
<HeaderStyled open={open}>
<img src="/images/logo.svg" alt="sunnyside_logo" />
<ul>
<li>About</li>
<li>Services</li>
<li>Projects</li>
<li><button>CONTACT</button> </li>
</ul>
<div onClick={() => setOpen(!open)}>
<div></div>
<div></div>
<div></div>
</div>
</HeaderStyled>
)
}
export default Header;
Here is my HeaderStyled component
const HeaderStyled = styled.div `
background-color: ${theme.primaryBlue};
display: flex;
justify-content: flex-end;
padding: 20px 20px;
align-items: center;
ul {
position: absolute;
background-color: white;
top: 6%;
width: 80%;
height: 25%;
right: 10%;
display: flex;
flex-direction: column;
padding: 0px;
align-items: center;
justify-content: space-around;
transform: ${({open}) => open ? 'translateX(0)': 'translateX(120%)'};
li {
padding: 0px;
a {
color: #0000002e;
}
}
button {
background-color: yellow;
color: black;
}
}
The error I got from HeaderStyled
Have a look in the Styled Components docs for Typescript - Using custom props
import React, { useState } from "react";
import styled from "styled-components";
interface Props {
open: boolean;
}
const HeaderStyled = styled.div<Props>``;
const Header = () => {
const [open, setOpen] = useState(false);
return <HeaderStyled open={open}></HeaderStyled>;
};
export default Header;
The way to do it in TS is to define a type or an interface and add that to the styled component:
type HeaderStyledProps = {
open: boolean;
}
const HeaderStyled = styled.div<HeaderStyledProps>`
background-color: ${theme.primaryBlue};
display: flex;
justify-content: flex-end;
padding: 20px 20px;
align-items: center;
ul {
position: absolute;
background-color: white;
top: 6%;
width: 80%;
height: 25%;
right: 10%;
display: flex;
flex-direction: column;
padding: 0px;
align-items: center;
justify-content: space-around;
transform: ${({open}) => open ? 'translateX(0)': 'translateX(120%)'};
li {
padding: 0px;
a {
color: #0000002e;
}
}
button {
background-color: yellow;
color: black;
}
}
`

Refactoring styled components [duplicate]

This question already has answers here:
idiomatic way to share styles in styled-components?
(3 answers)
Closed 2 years ago.
I'm using styled components and I have different elements/icons that require the same styling. What is a way to refactor this if I have separate types of "icons" but with same styling? What is the correct syntax for minimizing repetition in my styled component code?
import React from 'react';
import styled from 'styled-components';
import FolderIcon from 'src/assets/images/folder.svg';
import ListIcon from 'src/assets/images/clipboard.svg';
const StyledIcon = styled.div`
width: 32px;
height: 32px;
display: flex;
align-items: center;
`;
const StyledListIcon = styled(ListIcon)`
width: 32px;
height: 32px;
display: flex;
align-items: center;
`;
const StyledFolderIcon = styled(FolderIcon)`
width: 32px;
height: 32px;
display: flex;
align-items: center;
`;
const MenuItem = (props) => {
const { label, nodeType, onClick, icon } = props;
return (
<MenuItem onClick={onClick}>
{nodeType === 'LIST' ? (
<StyledListIcon />
) : icon ? (
<StyledIcon>{icon}</StyledIcon>
) : (
<StyledFolderIcon />
)}
<span>{label}</span>
</MenuItem>
);
};
export default MenuItem;
Thats a use case for css blocks:
const iconStyle = css`
width: 32px;
height: 32px;
display: flex;
align-items: center;
`;
const StyledIcon = styled.div`
${iconStyle}
`;
const StyledListIcon = styled(ListIcon)`
${iconStyle}
`;
const StyledFolderIcon = styled(FolderIcon)`
${iconStyle}
`;

How to center buttons with styled-components?

Can't figure out how to center 2 buttons horizontally with styled-components.
Below is my code.
Tried many ways to center, but didn't work.
import React from "react"
import styled from "styled-components"
const HomeStyles = styled.div`
h1 {
font-size: 1.5em;
text-align: center;
color: royalblue;
}
button {
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid royalblue;
border-radius: 3px;
color: royalblue;
}
`
export default function Home() {
return (
<HomeStyles>
<h1>Title</h1>
<button>Button1</button>
<button>Button2</button>
</HomeStyles>
)
}
UPDATE: I need to center buttons horizontally
Have you tried using flexbox on parent element?
const HomeStyles = styled.div`
display: flex;
flex-direction: column;
justify-items: center;
align-items: center;
....
`;
const ButtonsWrapper = styled.div`
display: flex;
justify-items: center;
align-items: center;
`;
<HomeStyles>
<h1>Title</h1>
<ButtonsWrapper>
<button>Button1</button>
<button>Button2</button>
</ButtonsWrapper>
</HomeStyles>

Resources