Why are Styled Component props displaying as HTML attributes? - reactjs

I'm passing down boolean props to Styled Components to change styling based on the props that are passed into the Component, like so:
<Button href="#contact" small elevate={false} display="primary">
CONTACT
</Button>
The output of this JSX is invalid HTML that looks like this:
<a href="#contact" class="Button__ButtonWrapper-fvVzGy gOcROU" display="primary" fluid="0" elevate="0" small="1">
CONTACT
</a>
Any idea how to ensure props won't be displayed as HTML attrs?
Full Button component:
const ButtonWrapper = styled.button`
padding: ${props =>
props.small
? `${rem(6)} ${props.theme.sizes.sm}`
: `${rem(12)} ${props.theme.sizes.med}`};
box-shadow: ${props =>
props.elevate
? `0 10px 15px 0 rgba(0,0,0,0.10)`
: `0 2px 8px 0 rgba(0,0,0,0.10)`};
color: ${props => {
if (props.display === 'primary') return props.theme.buttons.primary.color;
if (props.display === 'secondary')
return props.theme.buttons.secondary.color;
}};
`;
const Button = ({
display,
fluid,
children,
cta,
elevate,
small,
...other
}) => {
<ButtonWrapper
display={display}
fluid={fluid ? 1 : 0}
elevate={elevate ? 1 : 0}
small={small ? 1 : 0}
{...other}
>
{children}
{cta && (
<div className="icon" dangerouslySetInnerHTML={{ __html: CtaIcon }} />
)}
</ButtonWrapper>
};
export default Button;

This documentation page might be helpful: https://www.styled-components.com/docs/basics#passed-props
Basically if you use a non-camelcase prop to do styling, it'll get passed through to the DOM node. We're looking into better alternatives to this pattern.

I have the exact same problem, when I pass width or height props in to a component they are visible on the html, I think that both words (and maybe others) are actually keywords because with the rest of props this doesn't happen.
Example:
<div class="Container-sc-10mm8fh-0 cyDjRF">
<div class="Line-sc-10mm8fh-1 oPRx"></div>
<div height="3rem" class="VSpace-sc-18gziyv-1 kkKpPd"></div>
<div class="Line-sc-10mm8fh-1 oPRx"></div>
<div height="0.4rem" class="VSpace-sc-18gziyv-1 kkKpPd"></div>
<div class="Line-sc-10mm8fh-1 oPRx"></div>
</div>

Related

How can i create a new div when i onclick the button in React js?

code 1 component:-
const TableheaderText = props => {
//const [playlist, setPlaylist] = useState(props);
const [playlist, setPlaylist] = useState("playlist");
const [showing, SetShowing] = useState();
const [isActive, setActive] = useState(true);
//console.log(playlist);
useEffect(() => {
// setPlaylist(props);
SetShowing("PLAYLIST:");
setPlaylist(props.val);
}, [props])
return (
<div className="mainContent">
<div className="tableHeaderBody" >
<div className="TableText" >
<div id="HIDE">{showing}</div><div id="SHOW">{playlist}</div>
</div>
<div className="ClossIcon"><FaCircle style={{ color: "#FC0000", width: "10px", height: "10px", alignItems: "right" }} /></div>
</div>
</div>
)
}
code 2 component:-
<NavLink to={`/Table`} onClick={(e) => myClick(val, index)} >
<button className='notActive buttonLeft'
onClick={() => handleOnClick(index)} // pass the index
className={activeIndex === index ? "active" : "notActive"}>
{val}
</button>
</NavLink>
Right now i have one div and when i click the menu value then one div replace the name
but i want that when i click the 1 value its create one div and when click the 2 value its create second div with the name of 2 div and place right side of 1 div and so.. (if 3,4 value menu ..)
This may be one possible solution to achieve the desired objective (copied from OP's question):
i want that when i click the 1 value its create one div and when click
the 2 value its create second div with the name of 2 div and place
right side of 1 div and so..
Code Snippet
const {useState} = React;
const Thingy = () => {
const myDivs = [...Array(4).keys()].map(i => `My Div # ${i+1}`);
const [flipDivs, setFlipDivs] = useState([
...myDivs.map(
(text, id) => ({id, text, show: false})
)
]);
const handleClick = e => {
const idx = e.target.id;
const newArr = [...flipDivs];
newArr[idx].show = !flipDivs[idx].show;
setFlipDivs(newArr);
};
const myButtons = [...Array(4).keys()];
return (
<div>
<div class="allDivs">
<div> Fixed Div </div>
{
flipDivs.filter(({show}) => !!show).map(
({text, id, show}, idx) => (
<div
key={idx}
class="simpleMargin rightBorder"
>
{text}
</div>
)
)
}
</div>
<div class="buttons">
{myButtons.map(id => (
<button
id={id}
class="simpleMargin"
onClick={handleClick}
>
{flipDivs[id].show ? 'Hide' : 'Show'} Div # {id+1}
</button>
))}
</div>
</div>
);
};
ReactDOM.render(
<div>
DEMO
<Thingy />
</div>,
document.getElementById("rd")
);
.allDivs {
border: 2px solid black;
width: fit-content;
display: flex;
align-items: center;
margin: 10px 15px;
}
.simpleMargin { margin: 5px 10px; }
.rightBorder { border: 2px solid black; }
.buttons {
display: flex;
margin: 10px 5px;
}
<div id="rd" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.0/umd/react-dom.production.min.js"></script>
Explanation
simple, straightforward approach
Add a flag to determine which div needs to be rendered on which button click
On the click-handler, simply update the flag to show / hide div
For this you need to make a div element and whoe it conditionally ( with state declared with useState ) and then toggle the state on button click to show it. like :
{
showDiv ? <div></div> : null
}
Here showDiv is:
const [showDiv, setShowDiv] = useState (false)
Now toggle showDiv on button click to true. :)

How do I add style inline the color code which I m getting from an array of object

Suppose my array of object is like this ms=[{id : 1 , Name : a , color : #333} {id : 2 , Name : b , color : #666} {id : 3 , Name : c , color : #ddd}]
Now my return in functional component
ms.map((eachname, index)=>
{
<div classname = mainbloc>
<div classname = insideblock style=.
{{borderRight: 1px solid ###}}>
{eachname.Name}
</div>
</div>
})
I want to add the color of each object in the border right ### place
Use template strings to embed javascript expressions or values between strings. You can do something like this.
ms.map((eachname, index) => (
<div classname="mainblock" key={index}>
<div
classname="insideblock"
style={{ borderRight: `1px solid ${eachname.color}` }}
>
{eachname.Name}
</div>
</div>
));
More information on template string:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals
In case, for some reason, you don't want to use template strings you can use:
style={{
borderRightWidth: 1,
borderRightWidth: 'solid',
borderRightColor: eachname.color,
}}
You can also use styled components if you don't want to use inline styling and make component more reusable and readable. More information Styled components
import styled from 'styled-components'
const StyledDiv = styled.div`
borderRight: ${props => props.color}
`
ms.map((eachname, index) => (
<div classname="mainblock" key={index}>
<StyledDiv color={eachname.color}>
{eachname.Name}
</StyledDiv>
</div>
));

How can i hover in React using useState

I wanna toggle a class when hovering on a Container by changing the opacity from 0 to 1, I've used onmouseEnter and onMouseLeave Event to toggle the class, but when I console hover state I see that is changing from true to false when I hover but the class "Show" is not changing.
What do you think ?
<--Components-->
import React,{useState} from 'react';
import './MyWork.css';
import {Visibility, GitHub } from "#material-ui/icons";
const SingleProject = ({src, title}) => {
const [hover, isHover] = useState(false);
const showIcons = isHover ? "Show" : "";
return (
<div className="card-container" onMouseEnter={()=> isHover(true)} onMouseLeave={()=> isHover(false)}>
<img src={src} alt={title}/>
<h1 id="card-title">{title}</h1>
<div className={`Info ${showIcons}`}>
<div className="Icon">
<GitHub/>
</div>
<div className="Icon">
<Visibility/>
</div>
</div>
</div>
)
}
export default SingleProject;
<--- Css--->
.card-container {
height: 314px;
width: 500px;
cursor: pointer;
position : relative;
}
.Info {
position: absolute;
height: 100%;
width: 100%;
top:0;
left:0;
display:flex;
justify-content:center;
align-items: center;
background-color: rgba(0, 0, 0, 0.5);
opacity: 0;
}
.Info.Show {
opacity: 1;
}
When assigning the value to showIcons, you need to use hover instead of isHover which is the setter function for that state.
Additionally, I recommend naming the setter function setHover to avoid confusion and be more semantic. You can also add conditional Show class like this, which is more concise:
iconst SingleProject = ({src, title}) => {
const [hover, setHover] = useState(false);
return (
<div
className="card-container"
onMouseEnter={()=> setHover(true)}
onMouseLeave={()=> setHover(false)}
>
<img src={src} alt={title}/>
<h1 id="card-title">{title}</h1>
<div className={`Info ${hover ? "Show" : ""}`}>
<div className="Icon">
<GitHub/>
</div>
<div className="Icon">
<Visibility/>
</div>
</div>
</div>
)
}
export default SingleProject;
You are using the setter instead of the state itself on your condition. Change isHover with hover like below:
const showIcons = hover ? "Show" : "";

Can't figure out how change css using props in styled components and a useState hook

Trying to change the grid-column value of a styled.div based on user input via styled buttons. I have the grid-column values set up as props in a styled component, like so:
const Highlight = styled.div`
display: block;
margin: -0.5rem;
padding: 0;
border: 1px solid #00fff3;
border-radius: 16px;
z-index: 2;
background: hsla(177, 100%, 21%, 0.25);
grid-row: 1 / 2;
grid-column:
${props =>
props.key === 'C' ? `1 / 9` :
props.key === 'Db' ? `2 / 10` :
props.key === 'Eb' ? `3 / 11` :
`1 / 9`
};
`
and the value of the prop is in state, like so:
const [ key, setKey ] = useState()
...then the prop is on the styled component, like so:
<Highlight key={key}/>
...then the value of that prop is changed when any of the following buttons is pressed:
<C onClick={() => setKey('C')}>C</C>
<D onClick={() => setKey('D')}>D</D>
<E onClick={() => setKey('E')}>E</E>
<F onClick={() => setKey('F')}>F</F>
<G onClick={() => setKey('G')}>G</G>
<A onClick={() => setKey('A')}>A</A>
<B onClick={() => setKey('B')}>B</B>
<DFlat onClick={() => setKey('Db')}>Db</DFlat>
<EFlat onClick={() => setKey('Eb')}>Eb</EFlat>
<GFlat onClick={() => setKey('Gb')}>F#/Gb</GFlat>
<AFlat onClick={() => setKey('Ab')}>Ab</AFlat>
<BFlat onClick={() => setKey('Bb')}>Bb</BFlat>
...but it does not work yet, so I'm not doing something right, or I am missing something, but I do not know what I'm doing wrong.
key is an implicit prop in ReactJS. From the docs:
Keys serve as a hint to React but they don’t get passed to your components. If you need the same value in your component, pass it explicitly as a prop with a different name
List and Keys - Docs
So to pass the prop, you need to use a different name from key and you should be good to go.
As stated on the react documentation, keys are a reserved attribute for elements in React
A “key” is a special string attribute you need to include when
creating lists of elements.
Therefore, you can consider changing your props to a more fitting name, such as gridColumnKey.
const Highlight = styled.div`
display: block;
margin: -0.5rem;
padding: 0;
border: 1px solid #00fff3;
border-radius: 16px;
z-index: 2;
background: hsla(177, 100%, 21%, 0.25);
grid-row: 1 / 2;
grid-column:
${props =>
props.gridColumnKey === 'C' ? `1 / 9` :
props.gridColumnKey === 'Db' ? `2 / 10` :
props.gridColumnKey === 'Eb' ? `3 / 11` :
`1 / 9`
};
`
And on your component that renders the Highlight styled component,
<Highlight gridColumnKey={key}/>

Background using props in react.js

Adding background by passing a variable in the input i.e validUrl. Anyone let me know if this background property works. Also imported both valid and invalid image.
background: ${ props => props.validUrl ? "url(${valid}) no-repeat left 10px center" : "url(${invalid}) no-repeat left 10px center" };
Write it like this using Template literals:
background: props.validUrl ? `url(${valid}) no-repeat left 10px center` : `url(${invalid}) no-repeat left 10px center`
Update:
Stories storiesOf("URLField", module) .add("default", () => (
<ThemeProvider theme={theme}>
<URLField validUrl={true} />
</ThemeProvider> )
)
const URLField = ({validUrl}) => (
<Wrapper>
<Urlwrapper>
<Input validUrl={validUrl} />
<Text>{urlDescription}</Text>
</Urlwrapper>
</Wrapper>
);
This is how it would be done as we need to pass the variable in outer wrapper. If its defined in the input then the styles according to property needs to be defined in input.js from where it is called. Updated code is as follows:
const URLField = ({ validUrl}) => (
<Wrapper validUrl={validUrl}>
<Urlwrapper>
<Input />
<Text>{domain}</Text>
</Urlwrapper>
</Wrapper>
);

Resources