material-ui: [base][Tab] React does not recognize the `ownerState` prop

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Current behavior 😯

Following the example explained here the code works as expected:

<Tabs value={currentTab}>
  <Tab label="Inbox" value="/inbox/:id" to="/inbox/1" component={Link} />
  <Tab label="Drafts" value="/drafts" to="/drafts" component={Link} />
  <Tab label="Trash" value="/trash" to="/trash" component={Link} />
</Tabs>

However, when I try to replicate a similar behavior with the TabsUnstyled this way:

<TabsUnstyled value={currentTab}>
  <TabsListUnstyled>
    <TabUnstyled value="/inbox/:id" to="/inbox/1" component={Link}>
      Inbox
    </TabUnstyled>
    <TabUnstyled value="/drafts" to="/drafts" component={Link}>
      Drafts
    </TabUnstyled>
    <TabUnstyled value="/trash" to="/trash" component={Link}>
      Trash
    </TabUnstyled>
  </TabsListUnstyled>
</TabsUnstyled>

The browser raises the following error:

Warning: React does not recognize the ownerStateprop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercaseownerstate instead. If you accidentally passed it from a parent component, remove it from the DOM element.

I’m passing the Link component from the react-router-dom library to both the Tab and TabUnstyled, if it helps to understand the issue better.

Expected behavior 🤔

No errors thrown when using TabUnstyled.

Steps to reproduce 🕹

Code Sandbox

Context 🔦

No response

Your environment 🌎

  System:
    OS: Linux 5.10 Debian GNU/Linux 11 (bullseye) 11 (bullseye)
  Binaries:
    Node: 18.2.0 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 8.9.0 - /usr/local/bin/npm
  Browsers:
    Chrome: Not Found
    Firefox: Not Found
  npmPackages:
    @emotion/styled:  10.3.0
    @mui/base: ^5.0.0-alpha.76 => 5.0.0-alpha.79
    @mui/icons-material: ^5.6.1 => 5.6.2
    @mui/material: ^5.6.1 => 5.6.4
    @mui/private-theming:  5.6.2
    @mui/styled-engine-sc: ^5.6.1 => 5.6.1
    @mui/system: ^5.6.4 => 5.6.4
    @mui/types:  7.1.3
    @mui/utils:  5.6.1
    @types/react: ^18.0.3 => 18.0.9
    react: ^18.0.0 => 18.1.0
    react-dom: ^18.0.0 => 18.1.0
    styled-components: ^5.3.5 => 5.3.5
    typescript: ^4.6.4 => 4.6.4

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 3
  • Comments: 16 (9 by maintainers)

Most upvoted comments

We just merged the prepareForSlot util. If you are using third party components in some of the slots and you don’t need to use the ownerState you can just wrap the component with the prepareForSlot function. See e.g.: https://deploy-preview-38138--material-ui.netlify.app/base-ui/getting-started/customization/#system-PrepareForSlot.js

import * as React from 'react';
import { prepareForSlot } from '@mui/base/utils';
import { Button } from '@mui/base/Button';
import Link from 'next/link';

const LinkSlot = prepareForSlot(Link);

export default function PrepareForSlot() {
  return (
    <Button href="/" slots={{ root: LinkSlot }}>
      Home
    </Button>
  );
}

It will be available with the next release: @mui/base@5.0.0-beta.11

I have changed the styled engine to “styled-components”, and add the code below to resolve problems like this once for all

    <StyleSheetManager shouldForwardProp={isPropValid}>
      <RouterProvider router={router} />
    </StyleSheetManager>

We added the component/components props, so developers can customize the components (slots) used inside the “owner” unstyled component. To be able to customize based on the internal state of the component, the ownerState is passed into any custom component you provide. Obviously, as you noticed, this can create an issue if a component is used that simply spreads all the props it receives. To work around this problem, wrap the Link component in a custom one that will stop spreading the ownerState prop, like so:

const LinkWrapper = React.forwardRef(function LinkWrapper(props, ref) {
  const { ownerState, ...other } = props;
  return <Link {...other} ref={ref} />;
});

We need to update the docs to state what’s going on more clearly.

Please let me know if it helps.


@andrejstas could you please show concrete examples of your use cases (a codesandbox would be great)? We are evaluating different solutions to this problem but need to know how developers customize the components.

We are in process of adding types for slots of all the unstyled components. Tab hasn’t been covered yet, but once it’s done, you won’t need // @ts-ignore.

I am getting a similar error:

React does not recognize the `slotProps` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `slotprops` instead. If you accidentally passed it from a parent component, remove it from the DOM element.

When using the DatePicker.

I’m trying to add some unit tests on my components that use Material UI. I already have tried the solutions above none of them seems to work for me. I have styled components installed on my project because I need some custom components as well.

   "@mui/icons-material": "^5.11.16",
    "@mui/material": "^5.14.5",
    "@mui/styled-engine": "^5.12.0",
    "@mui/styled-engine-sc": "^5.12.0",

My tests are always throwing this error.

console.error
Warning: React does not recognize the `ownerState` prop on a DOM element. If you intentionally want it to appear in the 
DOM as a custom attribute, spell it as lowercase `ownerstate` instead. If you accidentally passed it from a parent 
component, remove it from the DOM element.

This is the component that seems to be throwing the error. It is a custom PassordField. The prepareForSlot function should be able to stop the warning on tests, shouldn’t it?

import { prepareForSlot } from "@mui/base/utils";
import Visibility from "@mui/icons-material/Visibility";
import VisibilityOff from "@mui/icons-material/VisibilityOff";
import {
  FormControl,
  IconButton,
  InputAdornment,
  InputLabel,
  OutlinedInput,
} from "@mui/material";
import { useState } from "react";

const PasswordField = (props: any) => {
  const [toggle, setToggle] = useState(false);

  return (
    <FormControl fullWidth sx={{ marginTop: 1.5 }}>
      <InputLabel>Password</InputLabel>
      <OutlinedInput
        {...props}
        type={toggle ? "text" : "password"}
        endAdornment={
          <InputAdornment position="end">
            <IconButton
              aria-label="toggle password visibility"
              onClick={() => setToggle((s) => !s)}
              edge="end"
            >
              {toggle ? <VisibilityOff /> : <Visibility />}
            </IconButton>
          </InputAdornment>
        }
      />
    </FormControl>
  );
};

export default prepareForSlot(PasswordField);

The code is running normally only in the tests I have those annoying warnings. Thanks for your attention

We’ve recently discussed the topic extensively and come up with this solution: We will introduce a helper function that will wrap 3rd party components and discard ownerState from their props. This way, we won’t introduce new props, new contexts wrapping each component or any breaking changes.

The usage will look as follows:

import { Link } from 'react-router-dom';

const LinkSlot = createSlot(Link); 

// ...

  return (
    <TabsUnstyled value={currentTab}>
      <TabsListUnstyled>
        <TabUnstyled value="/inbox/:id" to="/inbox/1" component={LinkSlot}>
          Inbox
        </TabUnstyled>
        <TabUnstyled value="/drafts" to="/drafts" component={LinkSlot}>
          Drafts
        </TabUnstyled>
        <TabUnstyled value="/trash" to="/trash" component={LinkSlot}>
          Trash
        </TabUnstyled>
      </TabsListUnstyled>
    </TabsUnstyled>
  );

I’m getting the same errors when using MenuUnstyled, MenuItemUnstyled and InputUnstyled components, also using the latest @mui/base package (5.0.0-alpha.82)