Repository navigation
Material Plus 0.0.1
The first release. Two components, and the scaffolding the rest will be built on.
Added
MPTextField— a Material UI text field that survives an IME. A controlled<input>is rendered from itsvalue, and while an input method is composing the browser is holding a provisional string that has not been committed yet; writingvalueback over it in that moment throws the syllable away and jumps the caret. Anything the parent does in itsonChange— trimming, upper-casing, validating, or simply re-rendering slowly — is enough to cause it. So the field stops renderingvaluefor the duration of a composition and shows its own copy of what the element actually contains, whileonChangekeeps firing for every keystroke. This is whyvalueandonChangeare a plain string rather than an event: an event'stargetis the element mid-composition, which is precisely the value that must not be trusted.- The field is
@mui/material's ownOutlinedInput, so the notched outline, the palette, the sizes and every theme override still belong to MUI. What is added around it is the assembly a form needs anyway:label,errorMessageas helper text,startIconas a leading adornment, and a password reveal toggle that cancels bothmousedownandmouseupso the caret stays where it was left.rowsrenders a<textarea>;resizablelets the reader drag it taller, vertically only.onSubmitfires on Enter, and Enter is then swallowed on a single-line field so a surrounding form is not also submitted natively —disableEnterKeyextends that to a multiline field.largeis MUI'smediumand the default is itssmall: two heights rather than a ladder, because those are the two@mui/materialhas. MPIcon— a glyph at a known size in a known colour, from whichever icon set you use. The glyph is theiconprop rather thanchildren, which is what lets the component set the size and colour of an element it did not draw. Two forms are accepted: a component, which is whatlucide-reactand most sets export and what allows the size and colour to be passed into the glyph, and an element, already drawn and scaled by the box it is laid into. The two are told apart withReact.isValidElementalone, so theforwardRefobjects modern icon sets actually export are correctly treated as components.sizeis a length, not a ladder. A number is CSS pixels and a string is any CSS length. Icon sets are drawn on a pixel grid at specific sizes, and a wrapper inventing five steps of its own would be a second opinion about a decision the set already made; left unset, the glyph draws at whatever size it was authored at. The length is written to the box and to itsfont-size, which is what makes an<svg>carrying its ownwidthand an<svg>sized inemcome out the same.colorbehaves the same way — unset, the icon inherits whatever it sits in, and the glyph is toldcurrentColorso a set with a hardcoded default follows too. Without alabelthe icon isaria-hiddenand leaves the accessibility tree; with one it is a namedrole="img".- One file imports
lucide-react, and it issrc/constants/icons.ts. Every glyph the library draws is named there under the role it plays (visibility) rather than the drawing lucide happens to ship (Eye), so the artwork can be swapped without touching a component. It leaves by two doors: named exports, which the library's own components use and which a bundler can tree-shake one at a time, andICONS, a name-keyed table for an application that wants one — an object literal cannot be shaken property by property, so importing it pulls in the whole set, and that trade is the reason the components never reach for it.
Package
@mui/material6 through 9,@emotion/react,@emotion/styled,reactandreact-dom18 or 19 are peer dependencies — the copy already in your project is the copy that is used, so there is never a second MUI in the bundle or a second theme in the tree. Only MUI 9 is exercised in CI.lucide-reactis the one runtime dependency.- ESM only, TypeScript declarations included. Every component compiles to its own module, so what is not imported is not shipped.
- Four entry points besides the barrel:
material-plus-ui/types,material-plus-ui/constants/icons,material-plus-ui/styles.cssandmaterial-plus-ui/tailwind.css.
Styles
- The stylesheet carries no reset, on either path. Tailwind's Preflight is a page reset and every project using this library already has one in
CssBaseline— and the two disagree visibly, since Preflight flattens the heading sizes, list markers and link colours MUI's typography sets up, and itsborder: 0 solidrestyles every@mui/materialcomponent on the page rather than only the ones from here. Nothing in this library depends on Preflight. material-plus-ui/styles.cssis finished CSS for a project with no Tailwind of its own;material-plus-ui/tailwind.cssis the token sheet for a project that has it. Both carry the@source '.'that registers the package's compiled files, so a consumer never writes an@sourcewhose correctness would depend on where their own CSS file sits.
Documentation
- A VitePress site in English and Korean at material-plus.cdget.com, with live previews that are the components running in the page rather than screenshots. Each preview carries a theme switch of its own, so a component can be read in the theme the page is not in.
- A page per component with its full props table, a getting-started guide covering the peer dependencies and both stylesheet paths, and a component index.
Testing
- Every component carries its own tests, run in a real browser rather than a DOM emulator — Material UI measures real layout, and a composition cannot be simulated by a synthetic helper. The suite drives genuine
compositionstart/compositionupdate/compositionendevents through the field and asserts on what the element is actually showing. - CI runs them across Chromium, Firefox and WebKit on Ubuntu, Windows and macOS, alongside lint, formatting and three separate typecheck passes for
src/,test/anddocs/.
Every release of this package is in the changelog on the docs site and in CHANGELOG.md at this tag.