Utilizing Material UI and TypeScript to effectively pass custom properties to styled components

Currently, I am utilizing TypeScript(v4.2.3) along with Material UI(v4.11.3), and my objective is to pass custom props to the styled component.

import React from 'react';
import {
  IconButton,
  styled,
} from '@material-ui/core';

const NavListButton = styled(IconButton)(
 ({ theme, panelOpen }: { theme: Theme; panelOpen: boolean }) => ({
   display: 'inline-block',
   width: 48,
   height: 48,
   borderRadius: 24,
   margin: theme.spacing(1),
   backgroundColor: panelOpen ? theme.palette.secondary.dark : 'transparent',
 }),
);

...

const Component: React.FC<Props> = () => {
  return (
    <NavListButton panelOpen={true} />
  );
};

The functionality works smoothly, but upon checking the browser console, it shows an error message.

Warning: React does not recognize the `panelOpen` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `panelopen` instead. If you accidentally passed it from a parent component, remove it from the DOM element.
    at button
    at ButtonBase ...

Is there a way to resolve this issue without resorting to using the styled-components module and sticking to using styled from Material UI?

Additionally, another related query arises.

I have a requirement to incorporate media queries into styled components, however, when attempted, it throws a

TypeError: Cannot read property 'addRule' of null
.

const PrintableTableContainer = styled(TableContainer)(() => ({
  '@media print': {
    '@page': { size: 'landscape' },
  },
}));

https://i.stack.imgur.com/XtzcF.png

I also experimented with the following approach.

const PrintableTableContainer = styled(TableContainer)`
  @media print {
    @page { size: landscape }
  }
`;

However, this alternative prompted the following error:

Argument of type 'TemplateStringsArray' is not assignable to parameter of type 'CreateCSSProperties<(value: string, index: number, array: readonly string[]) => unknown> | ((props: { theme: Theme; } & ((value: string, index: number, array: readonly string[]) => unknown)) => CreateCSSProperties<...>)'.
  Type 'TemplateStringsArray' is not assignable to type 'CreateCSSProperties<(value: string, index: number, array: readonly string[]) => unknown>'.
    Types of property 'filter' are incompatible.
...

Answer №1

Just sharing my thoughts, I hope the solution I suggest proves to be helpful for your situation.

The root of the issue lies in the version conflict within material-ui, where your project seems to be utilizing both version 4 and version 5 simultaneously.

Step 1: Upgrade to material-ui v5

  • @next version = v5
  • Install material-ui along with styled-engine to incorporate styled-components
// npm
npm install @material-ui/core@next @material-ui/styled-engine-sc@next styled-components
npm install --save-dev @types/styled-components


// yarn 
yarn add @material-ui/core@next @material-ui/styled-engine-sc@next styled-components
yarn add --dev @types/styled-components

Step 2: Implement react-app-rewired

As the default material-ui styled-engine is set to emotion, we need to override the webpack configuration to use styled-components instead.

The Official Documentation provides guidance on using styled-components in material-ui:

For create-react-app, install react-app-rewired

// npm 
npm install --save-dev react-app-rewired customize-cra

// yarn
yarn add --dev react-app-rewired customize-cra

Step 3: Customize webpack Configuration

Refer to the official example: https://github.com/mui-org/material-ui/tree/next/examples/create-react-app-with-styled-components-typescript

  • Create a new file named config-overrides.js
  • Update styled-engine path to point to styled-engine-sc path
// config-overrides.js
const { addWebpackAlias, override } = require('customize-cra');

module.exports = override(
  addWebpackAlias({
    '@material-ui/styled-engine': '@material-ui/styled-engine-sc',
  }),
);

Step 4: Utilize material-ui with styled-components

import { IconButton, styled, TableContainer, Theme } from "@material-ui/core";

const NavListButton = styled(IconButton)(
  ({ theme, $panelOpen }: { theme?: Theme, $panelOpen: boolean }) => ({
    display: "inline-block",
    width: 48,
    height: 48,
    borderRadius: 24,
    margin: theme?.spacing(1),
    backgroundColor: $panelOpen ? theme?.palette.secondary.dark : "transparent"
  })
);

const PrintableTableContainer = styled(TableContainer)(() => ({
  "@media print": {
    "@page": { size: "landscape" }
  }
}));

...

<NavListButton $panelOpen={true} />
<PrintableTableContainer />

In regards to the first question,

React does not recognize the `panelOpen` prop on a DOM element. 
.

styled-components offer transient props - $ as a solution to prevent custom props from being passed directly to the DOM.

https://styled-components.com/docs/api#transient-props


A demonstration repository is available for reference and troubleshooting if you encounter any difficulties implementing the changes

Answer №2

Encountered a comparable issue. I faced the following situation:

import styles from './MabSidebar.styles';
...
const Sidebar = styled(Box)(styles);

Resolved it hastily by resorting to a quick fix:

const Sidebar = styled(Box)(styles as any);

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

Leverage Ramda's clone function within a pipeline in a manner that ensures type safety

My goal is to utilize Ramda for cloning and updating objects in a type-safe manner, drawing inspiration from this approach. However, I am facing challenges implementing it in a type-safe way. Updating a nested object seems to work perfectly fine in a type ...

Exploring the process of dynamically incorporating headers into requests within react-admin

Currently utilizing react-admin with a data provider of simpleRestProvider. I am in need of a solution to dynamically add headers to requests based on user interactions. Is there a way to achieve this? Appreciate any assistance. Thank you! ...

What is the reason for injecting a service into 2 modules following the Singleton Pattern?

Here is the current file situation: AppService AppModule AModule AComponent BModule BComponent Regarding the Service, I have noticed that Angular will create two separate instances of the service if it is injected into two compone ...

Issue with displaying Typescript sourcemaps on Android device in Ionic 2

Encountering a strange behavior with Ionic2. After deploying my app to a simulator, I am able to view the .ts file sourceMap in the Chrome inspect debugger. In both scenarios, I use: ionic run android However, when deploying my APK on a real device, th ...

The HttpPut request code format is malfunctioning, although it is effective for another request

I'm struggling with a HTTPPUT request that just won't get called. Strangely enough, I have a similar put request that works perfectly fine for another tab even though both pages are practically identical. I've exhausted all options and can&a ...

How can I access members outside of a class without a name in Typescript?

I recently developed an "anonymous" class inspired by this insightful discussion on Typescript anonymous classes. However, I'm facing a challenge in accessing the outer scope members. Here's a snippet of my code for context: class BaseCounter { ...

Is it possible to have an interface, function, and variable all sharing the same name in a declaration?

Is it possible to have an interface, function, and variable all with the same name? For example, I would like to define the function as follows: declare function someName(...args: any[]); someName('foo'); The interface would look like this: ...

Angular asynchronous operations are failing to complete within the specified time frame

Observations suggest that Angular's async from @angular/core/testing is not properly resolving timeouts in tests when a beforeEach contains async as well. Sadly, the bug cannot be replicated on Plunkr or JSFiddle platforms. To reproduce this issue ea ...

Exploring ways to target a child div within props such as avatar and actions of cardHeader (a child of the card element from MaterialUI) using Jest and En

Currently, I am in the process of creating test cases for a React.js class using Jest and Enzyme frameworks. The class utilizes the Card component from Material UI, and a snippet of my code is shown below: <Card> <CardHeader avatar = ...

Restoring scroll position in Next.js when the page is reloaded

Problem Description I am facing an issue with the sticky header functionality I have implemented. It relies on a useEffect hook to monitor its scroll Y offset state. However, when I reload the page, it fails to detect the position until I manually scroll ...

Utilizing TypeScript 3.1: Easier Array Indexing with Enums in Strict Mode

Enabling TypeScript "strict" mode with "noImplicitAny" causes this code to fail compilation. I am looking for guidance on how to properly declare and use Arrays indexed by Enum values. namespace CommandLineParser { enum States { sNoWhere, sSwitchValu ...

Error: It is not possible to assign a value to the Request property of the Object since it only has a getter method

Encountering issues while attempting to deploy my Typescript Next.js application on Vercel. The build process fails despite functioning correctly and building without errors locally. Uncertain about the root cause of the error or how to resolve it. The f ...

What is the best method to add data to a child array located within a nested array?

Struggling to create an array that will display data in the following format: Healthcare -- Insights driven by data for improved healthcare -- Urban Analytics Transport -- Urban Analytics Cities -- Urban Analytics I have attempted ...

Ensure that a particular key type is determined by the value of another key within the object (Utilizing Discriminated Unions)

The title of my question may not have been clear about what I am looking for, but what I need is something known as discriminated unions. You can find more information about it here: https://www.typescriptlang.org/docs/handbook/unions-and-intersections.htm ...

The Material UI library is signaling that there is an unidentified property called `selectable` being used with the <table> tag

Whenever I try to add the selectable attribute to the Table component in Material-UI using React JS, I encounter an error. Despite checking that selectable is indeed included in TableProps, the issue persists. List of Dependencies : "material-ui": "1.0.0 ...

Creating a seamless navigation experience using Material UI's react Button and react-router-dom Link

Is there a way to have the Material UI react Button component behave like a Link component from react-router-dom while preserving its original style? Essentially, how can I change the route on click? import Button from '@material-ui/core/Button' ...

Retrieving the inner text of a dragged element using Angular Material's DragAndDrop feature

Can the inner text of a dragged element be retrieved and utilized in the "onDrop" function within Angular's cdkDragAndDrop feature? onDrop(event: CdkDragDrop<string[]>) { if (event.previousContainer === event.container) { moveItemIn ...

What's causing this MUI React data grid component to be rendered multiple times?

I have developed a wrapper for the MUI Data Grid Component as portrayed: Selection.tsx: import * as React from 'react'; import { DataGrid, faIR, GridSelectionModel } from '@mui/x-data-grid'; import type {} from '@mui/x-data-grid/t ...

Developing customizable React components with JSS

I'm struggling to understand the documentation on how to implement this feature Within my component, I have defined some styles that are meant to be applied universally. However, depending on the specific page the user navigates to within the app, I ...

Concealing tab bars on Ionic 2 secondary pages

In my Ionic Bootstrap configuration, I have the following setup: { mode: 'md', tabsHideOnSubPages: true } However, despite having this setting in place, the tabs still appear on some sub-pages. It seems to be happening randomly. Is there ...