Skip to content

feature(html/mjml): updates/reduction to underlying html#3059

Open
dazgreer wants to merge 7 commits intofix/replace-html-minifierfrom
feature/html-updates-and-tidy
Open

feature(html/mjml): updates/reduction to underlying html#3059
dazgreer wants to merge 7 commits intofix/replace-html-minifierfrom
feature/html-updates-and-tidy

Conversation

@dazgreer
Copy link
Collaborator

@dazgreer dazgreer commented Mar 5, 2026

Highlights

  • 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

Details

Features

  • mj-title throws an error if missing or empty (added test, updated doc)
  • added support-outlook-classic option to mjml tag to remove support for Outlook (removes ghost tables and other Outlook specific code. Set to `true by default) (updated doc)
  • added option to mj-preview to add blank space after preview text (updated doc) [Fixes Create automatically white space after <mj-preview> text #1829]

HTML changes

General

  • increased printWidth of Prettier to prevent long lines wrapping attributes and increasing filesize
  • auto removes any empty attribute instance of class=“” or style=“”
  • removed | IE from all conditional comments
  • updated docs for all attribute changes

html

  • removed namepsacexmlns attribute as no longer needed
  • only shows namepsace xmlns:o attribute when support-outlook-classic=“true"
  • only shows namepsace xmlns:v if background-url is present on mj-hero or mj-section

meta

  • updated charset tag
  • removed X-UA-Compatible tag as no longer useful
  • updated viewport tag to include user-scalable=yes
  • added format detections tags to prevent clients from creating links from dates, contact details etc
  • added dark mode tags behind support-dark-mode option (on <mjml> tag) to allow dark mode support

head (skeleton)

  • removed .mj-outlook-group-fix CSS as only applies to older unsupported Outlook versions (2003 and less)
  • removed -ms prefixed reset styles when support-outlook-classic="false"
  • changed -webkit-text-size-adjust to text-size-adjust
  • changed default margin from 13px to 1em
  • removed <link> font import, now uses just @import CSS
  • added dark mode :root CSS behind support-dark-mode option (on <mjml> tag) to allow dark mode support

style (skeleton)

  • removed type=“text/css” as no longer required
  • removed some spacing between CSS rules
  • concatenates <style> blocks where possible
  • removed width declaration for mj-column-per-100 as it’s declared by default in the tag

table

  • updated all instances of role=“presentation” to role=“none”
  • removed all <tbody> tags [breaking change for any user added CSS that relies on it in a selector]

font-family declarations

  • removed Helvetica and Arial as fallbacks [small breaking change as fonts will change to system default sans-serif font]

mj-body

  • added xml:lang=“” (populated from globalData language, declared on mjml tag)
  • removed background-colour and word-spacing as declared on the child div

mj-accordion

  • concatenated CSS selectors with identical declarations
  • changed border-bottom declaration to 0 and now only outputs when border is not already set to 0 or none
  • removed vertical-align as it’s default to the tag
  • fixed Gmail specific CSS (broken by Prettier) and broken out accordion CSS into its own <style> block as it broke other things in Gmail

mj-accordion-element

  • removed padding attribute as it’s default to the tag

mj-button

  • removed text-transform, font-weight attributes as default to the tag
  • removed target attribute as not necessary in email
  • set display to block and removed mso-padding-alt declaration to solve issue where the full button is not clickable when the width is set
    • added multiline option to allow users to negate issues with the above in Outlook classic when button text wraps
  • removed default cursor: auto set on <td> and margin: 0 set on <a>

mj-carousel

  • added prettier-ignore comment to fallback image as Prettier was breaking it
  • concatenated CSS selectors for identical declarations, where possible
  • changed carousel unique ID from 16 characters to 6
  • removed mso-hide-all attributes as the carousel is not displayed in Outlook
  • removed border-radius from Outlook fallback image as Outlook does not display it
  • created shared CSS for multiple carousel instances as previously it was duplicated
  • removed default target on links and height on image as not needed.
  • removed [owa] class as no longer used

mj-carousel-image

  • now respects target attribute
  • checkbox set to just checked for first input rather than checked="checked"

mj-column

  • removed direction attribute as default to the tag
  • removed vertical-align declaration from table as set in children
  • removed mj-outlook-group-fix class as only applies to older unsupported Outlook versions (2003 and less)

mj-divider

  • now uses either table or p (based on support-outlook-classic) and only outputs one
  • removed px units for html table width as they don’t work
  • added max-width to both table and p to better handle width

mj-group

  • removed direction attribute as default to the tag
  • removed 'text-align': 'left' from div as default
  • removed mj-outlook-group-fix class as only applies to older unsupported Outlook versions (2003 and less)

mj-hero

  • removed unnecessary background-url and padding defaults
  • removed duplication of background-repeat declaration in background shorthand value
  • reduced value of background-position declaration to single center
  • added closing </td> tags for fluid height hero as self-closing tag is not valid
  • removed vertical-align declaration from <tr> tag
  • fixed issue where left padding disappeared in Outlook when background-url (VML) added

mj-image

  • removed fluid-on-mobile CSS when not set
  • removed unnecessary class on td and changed CSS selector to accommodate
  • removed text-decoration, outline and font-size as attributes as default to the tag
  • removed target attribute as not necessary in email

mj-navbar

  • hamburger now takes set font-family / font-size / line-height when declaring in mj-attributes > mj-all. Previously it was using its own
  • removed hamburger CSS when hamburger is not set [Fixes Navbar without hamburger unnecessary css #2848]
  • removed ico-text-decoration attribute as default to the tag
  • concatenated CSS selectors with same rules
  • removed 'mso-hide': 'all' and '-moz-user-select': 'none' as not required
  • changed navbar unique ID from 16 characters to 6

mj-navbar-link

  • removed font-weight as attribute as default to the tag
  • removed target attribute as not necessary in email

mj-section

  • removed direction, background-repeat and background-size as attributes as default to the tag
  • removed multiple declarations of background-color or color reference in background as unnecessarily declared multiple times
  • changed text-align option to column-align as it was poorly named. Aliased the deprecated option for backwards compatibility [updated docs]
  • fixed issue where left padding disappeared in Outlook when background-url (VML) added

mj-social

mj-social-element

  • removed text-align and vertical-align as attributes as default to the tag

mj-table

  • removed width declaration when user sets to auto as default to tag
  • removed table-layout attribute as default to the tag. If the user adds, it will also not be be written out
  • updated associated test

mj-wrapper

  • removed text-align from docs as it doesn't do anything

- 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
Copy link
Collaborator

@guigui64 guigui64 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

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”
…d-tidy

- Merged cssnano-preset-lite improvements and normalizeMinifyCssOption helper from fix/replace-html-minifier
- Adopted Mocha-based *.test.js pattern for mjml-core tests (replacing old *-test.js runner)
- Preserved accordion-style and dark-mode skeleton tests from feature branch in skeleton.test.js
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.
@dazgreer dazgreer force-pushed the feature/html-updates-and-tidy branch from 3842f49 to 3184a11 Compare March 18, 2026 15:35
…t tests

- extracted mergeHeadStyleBlocks into its own helper module and imported
- added test file covering 29 unit tests.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants