Styling a dynamic component in React using styled-components

I encountered a challenge that requires some creative problem-solving:

In my project, I have defined various icons using components from Material-UI, each accompanied by additional props for flexibility in rendering. Now, imagine a scenario where I need to use the same icon but styled differently - one instance should be red while the other green. However, MUI icons do not natively support color props (aside from predefined options), so I turned to CSS for styling.

Typically, with styled-components, I would style the icon like this:

const StyledIcon = styled(AssignmentIcon)`
  color: red
`

The challenge arises when I don't know in advance which specific icon I'll need to style, as certain components may receive varying icons like AssignmentIcon and BugReportIcon. Since defining styled components inside another component isn't feasible with styled-components, I had to find a workaround.

My solution involves a helper function called styleIcon, capable of dynamically taking a React.ComponentType, applying styling through styled(), and returning the modified icon for rendering.

This approach feels somewhat convoluted, relying on helper functions to achieve the desired outcome. Are there simpler methods to tackle this issue? (Note: using style={{}} props directly during icon rendering is not suitable, as it could clash with other applied styles through prop spreading)

Answer №1

Your component should have the ability to switch to different colors easily.

  const color = props => props.color || 'red'

  const StyledIcon = styled.div`
    color: ${color};
  `

If a specific color is specified, it will be used, like this:

  return <StyledIcon color="blue" />

In cases where using a theme mode is preferred, for example, StyledComponent supports themes.

https://styled-components.com/docs/advanced

Even if you don't want to stick with one theme all the time, you can dynamically apply different themes at runtime.

  <ThemeProvider theme={theme1}>
    // A
    <ThemeProvider theme={theme2}>
      // B
      <Button>Themed</Button>
    </ThemeProvider>
    // C
  </ThemeProvider>
  // D

The locations A, B, C, and D will each receive different themes:

  • A. theme1
  • B. theme2
  • C. theme1
  • D. defaultTheme

The basic solution should provide insight, but if not, consider utilizing the advanced theme options offered by StyledComponent.

Answer №2

It seems like you're looking to change the color of Material UI icons without explicitly styling them. I've devised a solution using a wrapper that can take Material UI icons as child nodes.

To start, we'll define the styling for the wrapper:

const StyledIcon = styled.span<{color: string}>`
  svg, .icon {
    color: ${props => props.color}; // You can even pass a hex color
  }
`

Next, create a separate React component. While you can use the styled component directly, creating a separate component will help with managing states and effects in the future:

interface ColorfulIconProps {
  color: string;

  [k: string]: any;
}

const ColorfulIcon: React.FC<ColorfulIconProps> = ({ color, children, ...rest }) => {
  // Manage states and effects here

  return (
    <StyledIcon color={color} {...rest}>
      {children}
    </StyledIcon>
  );
};

Finally, to utilize this setup, simply pass the desired Material UI icons or your custom icon set formatted as svg:

const App = () => {
  return (
    <ColorfulIcon color="red">
      <AMaterialUIIcon />
    </ColorfulIcon>
  );
};

Check out the live demo: https://codesandbox.io/s/modern-brook-oecgn?file=/src/StyledIcon.tsx

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

Looking to troubleshoot the "404 page not found" error in React JS?

This code snippet includes the navigation bar component that is currently functioning without any issues. navBar.jsx import React, { useEffect, useState } from 'react'; import './navbar.css' import { Link, useLoaderData, useNavigate } f ...

How can we create a touch and mouse-friendly horizontal scrolling navigation pattern?

I am trying to implement horizontal scrolling for video testimonials in a single row on a responsive website, but I am encountering an issue. The width of the container class is larger than col-12, which leaves space and causes horizontal scroll on the pag ...

I am facing an issue with TypeScript as it is preventing me from passing the prop in React and Zustand

interface ArticuloCompra { id: string; cantidad: number; titulo: string; precio: number; descuento: number; descripcion: string; imagen: string; } const enviarComprasUsuarios = ({ grupos, }: { grupos: { [key: string]: ArticuloCompra & ...

What is the solution to resolving a JavaScript error involving the insertBefore() method?

<body> <div class="container mt-4"> <h1 class="display-4 text-center"> <i class="fas fa-car text-success"></i> My<span class="text-success ">Car</span>List</h1> <form id="ca ...

A guide on extracting data from various HTML elements effectively with JavaScript

I'm searching for a universal technique to extract values from multiple HTML elements. For instance: <div>Experiment</div> <select><option>Experiment</option></select> <input value="Experiment" /> These thr ...

What is causing the additional space at the bottom?

Why does my centered black border triangle have an extra bottom margin causing a scroll bar to appear? * { margin: 0; padding: 0; box-sizing: border-box; } body { height: 100vh; width: 100%; background: blue; } .canvas { border: 10px s ...

What is the best way to conceal the second and fourth rows of a table using either css or jquery?

I have a piece of code that is dynamic and I need to hide the second and fourth 'tr' elements of the table with the id HMP_options. How can I accomplish this? <table id="HMP_options" width="100%" cellspacing="0" cellpadding="0" border="0"> ...

steps to troubleshoot the issue of "Firefox unable to connect to the server at 127.0.0.1:8081"

const http = require("http"); http.createServer(function (req, res){ res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('Hey there!\n'); }).listen(8081); console.log('Server is up and running at http://1 ...

Is there a way to extract variables from a MySQL database and integrate them into a JavaScript function?

Hello everyone, I am looking to add markers on a map. In order to do this, I need to extract longitude and latitude from a database table. 1- I have used JavaScript to display the map (Google Maps). var map; var initialize; initialize = function( ...

React is displaying [object Object] instead of the intended value on the webpage. What steps can be taken to resolve this issue?

I have attempted to retrieve data from an API and am currently working on displaying this data within a table cell inside a component. Instead of rendering the original data, React is displaying [object Object]. I tried using the join() method with commas ...

The absence of the import no longer causes the build to fail

Recently, after an update to the yup dependency in my create react-app project, I noticed that it stopped launching errors for invalid imports. Previously, I would receive the error "module filename has no exported member X" when running react-scripts buil ...

Navigating through React Native using Navigation 5: A guide to configuring passing parameters to buttons

I am facing an issue with navigating to another screen in my project. Currently, I have a task where clicking a button should take me to the group chat screen and pass parameters to the routes. The error I encountered today is "undefined is not an object ( ...

Material UI Alert component not appearing on screen?

Greetings, I have been working on polishing my app now that it is finally complete. I decided to enhance the aesthetics by replacing all instances of window.alerts with Alerts from MUI (since they look way better). However, for some reason, they are not sh ...

Tips for dynamically adding rows to an HTML table using Bootstrap, utilizing values from a dropdown list in .NET 5.0

1. Description: I am currently working on a project related to creating an invoice page. In order to fill the row data, I have implemented a dropdown selection (as I couldn't find a better alternative). However, I am facing an issue where selecting ...

The Intersection of Material-UI, TypeScript, and Powerful Autocomplete Features

In my TypeScript project, I'm attempting to develop a Material-UI AutoComplete component that retrieves the input value based on an object's property name -> obj[key] However, when using the prop getOptionLabel, I encountered the following er ...

What is the best way to showcase the outcomes of a map function in JSX?

I'm currently learning react and working on implementing the searchMap function (to display movie title/poster) with the TMDB API. While I am able to successfully log the necessary information to the console, I am encountering issues such as undefined ...

Dealing with object properties that may not always be present in Vue.js template tags

Encountering a fatal error TypeError: Cannot read properties of null (reading 'propThatSometimesDoesNotExist') when utilizing the code below: <template> <div> <img v-if="obj.propThatSometimesDoesNotExist" :src=" ...

Vue: update data and trigger function upon completion of animation transformation, utilizing animation transformation completion listener

Check out this straightforward Vue example: https://codesandbox.io/s/sleepy-haze-cstnc2?file=/src/App.vue https://i.stack.imgur.com/zboCb.png Whenever I click on the square, it not only changes color but also expands to 200% of its original size with a 3 ...

Alignment within bootstrap using accordion

I am new to using bootstrap. Currently, I am creating a simple FAQ page with bootstrap and facing some challenges. https://i.sstatic.net/6fUW3.png I have been trying to adjust the position and margin of elements, but I am struggling to center the title a ...

Elevate the opacity with a hover effect

I am currently in the process of building my own website using siteorigin page builder on wordpress. One issue I have encountered is that they do not offer a hover option, so I had to create a custom CSS to add a hover effect on the background color. When ...