sazzledazzle
sazzledazzle

Reputation: 63

Conditional styling using Styled Components

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

Answers (3)

Drew Reese
Drew Reese

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>

Demo

Edit conditional-styling-using-styled-components

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>
  );
}

enter image description here

Upvotes: 4

the_previ
the_previ

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

Ezequiel S. Sandoval
Ezequiel S. Sandoval

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

Related Questions