What is the best way to efficiently pass a prop from a Parent styled component to its children's styled components, regardless of how deeply nested they are?

I am utilizing these customized components:

import styled, { css } from 'styled-components'

const Container = styled.div`
  background-color: ${props => props.theme === "light" ? "hsl(0, 0%, 98%)" : "hsl(235, 24%, 19%)" };
  border-radius: 4px;
  box-shadow: ${props => props.theme === "light" ? "0px 35px 50px -15px rgba(194, 195, 214, 0.5)" : "0px 35px 50px -15px rgba(0, 0, 0, 0.5)" };
`

const Footer = styled.footer`
  padding: 25px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: ${props => props.theme === "light" ? "hsl(236, 9%, 61%)" : "hsl(234, 11%, 52%)" };
  font-size: 14px;
`

const Nav = styled.nav`
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: inherit;
`

const NavItem = styled.a`
  cursor: pointer;
  display: inline-block;
  color: inherit;

  &:hover {
    color: ${props => props.theme === "light" ? "hsl(235, 19%, 35%)" : "hsl(236, 33%, 92%)" };
  }

  &:not(:last-of-type) {
    margin-right: 15px;
  }

  ${({ active }) =>
    active &&
    css`
      color: hsl(220, 98%, 61%);
    `
  }
`

const ClearList = styled.p`
  color: inherit;
  cursor: pointer;

  &:hover {
    color: ${props => props.theme === "light" ? "hsl(235, 19%, 35%)" : "hsl(234, 39%, 85%)" };
  }
`

In addition, I have this component labeled TodoList with a theme property that is passed to the styled components in this manner:

const TodoList = ({ theme }) => {
  return (
    <Container theme={theme}>
      <Footer theme={theme}>
        <p>5 items left</p>
        <Nav>
          <NavItem theme={theme}>All</NavItem>
          <NavItem theme={theme}>Active</NavItem>
          <NavItem theme={theme}>Completed</NavItem>
        </Nav>
        <ClearList theme={theme}>Clear Completed</ClearList>
      </Footer>
    </Container>
  )
}

export default TodoList

Is there a way for me to pass the theme property only once in the Container element and have it accessible to all nested elements such as Clearlist, NavItems, and Footer without explicitly passing them?

Many thanks

Answer №1

To resolve this issue, consider implementing ThemeProvider in your solution

For more information, please check out the following link https://styled-components.com/docs/advanced

Here is an example:

// Customizing button styles using props.theme
const Button = styled.button`
  color: ${props => props.theme.fg};
  border: 2px solid ${props => props.theme.fg};
  background: ${props => props.theme.bg};

  font-size: 1em;
  margin: 1em;
  padding: 0.25em 1em;
  border-radius: 3px;
`;

// Setting `fg` and `bg` properties on the theme object
const theme = {
  fg: "palevioletred",
  bg: "white"
};

// Creating a new theme by swapping `fg` and `bg` colors
const invertTheme = ({ fg, bg }) => ({
  fg: bg,
  bg: fg
});

render(
  <ThemeProvider theme={theme}>
    <div>
      <Button>Default Theme</Button>

      <ThemeProvider theme={invertTheme}>
        <Button>Inverted Theme</Button>
      </ThemeProvider>
    </div>
  </ThemeProvider>
);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

``Inconvenience of Extensive URLs Being Displayed in Tables

I've been struggling to find a solution for the problem I'm facing with Chrome when it comes to wrapping long URLs in a table cell. Despite trying various solutions found online, including using the CSS code word-wrap: break-word;, I have not bee ...

Combining Multiple Arrays into a Single Array

Is there a way to combine this merge operation that creates one array using forEach into a single array at the end? affProd.pipe(mergeMap( event1 => { return fireProd.pipe( map(event2 => { const fi ...

Tips on incorporating variable tension feature into D3 hierarchical edge bundling

I found a d3 sample on hierarchical edge bundling that I am experimenting with - My main focus is how to add tension functionality to the example provided at the following link (code can be found here): While I have reviewed the code in the first link, I ...

Displaying a secondary table within the Material-table detail panel

I've been attempting to incorporate a dense table from Material-UI below the detail panel of a Material-Table, but I'm struggling to make it work. The goal is to display the id, project_name, and links on the main table, and when clicking on a p ...

Javascript: Anticipating a Return from an Argument

I am currently working on a function that requires an attribute to respond before proceeding with its process. The function call is structured like this : processResult(getResult()); The issue lies in the fact that the getResult function takes some time ...

React - “Error: localStorage is undefined” displayed

Currently, I am working on optimizing my website for SEO by using meta tags and implementing server-side rendering in my application. However, I encountered an issue that shows the following error: An error occurred: ReferenceError - localStorage is not ...

When the page is scrolled to 50 pixels, a modal pop-up will appear

I attempted to use cookies to store a value when the user clicks on a popup to close it, ensuring that the popup does not show again once closed. However, I am encountering an issue where the popup continues to open whenever I scroll, even after closing it ...

Encountering Excessive Open Files Error with NextJS Deployment

I'm encountering a challenge in my Production environment during peak traffic hours. Any assistance with pinpointing the origin of this issue would be greatly appreciated. Error logs - [Error: EMFILE: too many open files, open '/app/.next/static ...

Exploring the combination of Material-UI's Box Component and Drawer Component for enhanced user interface

The Material-UI Box component enables us to reference other components in the following manner: import Button from "@material-ui/core/Button"; import Box from "@material-ui/core/Box"; const CustomButton = ({ children }) => ( <Box compoment={Butto ...

Why is the toggle functioning properly?

After much trial and error, I finally got my toggle functionality working with the following code. I was surprised that toggling the width actually changed the display settings, but it did the trick! It's still a bit mysterious to me how it all works ...

unable to perform a specific binary operation

Is there an efficient method to achieve the following using binary operations? First byte : 1001 1110 Second byte : 0001 0011 Desired outcome : 1000 1100 I am looking to reset all bits in the first byte that correspond to bit values of 1 in the secon ...

jQuery is great at adding a class, but struggles to remove it

When you click on an anchor with the class .extra, it adds the "extra-active" class and removes the "extra" class. However, when you click on an anchor with the extra-active class, it does not remove the extra-active class and replace it with extra. Here ...

The LoopBack framework encountered an issue where it could not execute the 'post' method due to being undefined

As a newcomer to loopback and node.js, I have successfully created two models - Rating and RatingsAggregate. Utilizing the loopback explorer, querying and posting against the API has been smooth. In an attempt to establish basic business logic, I am curre ...

Is there a way to remove a row through fetch using onclick in reactjs?

I'm completely new to this and struggling with deleting a row using fetch. I've written some messy code and have no idea if it will even work. Please help, I feel so lost... renderItem(data, index) { return <tr key={index} > &l ...

Uncaught TypeError: Cannot read property 'e' of undefined in vue.js

Feeling a bit frustrated now :( This is my first time trying to use vue.js, which comes after jQuery as the second JS framework I'm diving into on this planet. Here's the HTML code I have: var main = new Vue({ el: ".main-content", data: { ...

Conceal elements when they are too small without the use of JavaScript

I want to be able to hide content when the window size is below a certain point. After finding an example at (http://css-tricks.com/dynamic-page-replacing-content/), I still couldn't figure out why it actually works. <div class="container"> ...

Learn the process of integrating VueJS with RequireJS

I am attempting to set up VueJS with RequireJS. Currently, I am using the following VueJS library: . Below is my configuration file for require: require.config({ baseUrl : "js", paths : { jquery : "libs/jquery-3.2.1.min", fullcalendar : "libs/ful ...

Content below divs that are fixed and absolutely positioned

I have a design layout similar to this (a small snippet) and I am facing an issue where the text within .content is not clickable. The positioning of #gradient is fixed due to the background image, and #empty has an absolute position to cover the entire bo ...

Caught up: TypeScript not catching errors inside Promises

Currently, I am in the process of developing a SPFx WebPart using TypeScript. Within my code, there is a function dedicated to retrieving a team based on its name (the get() method also returns a promise): public getTeamChannelByName(teamId: string, cha ...

Using AngularJS to handle form data without ng-model

I am facing a unique situation that may seem a bit strange. I have a form that needs to edit/update information from different objects, such as services. My goal is to use ng-model to link input fields to their respective objects, but when the form is sub ...