Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[docs] component property on MUI components wrapped in styled in v6 #44931

Closed
khanilov opened this issue Jan 3, 2025 · 5 comments
Closed

[docs] component property on MUI components wrapped in styled in v6 #44931

khanilov opened this issue Jan 3, 2025 · 5 comments
Assignees
Labels
customization: css Design CSS customizability docs Improvements or additions to the documentation support: docs-feedback Feedback from documentation page

Comments

@khanilov
Copy link

khanilov commented Jan 3, 2025

Related page

https://mui.com/material-ui/migration/upgrade-to-v6/#breaking-changes-affecting-types

Kind of issue

Unclear explanations

Issue description

Hello, recently we tried to migrate our project to material v6, but faced an issue with styled and component property, that blocks us from completing migration. I wasn't able to find clear answers on that in docs, so I decided to open this issue to clear up the air around that.

First, seems like there is no more component property available in return type of styled() on any mui component in v6 compared to v5, not only the Box component that mentioned in breaking changes. Probably this should be mentioned properly in migration docs.

Second, the section about Box itself is confusing.

It suggests two options to fix missing component property in return type of styled(Box).

First suggestion is:

use a div element instead of Box

But next code have same typescript error of missing component property, as with using a Box component:

const StyledDiv = styled('div')``;

const Demo = () => {
    return <StyledDiv component={'a'} />;
};

Type '{ component: string; }' is not assignable to type 'IntrinsicAttributes & MUIStyledCommonProps & ClassAttributes & HTMLAttributes<...>'.
Property 'component' does not exist on type 'IntrinsicAttributes & MUIStyledCommonProps & ClassAttributes & HTMLAttributes<...>'.ts(2322)

So it's unclear what this first suggestion is about.

Second suggestion is:

you can also cast the styled returned value to typeof Box

This works, but only when you don't have additional custom properties passed to styled. Once you have them, typescript throws an error.

const StyledBox = styled(Box)<{ isClickable: boolean }>(({ isClickable }) => ({
    color: isClickable ? 'blue' : 'black',
})) as typeof Box;

Conversion of type 'StyledComponent<BoxOwnProps & Omit<Omit<DetailedHTMLProps<HTMLAttributes, HTMLDivElement>, "ref"> & { ...; }, keyof BoxOwnProps<...>> & MUIStyledCommonProps<...> & { ...; }, {}, {}>' to type 'OverridableComponent<BoxTypeMap<{}, "div", Theme>>' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Types of parameters 'props' and 'props' are incompatible.
Type '{ component: any; } & BoxOwnProps & Omit<any, keyof BoxOwnProps>' is not comparable to type 'BoxOwnProps & Omit<Omit<DetailedHTMLProps<HTMLAttributes, HTMLDivElement>, "ref"> & { ...; }, keyof BoxOwnProps<...>> & MUIStyledCommonProps<...> & { ...; }'.
Property 'isClickable' is missing in type '{ component: any; } & BoxOwnProps & Omit<any, keyof BoxOwnProps>' but required in type '{ isClickable: boolean; }'.ts(2352)

We have a lot of code in our code base that rely both on styled with additional custom properties and usage of component property on returned component and I am struggling to find clear documentation on that manner.

  1. Do component property in returning type of styled gone?
  2. Should styled('div') have component property in returning type or what was the meaning of that suggestion in migration guide?
  3. If type casting on returning type of styled to retain component property isn't an option due to additional custom properties passed to styled, what else we can do?

Thank you for your hard work, and looking forward for replies.

Context

In v5 we could write code like this to leverage both styles customisation and component composition:

import { Box, styled } from '@lingoda/ui';

const Demo = () => {
    return <StyledBox component={true ? 'button' : undefined} a={true} b={false} c={true} />;
};

const StyledBox = styled(Box)<{ a: boolean; b: boolean; c: boolean }>(({ a, b, c }) => ({
    color: a ? 'blue' : 'black',
    background: b ? 'white' : 'yellow',
    borderRadius: c ? 1 : 2,
}));

How can we achieve the same result in v6?

Search keywords: component, property, styled, typescript

@khanilov khanilov added status: waiting for maintainer These issues haven't been looked at yet by a maintainer support: docs-feedback Feedback from documentation page labels Jan 3, 2025
@zannager zannager added the docs Improvements or additions to the documentation label Jan 4, 2025
@DiegoAndai
Copy link
Member

DiegoAndai commented Jan 6, 2025

Hey @khanilov, thanks for reaching out.


  1. Do component property in returning type of styled gone?

This is a known issue, and I'm not sure why it worked for you before. The issue is reported here: #29875.

Here's the workaround: #29875 (comment)


  1. Should styled('div') have component property in returning type or what was the meaning of that suggestion in migration guide?

As you can see in the answer above, styled('div') won't have the component property.

The meaning of that section is that you can provide any tag to styled, so instead of

const StyledDiv = styled('div')``;

const Demo = () => {
    return <StyledDiv component={'a'} />;
};

You would do

const StyledA = styled('a')``;

const Demo = () => {
    return <StyledA />;
};

And if you need the component prop, you would do

const StyledDiv = styled('div')<{ component: React.ElementType }>``;

const Demo = () => {
    return <StyledDiv component={'a'} />;
};

  1. If type casting on returning type of styled to retain component property isn't an option due to additional custom properties passed to styled, what else we can do?

Taking your example:

import { Box, styled } from '@lingoda/ui';

const Demo = () => {
    return <StyledBox component={true ? 'button' : undefined} a={true} b={false} c={true} />;
};

const StyledBox = styled(Box)<{ a: boolean; b: boolean; c: boolean }>(({ a, b, c }) => ({
    color: a ? 'blue' : 'black',
    background: b ? 'white' : 'yellow',
    borderRadius: c ? 1 : 2,
}));

You can transform it to

import { styled } from '@lingoda/ui';

const Demo = () => {
  return <StyledDiv component={true ? 'button' : undefined} a={true} b={false} c={true} />;
};

const StyledDiv = styled('div')<{ a: boolean; b: boolean; c: boolean, component: React.ElementType | undefined }>(({ a, b, c }) => ({
  color: a ? 'blue' : 'black',
  background: b ? 'white' : 'yellow',
  borderRadius: c ? 1 : 2,
}));

The takeaway is: If you're using styled, you don't need Box, as the returned component will have all the props that Box does.


I hope this helps. Let me know.

@DiegoAndai DiegoAndai added status: waiting for author Issue with insufficient information customization: css Design CSS customizability and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Jan 6, 2025
@khanilov
Copy link
Author

khanilov commented Jan 7, 2025

Thank you, @DiegoAndai, for response and code suggestions.


This is a known issue, and I'm not sure why it worked for you before.

Indeed that's major oversight on my side. We have some wrapping that bring this component prop back for some components, that's why it worked. My apologies.


Given I need component prop and can enable it by passing corresponding type to generic argument of styled, what is the benefit of using div over Box?

const StyledDiv = styled('div')<{ component: React.ElementType }>``; // or
const StyledBox = styled('Box')<{ component: React.ElementType }>``;

We use Box as fundamental building block over div, and hence a lot of styled(Box). I would prefer to stay consistent whether use case requires component prop or not.

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information labels Jan 7, 2025
@DiegoAndai
Copy link
Member

Given I need component prop and can enable it by passing corresponding type to generic argument of styled, what is the benefit of using div over Box?

It's easier to explain the other way around: There's no benefit of using Box over div when using with styled (to my knowledge), so there's no reason to import Box. One less dependency is almost always better 👍🏼.

@DiegoAndai DiegoAndai added status: waiting for author Issue with insufficient information and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Jan 7, 2025
@khanilov
Copy link
Author

khanilov commented Jan 8, 2025

Got you. Thanks for responses!

@khanilov khanilov closed this as completed Jan 8, 2025
Copy link

github-actions bot commented Jan 8, 2025

This issue has been closed. If you have a similar problem but not exactly the same, please open a new issue.
Now, if you have additional information related to this issue or things that could help future readers, feel free to leave a comment.

Note

@khanilov How did we do? Your experience with our support team matters to us. If you have a moment, please share your thoughts in this short Support Satisfaction survey.

@github-actions github-actions bot added status: waiting for maintainer These issues haven't been looked at yet by a maintainer and removed status: waiting for author Issue with insufficient information status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Jan 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
customization: css Design CSS customizability docs Improvements or additions to the documentation support: docs-feedback Feedback from documentation page
Projects
None yet
Development

No branches or pull requests

3 participants