Skip to content

Decouple heading HTML tag semantics from visual size classes in modular sections - #3989

Closed
officialSmartWoo wants to merge 1 commit into
Shopify:mainfrom
officialSmartWoo:fix-issue-3988
Closed

officialSmartWoo wants to merge 1 commit into
Shopify:mainfrom
officialSmartWoo:fix-issue-3988

Conversation

@officialSmartWoo

Copy link
Copy Markdown

PR Summary:

Introduced a heading_tag setting to decouple semantic HTML heading levels (h1-h6, p, div) from visual typography classes (heading_size) in modular sections, ensuring merchants can create accessible heading hierarchies across custom landing pages and heroes.

Why are these changes introduced?

Fixes #3988.

In Shopify Dawn, modular sections frequently used as hero banners or content blocks (slideshow, rich-text, image-banner, image-with-text, multicolumn, featured-collection, featured-blog, collage, collection-list) hardcoded <h2> in Liquid templates regardless of the selected heading_size. When merchants build custom landing pages or replace default banners with hero sections, pages frequently ended up without an <h1> tag or with duplicate headings, violating WCAG 2.1/2.2 AA (SC 1.3.1 Info and Relationships) and failing automated Axe-core audits (page-has-heading-one, heading-order).

What approach did you take?

  1. Schema Localization: Added sections.all.heading_tag with options for h1-h6, p ("Paragraph"), and div ("Div") in locales/en.default.schema.json.
  2. Schema Setting: Added heading_tag select setting with default value "h2" to all 9 affected modular sections (rich-text, slideshow, image-banner, image-with-text, multicolumn, featured-collection, featured-blog, collage, collection-list).
  3. Dynamic Liquid Markup: Replaced hardcoded <h2> tags with dynamic <{{ heading_tag }} ...></{{ heading_tag }}> where heading_tag = ...settings.heading_tag | default: 'h2'.

Other considerations

  • 100% Backwards Compatible: By setting the default to "h2" and using | default: 'h2' in Liquid, existing merchant pages and saved sections without heading_tag configured will continue to render <h2> tags without any visual or DOM structure changes.
  • Visual styling: Visual typography styles remain completely controlled by heading_size (e.g. .h0, .h1, .h2), maintaining design fidelity while giving full control over semantic document structure.

Decision log

# Decision Alternatives Rationale Downsides
1 Use heading_tag select setting with default h2 Automatically derive heading level from section order Automatic derivation is fragile across dynamic sections; explicit schema setting gives merchants and developers full semantic control. Adds an additional dropdown to heading settings.
2 Support p and div alongside h1-h6 Only h1-h6 Certain modular layouts use banner headings as stylistic accents where semantic headings are not appropriate. Minor addition to option list.

Visual impact on existing themes

None. Existing merchant templates and defaults render <h2> exactly as before. When a different heading tag is selected, only the semantic HTML element tag changes; visual size and font styles continue to follow heading_size.

Testing steps/scenarios

  • Run shopify theme check to verify schema validation and locale key consistency across all files (0 errors).
  • Test default behavior: verify omitting heading_tag defaults to <h2>...</h2>.
  • Test semantic tag switching: configure heading_tag to h1, h3, p, and div and verify correct opening/closing HTML tags in rendered output.
  • Deploy development theme to live test environment and verify theme editor compatibility.

Demo links

Checklist

@officialSmartWoo
officialSmartWoo deleted the fix-issue-3988 branch September 30, 2026 10:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Accessibility: Decouple heading HTML tag semantics from visual size classes in modular Dawn sections

1 participant