feat(ui): add h1–h6 base typography styles#1746
Conversation
🦋 Changeset detectedLatest commit: e304ede The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
There was a problem hiding this comment.
Pull request overview
Adds the Juno design-system heading typography scale (h1–h6) as base styles in the UI components package, and aligns the FormattedText component’s heading styles to the same sizes/line-heights.
Changes:
- Added h1–h6 base typography rules (font-family/weight + size + line-height) in
global.css. - Added corresponding heading rules to
theme.cssand updatedFormattedTextheading line-heights (including addingh6). - Added a changeset to release the update.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| packages/ui-components/src/theme.css | Adds heading typography rules (currently unlayered). |
| packages/ui-components/src/global.css | Adds h1–h6 base styles in @layer base using prefixed Tailwind utilities for line-height. |
| packages/ui-components/src/components/FormattedText/formatted-text.css | Aligns heading line-heights/sizes to the design-system scale; adds h6. |
| .changeset/typography-scale-headings.md | Declares a minor version bump and describes the typography change. |
464f38f to
e2a926b
Compare
edda
left a comment
There was a problem hiding this comment.
Please check all components for internal usage of h1 - h6. Now that we define global font-sizes for them, existing places where they were used might look differen. E.g. the title prop in the Message component renders an h1 with bold font. Previously this would render in standard text size but bold. After this change it will have the h1 font-size, which is not intended. It was semantically already a mistake to render an h1 for this, so we'll need to adjust it to something more fitting. Modal titles also use h1, which we probably want to change as well. I'm sure there are others...
d26ce8c to
883acee
Compare
Implements the Juno typography scale for heading elements h1–h6 in the @layer base section of global.css. Styles follow the defined spec: IBM Plex Sans, weight 700, with rem-based font sizes and leading values aligned to Tailwind's leading-snug (h1–h3), leading-relaxed (h4–h5), and leading-normal (h6). Closes #1737 Signed-off-by: MartinS-git <info@eyepic.de>
Signed-off-by: MartinS-git <info@eyepic.de>
…ies in h1–h6 Signed-off-by: MartinS-git <info@eyepic.de>
Update h1–h6 in formatted-text.css to match the defined typography scale: - Align font-size and line-height with global.css values - Fix h5 font-size (1.03rem → 1.125rem) - Remove redundant font-weight and font-style declarations - Add missing h6 style Closes #1737 Signed-off-by: MartinS-git <info@eyepic.de>
Signed-off-by: MartinS-git <info@eyepic.de>
… theme.css Signed-off-by: MartinS-git <info@eyepic.de>
ContentHeading renders an h1 — now that h1–h6 base styles are defined in @layer base (global.css), the explicit jn:text-lg (1.125rem) was overriding the intended h1 size (1.69rem). Removing both overrides lets the base typography scale apply correctly. Signed-off-by: MartinS-git <info@eyepic.de>
Signed-off-by: MartinS-git <info@eyepic.de>
…al.css h1–h6 Consistent with theme.css and formatted-text.css which also use plain CSS values. Tailwind equivalent noted as comments. Signed-off-by: MartinS-git <info@eyepic.de>
…lues Signed-off-by: MartinS-git <info@eyepic.de>
…ements Resolves accessibility regression caused by the global h1–h6 typography scale: components that used <h1> for UI labels (titles, section headings) now rendered at 27px, which was not intended. Each element was reviewed for correct heading semantics: - Modal: <h1> → <h4>; removed jn:text-xl/font-bold overrides - Form: <h1> → <h3>; removed jn:text-2xl/font-bold overrides - FormSection: <h1> → <h4>; removed jn:text-lg/font-bold overrides - SignInForm: <h1> → <h2>; removed jn:text-xl/font-bold overrides - Message: <h1> → <strong> (alert title, not a navigable section) - IntroBox: <h1> → <p> (info box, no heading outline needed) - PopupMenu: <h1> → <span> (decorative menu section label) - ContentHeading: <h1> unchanged (intentional page-level heading) Signed-off-by: MartinS-git <info@eyepic.de>
…ct changeset inaccuracies Signed-off-by: MartinS-git <info@eyepic.de>
…1.28rem, leading-relaxed, bold) Signed-off-by: MartinS-git <info@eyepic.de>
…ily consistency with h4 path Signed-off-by: MartinS-git <info@eyepic.de>
…ull consistency Signed-off-by: MartinS-git <info@eyepic.de>
…prevent invalid HTML Signed-off-by: MartinS-git <info@eyepic.de>
…aphy Extend h1–h6 base rules in global.css and theme.css to also match corresponding .juno-h1–.juno-h6 classes, so non-heading elements (such as the Modal ReactNode-title div with role="heading") can share the same typography. Modal drops its duplicated titlestyles constant and uses the .juno-h4 class on the div path instead. Also rewrites the changeset to describe consumer-facing behavior instead of internal implementation history. Signed-off-by: Esther Schmitz <esther.schmitz@sap.com>
| <h4 className="juno-modal-title" id={modalTitleId}> | ||
| {modalTitle} | ||
| </h1> | ||
| </h4> | ||
| ) | ||
| } | ||
| return ( | ||
| <div className={`juno-modal-title ${titlestyles}`} id={modalTitleId}> | ||
| <div className="juno-modal-title juno-h4" role="heading" aria-level={4} id={modalTitleId}> | ||
| {modalTitle} |
Summary
global.css,theme.css, andFormattedTextContentHeadingto use the base h1 scale instead of overriding it<h1>tags with appropriate elements, resolving both visual regressions and accessibility issues.juno-h1–.juno-h6utility classes so non-heading elements can adopt the same styling without duplicating valuesChanges
global.css—@layer baseh1–h6base styles with IBM Plex Sans Bold, rem-based font sizes, and plain CSS numericline-heightvalues.juno-h1–.juno-h6class so non-heading elements (e.g. an element withrole="heading") can share the same typographytheme.css—@layer baseh1–h6(and.juno-h1–.juno-h6) styles for consumers usingtheme.cssstandalone@layer baseto respect cascade order (per Copilot review feedback)var(--font-sans)instead of hardcoded font stackFormattedText/formatted-text.cssh1–h6font sizes and line-heights with the typography scaleh5font size (1.03rem → 1.125rem)h6stylefont-weightandfont-styledeclarations (now inherited from base)ContentHeadingjn:font-boldandjn:text-lgoverrides — these were overriding the h1 base style (1.69rem) with the smallertext-lgvalue (1.125rem)Component heading fixes (accessibility + visual regression)
Several components used
<h1>for UI labels (titles, section headings). After introducing the global h1 base style, these rendered at 27px — unintended. Each was reviewed for correct heading semantics and accessibility:Modal<h1>+jn:text-xl<h4>(string title) /<div role="heading" aria-level={4} class="juno-h4">(ReactNode title)role="dialog"creates an isolated landmark; heading is correct and referenced viaaria-labelledby.<h4>matches previous visual size. ReactNode titles use a div +.juno-h4class to avoid invalid HTML (block elements inside heading elements) while sharing typography with the<h4>path.Form<h1>+jn:text-2xl<h3><h3>matches previous visual size.FormSection<h1>+jn:text-lg<h4><h3>) in the heading hierarchy.SignInForm<h1>+jn:text-xl<h2><h2>is a safe default for standalone and embedded use.Message<h1><strong>IntroBox<h1><p>(bold)PopupMenu<h1><header>ContentHeading<h1><h1>(unchanged)<h1>is semantically correct here.Changeset
@cloudoperators/juno-ui-componentsTypography Scale
The same scale is also available as
.juno-h1–.juno-h6utility classes for elements that should look like a heading but aren't a heading element.Closes #1737