From 3f1e03372b823d2e04b1b55d9399d31a3419400f Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Fri, 1 May 2026 13:21:44 -0700 Subject: [PATCH 01/23] Update heading tags in various page elements for better accessibility --- .../components/releaseNotes/components.md | 4 ++ .../components/auditlog/AuditDetails.tsx | 2 +- .../components/base/PageHeader.test.tsx | 9 ++++- .../internal/components/base/PageHeader.tsx | 40 ++++++++++++++----- .../src/internal/components/base/Section.tsx | 11 +++-- .../domainproperties/DomainFieldsDisplay.tsx | 4 +- .../DomainFieldsDisplay.test.tsx.snap | 12 +++--- .../components/forms/PageDetailHeader.tsx | 4 +- .../PageDetailHeader.test.tsx.snap | 18 ++++----- .../components/forms/detail/DetailDisplay.tsx | 2 +- .../forms/detail/DetailPanelHeader.tsx | 8 ++-- .../labelPrinting/BarTenderSettingsForm.tsx | 2 +- .../lineage/node/NodeDetailHeader.tsx | 2 +- .../permissions/GroupDetailsPanel.tsx | 2 +- .../samples/ManageSampleStatusesPanel.tsx | 2 +- .../components/settings/ActiveUserLimit.tsx | 2 +- .../components/settings/NameIdSettings.tsx | 2 +- .../components/user/UserDetailsPanel.tsx | 2 +- .../UserDetailHeader.test.tsx.snap | 8 ++-- .../UserDetailsPanel.test.tsx.snap | 24 +++++------ .../src/public/QueryModel/GridPanel.tsx | 4 +- .../src/public/QueryModel/TabbedGridPanel.tsx | 2 +- packages/components/src/theme/app/app.scss | 4 ++ packages/components/src/theme/detail.scss | 9 +++++ packages/components/src/theme/lineage.scss | 2 + packages/components/src/theme/panel.scss | 11 +++++ 26 files changed, 127 insertions(+), 65 deletions(-) diff --git a/packages/components/releaseNotes/components.md b/packages/components/releaseNotes/components.md index 61f73f23c5..a82b4d0516 100644 --- a/packages/components/releaseNotes/components.md +++ b/packages/components/releaseNotes/components.md @@ -1,6 +1,10 @@ # @labkey/components Components, models, actions, and utility functions for LabKey applications and pages +### version TBD +*Released*: TBD +- Update heading tags in various page elements for better accessibility + ### version 7.33.3 *Released*: 1 May 2026 - Accessibility improvements: add labels or aria-labels to input elements diff --git a/packages/components/src/internal/components/auditlog/AuditDetails.tsx b/packages/components/src/internal/components/auditlog/AuditDetails.tsx index 557e9cb746..ed9034336f 100644 --- a/packages/components/src/internal/components/auditlog/AuditDetails.tsx +++ b/packages/components/src/internal/components/auditlog/AuditDetails.tsx @@ -204,7 +204,7 @@ export class AuditDetails extends Component { return (
-
{title}
+

{title}

{children} {!rowId &&
{emptyMsg}
} diff --git a/packages/components/src/internal/components/base/PageHeader.test.tsx b/packages/components/src/internal/components/base/PageHeader.test.tsx index a93ffb585a..59c837c743 100644 --- a/packages/components/src/internal/components/base/PageHeader.test.tsx +++ b/packages/components/src/internal/components/base/PageHeader.test.tsx @@ -7,7 +7,7 @@ import { PageHeader } from './PageHeader'; describe('', () => { test('render without properties', () => { render(); - expect(document.querySelector('h2').textContent).toEqual(''); + expect(document.querySelector('h2')).not.toBeInTheDocument(); }); test('render with icon', () => { @@ -28,6 +28,13 @@ describe('', () => { expect(document.querySelector('h2').textContent).toEqual(' Page title'); }); + + test('render with icon and title as primary', () => { + render(); + expect(document.querySelectorAll('span.fa-star').length).toEqual(1); + expect(document.querySelector('h1').textContent).toEqual(' Page title'); + }); + test('render with children', () => { render( diff --git a/packages/components/src/internal/components/base/PageHeader.tsx b/packages/components/src/internal/components/base/PageHeader.tsx index 207a0cdb20..2d8335a921 100644 --- a/packages/components/src/internal/components/base/PageHeader.tsx +++ b/packages/components/src/internal/components/base/PageHeader.tsx @@ -19,20 +19,40 @@ import { Notifications } from '../notifications/Notifications'; interface PageHeaderProps extends PropsWithChildren { iconCls?: string; + primaryHeader?: boolean; showNotifications?: boolean; title?: string; } -export const PageHeader: FC = ({ children, iconCls, showNotifications = true, title }) => ( -
- {children} +export const PageHeader: FC = ({ + children, + iconCls, + primaryHeader, + showNotifications = true, + title, +}) => { + const showTitle = !!iconCls || !!title; -

- {iconCls ?   : null} - {title} -

+ return ( +
+ {children} + + {showTitle && primaryHeader && ( +

+ {iconCls ?   : null} + {title} +

+ )} + {showTitle && !primaryHeader && ( +

+ {iconCls ?   : null} + {title} +

+ )} + + {showNotifications && } +
+ ); +}; - {showNotifications && } -
-); PageHeader.displayName = 'PageHeader'; diff --git a/packages/components/src/internal/components/base/Section.tsx b/packages/components/src/internal/components/base/Section.tsx index f6c3d4e854..58d531121b 100644 --- a/packages/components/src/internal/components/base/Section.tsx +++ b/packages/components/src/internal/components/base/Section.tsx @@ -44,10 +44,15 @@ export const Section: FC = props => { {showHeader && (
- {title && ( -
+ {title && titleSize === 'large' && ( +

{title} -

+ + )} + {title && titleSize !== 'large' && ( +

+ {title} +

)} {caption &&
{caption}
}
diff --git a/packages/components/src/internal/components/domainproperties/DomainFieldsDisplay.tsx b/packages/components/src/internal/components/domainproperties/DomainFieldsDisplay.tsx index 8aba4847e0..3755e35c39 100644 --- a/packages/components/src/internal/components/domainproperties/DomainFieldsDisplay.tsx +++ b/packages/components/src/internal/components/domainproperties/DomainFieldsDisplay.tsx @@ -55,9 +55,9 @@ type Props = { export const DomainFieldsDisplay: FC = ({ domain, title }) => (
-
+

{title || domain.name}
-

+

{domain.description}

diff --git a/packages/components/src/internal/components/domainproperties/__snapshots__/DomainFieldsDisplay.test.tsx.snap b/packages/components/src/internal/components/domainproperties/__snapshots__/DomainFieldsDisplay.test.tsx.snap index b8e15ba7bd..7e71f258d6 100644 --- a/packages/components/src/internal/components/domainproperties/__snapshots__/DomainFieldsDisplay.test.tsx.snap +++ b/packages/components/src/internal/components/domainproperties/__snapshots__/DomainFieldsDisplay.test.tsx.snap @@ -5,13 +5,13 @@ exports[`DomainFieldsDisplay with empty domain design 1`] = `
-
-
+
@@ -118,7 +118,7 @@ exports[`DomainFieldsDisplay with title 1`] = `
-
test domain title
-
+
@@ -233,7 +233,7 @@ exports[`DomainFieldsDisplay without title 1`] = `
-
test domain name
-
+
diff --git a/packages/components/src/internal/components/forms/PageDetailHeader.tsx b/packages/components/src/internal/components/forms/PageDetailHeader.tsx index 2d9289ba04..f21e7bdce1 100644 --- a/packages/components/src/internal/components/forms/PageDetailHeader.tsx +++ b/packages/components/src/internal/components/forms/PageDetailHeader.tsx @@ -59,8 +59,8 @@ export class PageDetailHeader extends PureComponent {
)}
-

{title}

- {subTitle &&

{subTitle}

} +

{title}

+ {subTitle &&
{subTitle}
} {description && {description}}
diff --git a/packages/components/src/internal/components/forms/__snapshots__/PageDetailHeader.test.tsx.snap b/packages/components/src/internal/components/forms/__snapshots__/PageDetailHeader.test.tsx.snap index 4d32e9c578..6068f52e1c 100644 --- a/packages/components/src/internal/components/forms/__snapshots__/PageDetailHeader.test.tsx.snap +++ b/packages/components/src/internal/components/forms/__snapshots__/PageDetailHeader.test.tsx.snap @@ -22,11 +22,11 @@ exports[` default props 1`] = `
-

Title -

+
with additional props 1`] = `
-

Title -

-

+
Subtitle -

+
@@ -100,11 +100,11 @@ exports[` without icon 1`] = `
-

Title -

+
= memo(props => { if (asPanel) { return (
-
Details
+

Details

{body}
); diff --git a/packages/components/src/internal/components/forms/detail/DetailPanelHeader.tsx b/packages/components/src/internal/components/forms/detail/DetailPanelHeader.tsx index 7a52a986a0..150b8cced3 100644 --- a/packages/components/src/internal/components/forms/detail/DetailPanelHeader.tsx +++ b/packages/components/src/internal/components/forms/detail/DetailPanelHeader.tsx @@ -29,7 +29,7 @@ export const DetailPanelHeader: FC = memo(props => { if (editing) { return ( -
+

{verb} {title} {warning !== undefined && ( @@ -39,12 +39,12 @@ export const DetailPanelHeader: FC = memo(props => { )} -

+ ); } return ( -
+

{title} {isEditable && ( @@ -56,7 +56,7 @@ export const DetailPanelHeader: FC = memo(props => { )} -

+ ); }); DetailPanelHeader.displayName = 'DetailPanelHeader'; diff --git a/packages/components/src/internal/components/labelPrinting/BarTenderSettingsForm.tsx b/packages/components/src/internal/components/labelPrinting/BarTenderSettingsForm.tsx index c6d7dd480a..7ecf3c9d1e 100644 --- a/packages/components/src/internal/components/labelPrinting/BarTenderSettingsForm.tsx +++ b/packages/components/src/internal/components/labelPrinting/BarTenderSettingsForm.tsx @@ -184,7 +184,7 @@ export const BarTenderSettingsForm: FC = memo(props return (
-
{title}
+

{title}

{error && {error}} {loading && } diff --git a/packages/components/src/internal/components/lineage/node/NodeDetailHeader.tsx b/packages/components/src/internal/components/lineage/node/NodeDetailHeader.tsx index da3f37b2b4..24421b7e40 100644 --- a/packages/components/src/internal/components/lineage/node/NodeDetailHeader.tsx +++ b/packages/components/src/internal/components/lineage/node/NodeDetailHeader.tsx @@ -20,7 +20,7 @@ export const DetailHeader: FC = memo(({ children, header, ico
-

{header}

+
{header}
{children}
diff --git a/packages/components/src/internal/components/permissions/GroupDetailsPanel.tsx b/packages/components/src/internal/components/permissions/GroupDetailsPanel.tsx index a4a605cab2..c233ec031e 100644 --- a/packages/components/src/internal/components/permissions/GroupDetailsPanel.tsx +++ b/packages/components/src/internal/components/permissions/GroupDetailsPanel.tsx @@ -62,7 +62,7 @@ export const GroupDetailsPanel: FC = memo(props => { return (
-
{principal?.displayName ?? 'Group Details'}
+

{principal?.displayName ?? 'Group Details'}

{principal ? ( <> diff --git a/packages/components/src/internal/components/samples/ManageSampleStatusesPanel.tsx b/packages/components/src/internal/components/samples/ManageSampleStatusesPanel.tsx index d473ee30e5..c842b13cea 100644 --- a/packages/components/src/internal/components/samples/ManageSampleStatusesPanel.tsx +++ b/packages/components/src/internal/components/samples/ManageSampleStatusesPanel.tsx @@ -469,7 +469,7 @@ export const ManageSampleStatusesPanel: FC = mem return (
-
{TITLE}
+

{TITLE}

{error && {error}} {!states && } diff --git a/packages/components/src/internal/components/settings/ActiveUserLimit.tsx b/packages/components/src/internal/components/settings/ActiveUserLimit.tsx index 262b00a60c..72270af256 100644 --- a/packages/components/src/internal/components/settings/ActiveUserLimit.tsx +++ b/packages/components/src/internal/components/settings/ActiveUserLimit.tsx @@ -53,7 +53,7 @@ export const ActiveUserLimit: FC = memo(props => { return (
-
Active Users
+

Active Users

{error} {settings && ( diff --git a/packages/components/src/internal/components/settings/NameIdSettings.tsx b/packages/components/src/internal/components/settings/NameIdSettings.tsx index 831fbcc884..56440194ca 100644 --- a/packages/components/src/internal/components/settings/NameIdSettings.tsx +++ b/packages/components/src/internal/components/settings/NameIdSettings.tsx @@ -280,7 +280,7 @@ export const NameIdSettingsForm: FC = props => { return (
-
{TITLE}
+

{TITLE}

{error !== undefined && {error}} {prefixIneligibleSampleTypeNames.length > 0 && ( diff --git a/packages/components/src/internal/components/user/UserDetailsPanel.tsx b/packages/components/src/internal/components/user/UserDetailsPanel.tsx index 6263a0c3a5..51b3e551cd 100644 --- a/packages/components/src/internal/components/user/UserDetailsPanel.tsx +++ b/packages/components/src/internal/components/user/UserDetailsPanel.tsx @@ -365,7 +365,7 @@ export const UserDetailsPanel: FC = props => { return (
-
{renderHeader()}
+

{renderHeader()}

{renderBody()} {!isSelfCtx && !isGroup && onUsersStateChangeComplete && renderButtons()} diff --git a/packages/components/src/internal/components/user/__snapshots__/UserDetailHeader.test.tsx.snap b/packages/components/src/internal/components/user/__snapshots__/UserDetailHeader.test.tsx.snap index cb47620f02..009c7f6f40 100644 --- a/packages/components/src/internal/components/user/__snapshots__/UserDetailHeader.test.tsx.snap +++ b/packages/components/src/internal/components/user/__snapshots__/UserDetailHeader.test.tsx.snap @@ -19,11 +19,11 @@ exports[`UserDetailHeader default properties 1`] = `
-

Title -

+
-

Title (Custom) -

+
no principal 1`] = `
-
User Details -
+
@@ -26,13 +26,13 @@ exports[` unknown user props 1`] = `
-
TestDisplayName -
+
@@ -125,13 +125,13 @@ exports[` with principal and buttons 1`] = `
-
cnathe -
+
@@ -224,13 +224,13 @@ exports[` with principal and buttons not allowDelete or allow
-
cnathe -
+
@@ -316,7 +316,7 @@ exports[` with principal no buttons because of self 1`] = `
-
@@ -327,7 +327,7 @@ exports[` with principal no buttons because of self 1`] = ` > Active -
+
@@ -544,13 +544,13 @@ exports[` with principal that isGroup 1`] = `
-
Test Group -
+
diff --git a/packages/components/src/public/QueryModel/GridPanel.tsx b/packages/components/src/public/QueryModel/GridPanel.tsx index b72ec7ef1b..a7a9803195 100644 --- a/packages/components/src/public/QueryModel/GridPanel.tsx +++ b/packages/components/src/public/QueryModel/GridPanel.tsx @@ -340,7 +340,7 @@ export const GridTitle: FC = memo(props => { } return ( -
+

{isEdited && allowViewCustomization && Edited} {isUpdated && allowViewCustomization && Updated} {displayTitle ?? 'Default View'} @@ -366,7 +366,7 @@ export const GridTitle: FC = memo(props => { )} {errorMsg && {errorMsg}} -

+ ); }); diff --git a/packages/components/src/public/QueryModel/TabbedGridPanel.tsx b/packages/components/src/public/QueryModel/TabbedGridPanel.tsx index ef31a951a4..11975d1fdc 100644 --- a/packages/components/src/public/QueryModel/TabbedGridPanel.tsx +++ b/packages/components/src/public/QueryModel/TabbedGridPanel.tsx @@ -288,7 +288,7 @@ export const TabbedGridPanel: FC = m <> {hasTabs && (
- {asPanel && panelTitle &&
{panelTitle}
} + {asPanel && panelTitle &&

{panelTitle}

}
    {tabOrder.map(modelId => { diff --git a/packages/components/src/theme/app/app.scss b/packages/components/src/theme/app/app.scss index f7bf6e1fd6..ba9847342b 100644 --- a/packages/components/src/theme/app/app.scss +++ b/packages/components/src/theme/app/app.scss @@ -23,6 +23,10 @@ margin: 0 0 15px 0; padding: 0; border: 0; + + & > h1 { + font-size: 30px; + } } .menu-section-icon { diff --git a/packages/components/src/theme/detail.scss b/packages/components/src/theme/detail.scss index b50aeba7a7..9d40e96152 100644 --- a/packages/components/src/theme/detail.scss +++ b/packages/components/src/theme/detail.scss @@ -52,6 +52,14 @@ } } +.detail-subtitle { + font-weight: 500; + font-size: 18px; + line-height: 1.1; + margin-top: 10px; + margin-bottom: 10px; +} + .detail-component__active { background: $brand-primary; color: $white; @@ -196,6 +204,7 @@ } .detail__header--name { + font-size: 30px; margin: 0; overflow-wrap: break-word; } diff --git a/packages/components/src/theme/lineage.scss b/packages/components/src/theme/lineage.scss index d3f8928967..5c22490999 100644 --- a/packages/components/src/theme/lineage.scss +++ b/packages/components/src/theme/lineage.scss @@ -47,6 +47,8 @@ .lineage-name-data { display: inline; + font-size: 18px; + font-weight: 500; } .lineage-data-link { diff --git a/packages/components/src/theme/panel.scss b/packages/components/src/theme/panel.scss index 3bfee4c8a9..4b86a75c74 100644 --- a/packages/components/src/theme/panel.scss +++ b/packages/components/src/theme/panel.scss @@ -26,12 +26,18 @@ .panel-content-title, .panel-content-title-medium { display: inline-block; + font-weight: normal; font-size: 18px; + margin-block-start: 0; + margin-block-end: 0; } .panel-content-title-large { display: inline-block; + font-weight: normal; font-size: 28px; + margin-block-start: 0; + margin-block-end: 0; } .panel-content-caption { @@ -43,6 +49,10 @@ .panel-default:not(.domain-form-panel) .panel-heading, .panel-info .panel-heading { font-size: 18px; + font-weight: normal; + margin-top: 0; + margin-bottom: 0; + line-height: 1.4; } .panel-default:not(.domain-form-panel) .panel-heading { background-color: $white; @@ -51,6 +61,7 @@ padding: 0; } + // revert panel heading font-size for those within a tabbed-grid-panel .tabbed-grid-panel .panel-heading { font-size: 14px !important; From d4ec16dc4b91f18d03c5856a397f12c7e596e811 Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Fri, 1 May 2026 13:26:15 -0700 Subject: [PATCH 02/23] @labkey/components v7.33.4-pageStructure.0 --- packages/components/package-lock.json | 4 ++-- packages/components/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/components/package-lock.json b/packages/components/package-lock.json index 09ac1a54fa..31c54e0203 100644 --- a/packages/components/package-lock.json +++ b/packages/components/package-lock.json @@ -1,12 +1,12 @@ { "name": "@labkey/components", - "version": "7.33.3", + "version": "7.33.4-pageStructure.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@labkey/components", - "version": "7.33.3", + "version": "7.33.4-pageStructure.0", "license": "SEE LICENSE IN LICENSE.txt", "dependencies": { "@hello-pangea/dnd": "18.0.1", diff --git a/packages/components/package.json b/packages/components/package.json index 7b5215e79c..fd7f935342 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,6 +1,6 @@ { "name": "@labkey/components", - "version": "7.33.3", + "version": "7.33.4-pageStructure.0", "description": "Components, models, actions, and utility functions for LabKey applications and pages", "sideEffects": false, "files": [ From 9f25affc0e72866ee1efefc1570dbc2d2479e0ff Mon Sep 17 00:00:00 2001 From: labkey-susanh Date: Fri, 1 May 2026 13:29:33 -0700 Subject: [PATCH 03/23] Missing label reference --- .../src/internal/components/assay/SpecialtyAssayPanel.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/components/src/internal/components/assay/SpecialtyAssayPanel.tsx b/packages/components/src/internal/components/assay/SpecialtyAssayPanel.tsx index d38833aeb6..9e099e8bc8 100644 --- a/packages/components/src/internal/components/assay/SpecialtyAssayPanel.tsx +++ b/packages/components/src/internal/components/assay/SpecialtyAssayPanel.tsx @@ -54,11 +54,12 @@ export const SpecialtyAssayPanel: FC = memo(props => {
    {selected && options?.length > 0 && ( <> -
    +
    Use Instrument-Specific Data Format