feature(html/mjml): updates/reduction to underlying html#3059
Open
dazgreer wants to merge 14 commits into
Open
feature(html/mjml): updates/reduction to underlying html#3059dazgreer wants to merge 14 commits into
dazgreer wants to merge 14 commits into
Conversation
guigui64
approved these changes
Mar 11, 2026
Collaborator
guigui64
left a comment
There was a problem hiding this comment.
Code looks good to me.
Just one remark on this:
removed all tags [potential small breaking change for any user added CSS that relies on it in a selector]
I think it is a breaking change (not a small one) and you should list it in the release notes.
guigui64
approved these changes
Mar 16, 2026
totocap
approved these changes
Mar 17, 2026
3842f49 to
3184a11
Compare
totocap
approved these changes
Mar 19, 2026
totocap
approved these changes
Apr 9, 2026
totocap
approved these changes
Apr 9, 2026
d23ff3b to
01e2d5e
Compare
totocap
reviewed
Apr 29, 2026
8ca10ab to
1f4e431
Compare
totocap
approved these changes
Apr 30, 2026
1f4e431 to
9549fec
Compare
totocap
approved these changes
May 25, 2026
- mj-title throws an error if missing or empty - optional Outlook and dark mode support - add space to preview text - comprehensive tidy of HTML to reduce code bloat - updated tests and docs
mjml-core - Updated Prettier to use single quotes inside of CSS - Broken out the accordion CSS into its own style block as it was breaking other CSS and causing non functional components, e.g. carousel in Gmail and updated test mjml-section - fixed issues caused by removing background-size and background-repeat as default attributes whereby the default values were used to determine VML settings. Created automated test - removed multiple declarations of the background color and concatenated two divs that were split because of this - updated table to use role=“none”
cheerio is a webpack external for the browser bundle, so calling load() inside mergeHeadStyleBlocks() crashed the smoke test with 'Cannot read properties of undefined (reading load)'. Replace the cheerio DOM walk with a plain character scanner that tokenises <head> content into plain-style / whitespace / other segments and merges consecutive eligible <style> blocks inline. The merged output is identical; the import of load from cheerio is retained for the mj-html-attributes feature at the call-site that is already correctly guarded by an isEmpty() check. Also fixes no-continue lint errors by using an 'advanced' flag instead of continue statements in the tokenizer loop.
…t tests - extracted mergeHeadStyleBlocks into its own helper module and imported - added test file covering 29 unit tests.
…ibutes - background-color applied to body tag in mj-body - background-color applied to parent table tag instead of both td tags in mj-accordion-title
- now scans mj-wrapper when deciding whether to include the xmlns:v namespace. - now changes the support-outlook-classic="false" attribute to a string before comparing, correctly evaluating to false. Added automated test
- Updated extraction boundaries from tbody to the raw div itself in in mj-raw - Removed fallback fonts from mj-text - Updated indentation outpu Co-authored-by: Copilot <copilot@github.com>
- Refactored expressions for simplicity - Updated printWidth value for Prettier - Removed mj-title validation and testing
…r following rebase The beautify tests were written against the old Prettier formatter. Now that mjml-core uses js-beautify, two fixtures needed updating: - "keeps raw html comment spacing": js-beautify does not insert a space after HTML comments, so expectedBeautified now matches actual output. Added skipFragmentDiffCheck: true since the fragment is unchanged by beautify (the document-level check still asserts overall reformatting). - "wraps long raw html start tags": deleted. js-beautify uses wrap_line_length: 0 by default and does not split long attribute lists across lines. The same input is already covered by the passing standalone it() "keeps long raw html start tags and attributes intact while beautifying". Also deleted a duplicate standalone it() for the comment-spacing case that searched for <tbody> as its start token. MJML never emits that tag inside an mj-raw block, so the test always failed with "Missing start token". Co-authored-by: Copilot <copilot@github.com>
Now that beautification uses js-beautify instead of prettier, prettier-ignore comments serve no purpose and should not appear in rendered output. - Removed the post-render strip of /* prettier-ignore */ and <!-- prettier-ignore --> from mjml-core - Removed /* prettier-ignore */ comments in mj-accordion and mj-carousel
…apple message formatting - Updated column-align default and inheritance from text-align as the colum-align default was overriding the user specified text-align value - removed <meta name="x-apple-disable-message-reformatting"> from skeleton as it's legacy code (iOS9 and bellow) Co-authored-by: Copilot <copilot@github.com>
9ac8c4a to
09954e2
Compare
…ed meta for CSS - reintroduced mso-padding-alt for mj-button with multiline="true" to work the same as the current MJML - added function to remove 1px padding to compensate for the added border - removed <meta name="format-detection"> as it was ineffective. Replaced with CSS - Added regression tests for border comensation fix
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Highlights
mj-titlethrows an error if missing or emptyDetails
Features
mj-titlethrows an error if missing or empty (added test, updated doc)support-outlook-classicoption tomjmltag to remove support for Outlook (removes ghost tables and other Outlook specific code. Set to `true by default) (updated doc)mj-previewto add blank space after preview text (updated doc) [Fixes Create automatically white space after <mj-preview> text #1829]HTML changes
General
class=“”orstyle=“”| IEfrom all conditional commentshtml
xmlnsattribute as no longer neededxmlns:oattribute whensupport-outlook-classic=“true"xmlns:vifbackground-urlis present onmj-heroormj-sectionmeta
charsettagX-UA-Compatibletag as no longer usefuluser-scalable=yessupport-dark-modeoption (on<mjml>tag) to allow dark mode supporthead (skeleton)
.mj-outlook-group-fixCSS as only applies to older unsupported Outlook versions (2003 and less)-msprefixed reset styles whensupport-outlook-classic="false"-webkit-text-size-adjusttotext-size-adjustmarginfrom13pxto1em<link>font import, now uses just@importCSS:rootCSS behindsupport-dark-modeoption (on<mjml>tag) to allow dark mode supportstyle (skeleton)
type=“text/css”as no longer required<style>blocks where possiblemj-column-per-100as it’s declared by default in the tagtable
role=“presentation”torole=“none”<tbody>tags [breaking change for any user added CSS that relies on it in a selector]font-family declarations
HelveticaandArialas fallbacks [small breaking change as fonts will change to system default sans-serif font]mj-body
xml:lang=“”(populated from globalData language, declared onmjmltag)word-spacingas declared on the childdivmj-accordion
border-bottomdeclaration to0and now only outputs when border is not already set to0ornonevertical-alignas it’s default to the tag<style>block as it broke other things in Gmailmj-accordion-element
paddingattribute as it’s default to the tagmj-accordion-title
background-colorattribute to parenttabletag rather than bothtdtagsmj-button
text-transform,font-weightattributes as default to the tagtargetattribute as not necessary in emaildisplaytoblockand removedmso-padding-altdeclaration to solve issue where the full button is not clickable when thewidthis setmultilineoption to allow users to negate issues with the above in Outlook classic when button text wrapscursor: autoset on<td>andmargin: 0set on<a>mj-carousel
prettier-ignorecomment to fallback image as Prettier was breaking itmso-hide-allattributes as the carousel is not displayed in Outlookborder-radiusfrom Outlook fallback image as Outlook does not display ittargeton links andheighton image as not needed.[owa]class as no longer usedmj-carousel-image
targetattributecheckedfor first input rather thanchecked="checked"mj-column
directionattribute as default to the tagvertical-aligndeclaration fromtableas set in childrenmj-outlook-group-fixclass as only applies to older unsupported Outlook versions (2003 and less)mj-divider
tableorp(based onsupport-outlook-classic) and only outputs onepxunits for html tablewidthas they don’t workmax-widthto bothtableandpto better handle widthmj-group
directionattribute as default to the tag'text-align': 'left'from div as defaultmj-outlook-group-fixclass as only applies to older unsupported Outlook versions (2003 and less)mj-hero
background-urlandpaddingdefaultsbackground-repeatdeclaration inbackgroundshorthand valuebackground-positiondeclaration to singlecenter</td>tags for fluid height hero as self-closing tag is not validvertical-aligndeclaration from<tr>tagmj-image
fluid-on-mobileCSS when not settdand changed CSS selector to accommodatetext-decoration,outlineandfont-sizeas attributes as default to the tagtargetattribute as not necessary in emailmj-navbar
font-family/font-size/line-heightwhen declaring inmj-attributes>mj-all. Previously it was using its ownico-text-decorationattribute as default to the tag'mso-hide': 'all'and'-moz-user-select': 'none'as not requiredmj-navbar-link
font-weightas attribute as default to the tagtargetattribute as not necessary in emailmj-section
direction,background-repeatandbackground-sizeas attributes as default to the tagbackground-coloror color reference inbackgroundas unnecessarily declared multiple timestext-alignoption tocolumn-alignas it was poorly named. Aliased the deprecated option for backwards compatibility [updated docs]mj-social
targetattribute as not necessary in emailwidthdeclarations [Fixes MJ-SOCIAL - Outlook app android/iOS interpret wrong the icon-padding. #3043]mj-social-element
text-alignandvertical-alignas attributes as default to the tagmj-table
widthdeclaration when user sets toautoas default to tagtable-layoutattribute as default to the tag. If the user adds, it will also not be be written outmj-wrapper
text-alignfrom docs as it doesn't do anything