Is there a way to declare styled component with different main elements? - reactjs

I need to create 2 similar styled components, which will share their styling but use different HTML element.
There is a way to do in runtime with "as" property (), but I have a specific exports which I need to use the default but I need for it to be in a way without using it so the Link styled component be a "styled.a" and StyledLink component to be "styled.span", I tried to do something like:
export const StyledLink = styled.span(`
color: ${props => props.theme.colors.mainLinkColor};;
text-decoration: underline;
&:hover {
color: ${props => props.theme.colors.textAccent};
text-decoration: underline;
}
`);
export const Link = <StyledLink as={RRLink} />;
That is obviously not working... So is there a way for a Link to mimic StyledLink styles but use an "a" tag instead of "span"?

Simply import and use css from styled-components like so:
import React from "react";
import ReactDOM from "react-dom";
import styled, { css } from 'styled-components';
const sharedStyles = css`
background-color: gold;
`;
const Div = styled.div`
${sharedStyles}
`;
const Button = styled.button`
${sharedStyles}
`;
const App = () => (
<>
<Div>Hello Div</Div>
<Button>Hello Button</Button>
</>
);
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Related

how to change styled(component) element

Having trouble changing the "section" into a div without touching the BaseGrid, the BaseGrid is in a different folder component, and I'm just importing it. If I use the forwardedAs='div' or as='div', it will render as a div but will not pass the default values that I still need from the BaseGrid.
How can I make it as a div and still get all the props that i need from the BaseGrid styled.section
const BaseGrid = styled.section `
....style here
`;
import {BaseGrid} from '/somefolder';
const SectionGrid = styled(BaseGrid).attrs({as: 'div'})`
..style here
`;
const SectionGrid = ({ forwardedAs, className, children, ...rest }: SectionGridProps) => (
<BaseGrid forwardedAs={'div'} className={addClassName('section-grid', className)} {...rest}>
{children}
</BaseGrid>
);
const app () => {
return
<>
<SectionGrid />
</>
};
I'm trying to implement these but still not working
import React from "react";
import ReactDOM from "react-dom";
import styled from "styled-components";
import "./styles.css";
const ExtendMe = styled.div`
color: red;
border: 1px solid red;
`;
const SomeImg = styled(ExtendMe).attrs({
as: "img"
})`
margin: 2em;
`;
const SomeDiv = styled(ExtendMe)`
margin: 3em;
`;
function App() {
return (
<div className="App">
<SomeImg src="data:image/jpeg;base64,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" />
<SomeDiv>A div</SomeDiv>
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
You can refer: https://www.styled-components.com/docs/api#as-polymorphic-prop.

how can i fix use location error in my react app?

import styled from "styled-components";
import Navbar from "../componant/Navbar";
import Announcement from "../componant/Announcement";
import Products from "../componant/Products";
import Newsletter from "../componant/Newsletter";
import Footer from "../componant/Footer";
import { mobile } from "../responsive";
import { useLocation } from "react-router";
import { useState } from "react";
const Container = styled.div``;
const Title = styled.h1`
margin: 20px;
`;
const FilterContainer = styled.div`
display: flex;
justify-content: space-between;
`;
const Filter = styled.div`
margin: 20px;
${mobile({ width: "0px 20px", display: "flex", flexDirection: "column" })}
`;
const FilterText = styled.span`
font-size: 20px;
font-weight: 600;
margin-right: 20px;
${mobile({ marginRight: "0px" })}
`;
const Select = styled.select`
padding: 10px;
margin-right: 20px;
${mobile({ margin: "10px 0px" })}
`;
const Option = styled.option``;
const ProductList = () => {
const location = useLocation();
const cat = location.pathname.split("/")[2];
const [filters, setFilters] = useState({});
const [sort, setSort] = useState("newest");
const handleFilters = (e) => {
const value = e.target.value;
setFilters({ ...filters, [e.target.name]: value, });
};
return (
{cat} Filter Products: Color white black red blue yellow green Size XS S M L XL Sort Products:
<Select onChange={(e) => setSort(e.target.value)}> Newest Price (asc) Price (desc)
);
};
export default ProductList;
The error useLocation() may be used only in the context of a <Router> component. is caused by an invariant violation. The error message is clear enough, you've not rendered the ProductList component using the useLocation hook within a routing context provided by a Router.
This is react-router-dom version 6
useLocation
export function useLocation(): Location {
invariant(
useInRouterContext(),
// TODO: This error is probably because they somehow have 2 versions of the
// router loaded. We can help them understand how to avoid that.
`useLocation() may be used only in the context of a <Router> component.`
);
return React.useContext(LocationContext).location;
}
You should have a single router wrapping your App component to provide a routing context to the entire app, which would including this ProductList component.
import { BrowserRouter as Router } from 'react-router-dom';
import App from './App';
ReactDOM.render(
<React.StrictMode>
<Router>
<App />
</Router>
</React.StrictMode>,
document.getElementById('root')
);
Based on some comments of yours from the other answer it appears you are mixing up the RRDv5 and RRDv6 components. V6 has no Switch component, it was replaced by a Routes component.
Check the installed version of react-router and react-router-dom:
npm run list react-router react-router-dom
If you have v5 installed, follow the v5 docs, otherwise if you've v6 installed, see the v6 docs. The upgrading from v5 migration guide will detail the differences between the two versions.
Wrap your app in Routes component.
import React from "react";
import {
BrowserRouter as Router,
Routes,
} from "react-router-dom";
const AppWrapper = () => {
return (
<Router>
<Routes>
<App />
</Routes>
</Router>
);
};
export default AppWrapper;

Link component not working with Styled Components

The style not working
const MenuOption = styled(Link)`
font-size: 14px;
`;
Only using pseudo-class that styles its works
The better way is to Make a styled div or ul and then wrap it around link tag. Maybe make a component for it.
Example:
const NavBarLinkDiv = styled.div`
//your styles
`;
export default const NavBarLink = ({ children, to }) => {
return (
<Link to={to}>
<NavBarLinkDiv>{children} </NavBarLinkDiv>
</Link>
);
};

hide imported child component on hover using styled-components

Like the title says, this works with styled components sitting within the same js file (provided they are procedural-ordered above). But with imported child components I can't get it to work.
import React from "react";
import styled from "styled-components";
// Components
import Bars from "../path/Bars.js";
import BarsHover from "../path/BarsHover.js";
// Variables
import { colors } from "../../path/index.js";
//============================================ styles =============================================
const DivBars = styled(Bars)``;
const DivBarsHover = styled(BarsHover)``;
const DivWrapper = styled.div`
display: flex;
width: 20rem;
margin-bottom: 3rem;
&:hover {
cursor: pointer;
}
&:hover ${DivBars} {
display: none;
}
&:hover ${DivBarsHover} {
display: block;
}
`;
//=========================================== component ===========================================
const ParentComponent = props => {
return (
<DivContainer>
<DivBars fullBarWidth={"100%"} fractionBarWidth={"70%"} barColor={colors.niagara} />
<DivBarsHover fullBarWidth={"100%"} fractionBarWidth={"70%"} barColor={colors.gallery2} />
</DivContainer>
);
};
export default ParentComponent;
I think this caveat is the cause:
...wrapping A in a styled() factory makes it eligible for
interpolation -- just make sure the wrapped component passes along
className.
class A extends React.Component {
render() {
return <div className={this.props.className} />
}
}
const StyledA = styled(A)``
const B = styled.div`
${StyledA} {
}
`
NOTE: Ensure the className prop is propagated all the way to the component being referenced in the case that it isn't a direct descendent.

How do you pass an image to a styled component?

I'm using styled-components in ReactJS and I'm trying to create a component that can take in the background-image as a prop. After some research, I've tried this:
import SpeechBubble1 from '../images/home_images/Speech 1.png';
...
const SpeechBubble = styled.div`
background-image: url(${props => props.background});
`;
...
<SpeechBubble background={SpeechBubble1} />
But it doesn't work. Checking in the browser element window, I can see I'm getting an Invalid property value for background-image.
What am I doing wrong?
Edit:
I also tried doing this, which hasn't worked:
<SpeechBubble style={{background: `url(${SpeechBubble1})`}} />
Make sure you are including a height for the styled component, otherwise, it won't display anything (unless it has children that define its dimensions).
Working example:
components/Container
import styled from "styled-components";
const Container = styled.div`
height: 100vh;
background-image: url(${({ background }) => background});
background-repeat: no-repeat;
background-size: cover;
`;
export default Container;
index.js
import React, { Fragment } from "react";
import { render } from "react-dom";
import reactbg from "./images/reactbg.png";
import Container from "./components/Container";
import GlobalStyles from "./components/GlobalStyles";
import Title from "./components/Title";
const App = () => (
<Fragment>
<GlobalStyles />
<Container background={reactbg}>
<Title>Hello World</Title>
</Container>
</Fragment>
);
render(<App />, document.getElementById("root"));
Index.js
import React from 'react'
import {ProfilePic} from './NavigationElements'
import profileimg from '../../images/profileimg.jpg'
const Navigation = () => {
return (
<NavigationWrapper>
<ProfilePic src={profileimg} alt="" />
</NavigationWrapper>
)
}
export default Navigation
NavigationElements.js
import styled from "styled-components";
export const NavigationWrapper = styled.div`
color: #fff;
`
export const ProfilePic = styled.img`
width: 5vh;
height: 3vh;
margin: 55px;
`
You can use inline styling:
<SpeechBubble style={{background: `url(${SpeechBubble1})`}} />

Resources