Open kof opened 7 years ago
@kof Thanks for starting this discussion. You have opened quite some interesting issues lately. What do you have in mind with core components? Does this discussion take into account a unstyled version of the library?
unstyled version of the library
Exactly, I called it naked ui, it should be just core stuff required for every theming/ux.
From my perspective of the next codebase, much of the modules that we could extract away from the lib have already been extracted. We don't try to reinvent the wheel.
I think a lot more is not really material-ui specific but generic and we can do more generic if we use variants mui/material-ui#6130
For e.g. the components innside of internal/** look like mostly generic also I see more stuff can become generic.
Just from what I have looked into: Form, Divider, Avatar, Icon, Input and probably lots of others can be also generic nacked components and mui just a theme + variants on top.
Thanks for clarifying your motivation. I see two ways to move forward into that direction.
classes
property object with various customization class names points.
Then, to expose the material version, we would have to wrap all those naked components with an Higher-order Component.In order to achieve naked components we would need to implement mui/material-ui#6130 first anyways. Also naked components would need some core styles, theme unrelated.
Reminds me of Reapp -the very first React component library I tried for the personal project that ultimately led to my involvement in Material-UI. :-) (In fact, I'm almost certain I discovered React from it, not the other way around!).
The components had no inherent styling (https://github.com/reapp/reapp-ui/tree/master/src/components, and a theme included the style objects for each component: https://github.com/reapp/reapp-ui/tree/master/src/themes/ios/styles
Only the iOS theme was developed, but the intention was that it could support Material Design, or other styles.
I think there was a certain naivety in that, since looking at the more complicated components in Material-UI such as the pickers (as malformed as they may be), some of the sub-component hierarchy and functionality is dictated by the design that the component is aiming to meet.
Making that generic could be tricky. (Not impossible, but certainly an added burden.). All that said, I'm certainly on-board with the idea in principal, but I'll leave it to those smarter than me to figure out the implementation details.
Yeah, such complex components like Datepicker are hard to make generic and probably not a good idea too. They may be implemented within material-ui but using all the generics from the nacked library.
A nacked library can provide though all necessary parts for it, so that assembling own custom picker is not as hard any more.
I like this. :+1:
In a perfect world we'd have a style-independent repository with core-components that we can use across multiple projects with theme adapters. (Like a material theme, a bootstrap theme...).
There is this repository : https://github.com/react-component/ which follow more or less the same idea, minus the styles that don't seem "open".
If it is gonna take years to implement, I really don't think it is a good path to follow. I'd rather have material-ui focus only on material design component implementation with react.
@stunaz I agree we should focus on porting more components to the next branch first and make them fully in line with Material Design guidelines. Also improve their APIs and generally make them more robust.
This is a great idea though and I'd love to see it implemented. Especially after reading mui/material-ui#6130
This is about next steps, for sure we need to release "next" first.
Please don't fall into illusion of abstraction levels. As @stunaz @Zuurkern @kof say not all components are good material
for that
In case it could serve as inspiration, I remember the angular team coming up with what they call "a CDK" for their material UI library. https://blog.angular.io/a-component-dev-kit-for-angular-9f06e3b4b3b4
📊 To the developers who have upvoted the issue:
We have started to explore a possible solution to the unstyled problem with this approach (you can play with the above on this codesansbox). See pull request mui/material-ui#22435
import * as React from 'react';
import styled from '@emotion/styled';
import { SliderBase } from '@material-ui/core/Slider';
const StyledSlider = styled(SliderBase)`
height: 2px;
width: 100%;
padding: 13px 0;
display: inline-block;
position: relative;
cursor: pointer;
touch-action: none;
-webkit-tap-highlight-color: transparent;
& .MuiSlider-rail {
display: block;
position: absolute;
// …
SliderBase
is a version of the component with almost no dependencies (it's very bundle-size efficient). The component can be customize with a couple of approaches.
components
prop to inject nested custom components. This works well with styled-components and for performing DOM changes.<SliderBase components={{ Root: StyledRoot, thumb: StyledThumb }} />
componentsProps
prop to add props on nested components (following this RFC: mui/material-ui#21453). This works well with CSS utility libraries, e.g. Tailwind, or inline-style.<SliderBase componentsProps={{ root: { className: 'mt-5' }, thumb: { style: { background: 'red' } } }} />
classes
prop to inject custom class names. This can work best with CSS-modules or when you can't use the global class names.<SliderBase classes={{ root: 'my-root-class', thumb: 'my-thumb-class' }} />
What do you think about it? What solution would you like to see us deliver?
The main advantage of the above proposal is that it solves two or event three problems at the same time. 1. It solves the migration to emotion/styled-components, 2. it allows us to test the potential for unstyled-components, and 3. it's likely required to deliver a second theme, in addition to Material Design (love-hate relationship of the community around this design spec). There are two other directions that we can push in order to better address the "unstyled" use case.
It's what we have done with the Combo Box and the Pagination components.
Pros:
Cons:
Same proposal but with components closer to the DOM nodes. For instance, with a slider, we could have:
<Slider defaultValue={20}>
<SliderTrack />
<SliderRail />
<SliderThumb />
</Slider>
Pros:
Cons:
<SliderBase components={{ Root: StyledRoot, thumb: StyledThumb }} />
The previous one allows you to do all the other ones, and incentivize component-based interfaces, without having to introduce APIs that subjectively are simple to use.
The best of both worlds would be to construct the Base component out of the hooks IMO.
By default you can go with the Base which covers 90% of the usual cases, and you can "build your own Base" when things get fancy.
This is more or less the approach taken by Adobe's spectrum and I think it's a very effective one.
It might be a good chance to introduce theme-ui
spec to the stack. Why not make a styling solution as dependency injection. One big theme spec specific provider on top + some style resolvers, depending which styling solution you prefer (seems like a good api design challenge).
You can play with the first unstyled component in https://next--material-ui.netlify.app/components/slider-styled/#unstyled-slider.
It might be a good chance to introduce theme-ui spec to the stack.
@daraselia The unstyled components have no knowledge of any specific style or theming convention. We have seen this very theme specification request come up a few times, for instance, we chat about it with @shinework. So far, we haven't seen a strong argument for changing the current theme specification that outweighs the opportunity cost. I have seen the following arguments so far:
Counter argument: we will revamp the system engine in v5. The value proposition for developers is well explained in the answer of https://github.com/jsxstyle/jsxstyle#why-write-styles-inline-with-jsxstyle. We need to push further. We used to have that in v0.x with inline styles.
Counter argument: so is Material-UI's theme structure. It's not strongly tightened to Material Design. Actually, we will bring a second theme mui/material-ui#22485 to make this better resonate.
Limitation: isn't Material-UI's theme structure more frequently used? What about the BC implications for current MUI users? Can a unification really make a difference for the overall industry? What about Tailwind that went with its own theme structure?
I don't think that theme-ui
should be discussed more on this specific thread. If you want to make the case for it, please open a detailed RFC :).
I recently had to implement something related to this (outside Mui, just general feedback).
import React from "react";
import CheckIcon from "@material-ui/icons/Check";
// It will allow people to get used to some nomenclature across the ecosystem,
// I would love to see some alignment in the across community honestly, maybe
// take the lead in the future about, and align with other libraries.
// I am not sure what type should I use for general React component type, so
// I used React.FC.
type PropsWithComponents<
C extends Partial<{ [key: string]: React.FC }>,
P
> = P & {
components?: C;
};
type Components = Partial<{
SuccessMessage: React.FC<{ message: string }>;
}>;
type MyInputProps = React.PropsWithChildren<
PropsWithComponents<
// We could pass a list of names instead of an interface, but then we lose
// the flexibility of documenting some properties that may be pass to a
// particular component. I think would be worth for the internal code
// documentation
Components,
{
success?: boolean;
failure?: boolean;
}
>
>;
function DefaultSuccessMessage() {
return (
<CheckIcon className="text-green-500 absolute right-0 bottom-0 mb-4 mr-4" />
);
}
function MyInput(props: MyInputProps) {
// Pattern for look up the components, and adding the default implementation
// if we have one.
const SuccessMessage =
props.components?.SuccessMessage ?? DefaultSuccessMessage;
// Internal state
const message = ""
return (
<div>
....
{/* We pass internal states as displayed with message */}
{/*
We control the render of the component, this will allow Mui to decide
lazy evaluation of when particular component needs to actually render.
Classical issues when people expect components pre-rendered, they mess
up the performance.
*/}
{props.success ?? <SuccessMessage message={message} />}
</div>
);
}
import React from "react";
import CheckIcon from "@material-ui/icons/Check";
// Perfect, it is just a component, we define statically, everything is good
// The downside is that we dont have access to MyUI scope
function SuccessMessage() {
return (
<span className="absolute flex items-center font-semibold right-0 bottom-0 mb-4 mr-4 uppercase text-green-500">
<CheckIcon className="mr-1" />
Coupon applied
</span>
);
}
function MyUI() {
return (
<div>
...
<MyInput
success={true}
components={{ SuccessMessage }}
/>
</div>
)
}
import React from "react";
import CheckIcon from "@material-ui/icons/Check";
function SuccessMessage() {
return (
<span className="absolute flex items-center font-semibold right-0 bottom-0 mb-4 mr-4 uppercase text-green-500">
<CheckIcon className="mr-1" />
Coupon applied
</span>
);
}
// Just the old factory function.
function createSuccessMessage(myUIProps: any) {
// Perfect we have access to all the scopes
return (muiProps)=> <SuccessMessage />
}
function MyUI(props: any) {
const SuccessMessage = createSuccessMessage(props)
return (
<div>
...
<MyInput
success={true}
components={{ SuccessMessage }}
/>
</div>
)
}
I think this approach is clean enough and easy to understand and maintain.
Worth pointing once again about the fact that Mui controls the rendering of the components, this has been the biggest issue using 3rd parties libraries and Juniors not knowing why the app is so slow in the List Page, where they are rendering an entire unused Modal per item because they eagle evaluation the rendering of those components in their component definition (please help me indirectly).
An update on the priorities. We plan to push this as soon as v5 has made enough progress. We will work on it hand in hand with mui/material-ui#22485 to have a healthy constraint.
Status update: I recently joined the core team and unstyled components are my main focus. As for the implementation I'm leaning towards having unstyled components using hooks. I published a draft of a PR with this approach and I'd love to know what you think about the proposed API.
You can follow our progress in mui/base-ui#10.
I read this issue as a newbie today and i cannot understand how developers follow a specific feature for more than 5+ years as it seems really complex .is there any meaningful way for me to contribute to this feature ?
@antariksh17 The answer is linked in the comment above yours: https://github.com/mui/base-ui/issues/10
Material-UI as "material to build UI", not "material design"!
I am wondering if it would make any sense to extract the core components of material-ui in a separate, completely non-opinionated and naked library and make all material-ui specific design decisions a theme + stuff like Ripple.
As an outcome I would expect: