Reputation: 63
I've been trying for hours to figure this out, and I'm sure the answer is simple. When an Item is clicked, it will ultimately create a filter for my todo list. What I'm struggling to do is apply conditional styling, so that the font color of the 'active' item is blue.
I have included status
as a prop, but I can't seem to use it as well as props inside the styled components.
From my App.js:
import { useState } from 'react'
function App() {
const [ status, setStatus ] = useState("all")
return (
<Filter status={status} setStatus={setStatus}/>
)
}
Filter.js
const Container = styled.div`
display: flex;
justify-content: center;
`
const Item = styled.p`
color: red;
// I'm trying to do something like this..
${(status, props) => {
if (status === props.id) {
return `
color: blue;
`
}
}}
`
export const Filter = ({ setStatus, status }) => {
const statusHandler = (e) => {
if (e.target.id) {
setStatus(e.target.id)
}
}
return (
<div>
<Container onClick={statusHandler}>
<Item id="all">All</Item>
<Item id="active">Active</Item>
<Item id="completed">Completed</Item>
</Container>
</div>
)
}
Upvotes: 4
Views: 5703
Reputation: 203427
Pass both the status
and id
props to the Item
component and do the comparison in the props callback.
const Item = styled.p`
color: red;
${({ id, status }) => status === id && 'color: blue; '}
`;
Usage:
<Item id="all" status={status}>All</Item>
You could make this simpler though with a single prop and do the conditional test in the component.
const Item = styled.p`
color: red;
${({ isStatusMatch }) => isStatusMatch && "color: blue;"}
`;
...
<Item isStatusMatch={status === 'all'}>All</Item>
Full demo code:
const Item = styled.p`
color: red;
${({ id, status }) => status === id && "color: blue;"}
`;
const Item2 = styled.p.attrs(({ id, status }) => ({
className: id === status && "statusMatch"
}))`
color: red;
&.statusMatch {
color: blue;
}
`;
const Item3 = styled.p`
color: red;
${({ statusMatch }) => statusMatch && "color: blue;"}
`;
function App() {
return (
<div className="App">
<Item id="test" status="test">
test
</Item>
<Item id="nottest" status="test">
not test
</Item>
<Item2 id="test" status="test">
test
</Item2>
<Item2 id="nottest" status="test">
not test
</Item2>
<Item3 statusMatch={"test" === "test"}>test</Item3>
<Item3 statusMatch={"nottest" === "test"}>not test</Item3>
</div>
);
}
Upvotes: 4
Reputation: 682
I think the easiest way to perform this task is to add a class at the element you want to change the color.
So you're item will be
const Item = styled.p`
color: black;
&.selected {
color: red
}
and you're Component will be:
<>
<Item id="all" className={status === "all" ? "selected" : null}>All</Item>
<Item id="active" className={status === "active" ? "selected" : null}>Active</Item>
<Item id="completed" className={status === "completed" ? "selected" : null}>Completed</Item>
</>
To avoid to write repeating code you can loop the values. And here we go:
const items = [
{
id: "all",
value: "All"
},
{
id: "active",
value: "Active"
},
{
id: "completed",
value: "Completed"
},
]
items.map(({id, value}) => (
<Item key={id} id={id} className={status === id ? "selected" : null}>{value}</Item>
))
There's no need to put logic in Styled Component if you can keep in React
Upvotes: 3
Reputation: 170
You can try something like:
// YOUR STYLES
const activeStyles = (props) => ({
color: props.status === props.id ? 'blue' : null
});
// YOUR FILTER COMPONENT
return (
<div>
<Container onClick={statusHandler}>
<Item id="all" styles={{...activeStyles({status, id:'all'})}}>All</Item>
<Item id="active" styles={{...activeStyles({status, id:'active'})}}>Active</Item>
<Item id="completed" styles={{...activeStyles({status, id:'completed'})}}>Completed</Item>
</Container>
</div>
)
Upvotes: 0