Open o-alexandrov opened 3 months ago
Not long ago I made a suggestion that would exapnd the icons' package features and improve DX when requiring specific icons at runtime (eg. based on user input).
See the issue at #42450.
Now, thinking of it in the context of performance, splitting the icons into separate packages based on style could allow tree shakers to reduce the bundled size significantly if icons of one particular style are used. A separate import could be used for when all the icons of all styles are required.
My issue was requesting the ability to get the icons at runtime based on their style(s) and tag(s)/synonym(s) (see why I need that feature in mui/mui-x#13206). It's a shame it got closed just because there's already a hacky way to import icons at runtime in userland. The current way of doing it is also not optimised for a particular style. I'm glad this RFC has been opened, so we can have a proper discussion on the topic.
Given the very likely adoption of Material Symbols (#32846) in MUI v7, I believe an expansion of the icons' package API (like my suggestion or similar) should be considered by the team. A well thought-out API expansion in this area could bring both extended functionality and improved performance, thus covering extra use-cases (like mine from mui/mui-x#13206) and improving performance, as mentioned here.
I'll copy & paste the proposed API changes I made in the issues mentioned in the above reply so that they can be discussed further right here.
I would like to add an explicit example of how the utility function from the icons package I was talking about could look like:
import { getIcons } from '@mui/icons-material'; import SvgIcon from '@mui/material/SvgIcon'; // Get all icons in all styles let allIcons: Array<SvgIcon> = getIcons(); // Get all outlined icons let allOutlinedIcons: Array<SvgIcon> = getIcons({ styles: [ 'outlined' ] }); // Get only filled and outlined icons let filledAndOutlinedIcons: Array<SvgIcon> = getIcons({ styles: [ 'filled', 'outlined' ] }); // Get only filled icons with the "home" tag // Should only return these icons: https://mui.com/material-ui/material-icons/?query=home let filledHomeIcons: Array<SvgIcon> = getIcons({ styles: [ 'filled' ], tags: { anyOf: [ 'home' ] } }); // Get all icons with the "home" tag, in all styles let allHomeIcons: Array<SvgIcon> = getIcons({ tags: { anyOf: [ 'home' ] } }); // Get all icons that have either the "home" or the "building" tags, in all styles let allHomeOrBuildingIcons: Array<SvgIcon> = getIcons({ tags: { anyOf: [ 'home', 'building' ] } }); // Get all icons that have both the "home" and "building" tags, in the sharp style only let allSharpHomeAndBuildingIcons: Array<SvgIcon> = getIcons({ styles: [ 'sharp' ], tags: { allOf: [ 'home', 'building' ] } }); // Do not support allOf and anyOf at the same time let willThrowException = getIcons({ tags: { anyOf: [ 'home' ], allOf: [ 'building' ] } });
The
styles
argument is optional and, if missing, every style will be included in the output. It is a string array that can have any of the following optionsfilled
,outlined
,rounded
,two tone
andsharp
. These could additionally also be exported as enums to be used in code conveniently.The
tags
argument is also optional, and its filtering will apply together with thestyle
filter. It is an object that must have either theanyOf
or theallOf
keys that map to string arrays. They should not be both supported at the same time, resulting in an exception being thrown. Using the argument withanyOf
option will return all the icons that have at least one of the tags in the list. Using it with theallOf
option will return only the icons that have all the tags from the given tag list.With this kind of API, the Icon Picker component can pass its state as arguments to the
getIcons
function and fulfil my requirement. When the user would change the style option(s) or change the search word, the state would update and call the function again, and the Icon Picker would rerender to only display the new icons returned bygetIcons
. Having both theanyOf
and theallOf
tag selectors will enable this component to potentially use Chip-based sorting as well as the already discussed Radio Button/Tree View variants.Additionally, a function that allows getting all tags for a specific icon (maybe call it
getIconTags
) should also be available for flexibility (to show the user the keywords/tags a specific icon can be found by), but this would require an internal ID for every icon to be passed as an argument to that function. I am not that accustomed to the internals of the icons package, so I do not know how difficult such an addition would be.If this icons-related reply is out of topic here, feel free to move (or copy) this issue to the corresponding repository (
material-ui
).
Of course, this proposed API should be expanded taking into account the separation of the icons' packages based on style, to reduce the final build size through tree shaking when not all styles are required.
What's the problem?
This RFC looks at 2 problems with icons:
Sharp
,Rounded
,Outlined
,TwoTone
,Filled
What are the requirements?
MUI's user should be able to enforce icons' variants and the number of icons shouldn't affect DX.
Proposed solution
We can tackle both problems by allowing MUI's users to have more consistent interfaces by enforcing icons' variants using ESLint's no-restricted-imports.
File structure for Material Icons:
File structure for Material Symbols:
Related issues
Search keywords: material icons, symbols, icons v2