Skip to content

Add support for Text in the AppHeader #2951

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 36 commits into from
Jun 30, 2025
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
6d81131
Testing different Application Name examples in context
jorytindall Jun 13, 2025
c5de994
Added support for a title within the HomeLink
jorytindall Jun 13, 2025
6cc917a
Updated styling to remove the width/height set by the token to use pa…
jorytindall Jun 13, 2025
00e8ac8
Added examples for Terraform Admin Console, Admin UI, and Boundary De…
jorytindall Jun 13, 2025
3864ab5
Updated examples and added examples of the HomeLink states with titles
jorytindall Jun 13, 2025
6db5af1
lint
jorytindall Jun 13, 2025
419464a
Add missing closing tag in showcase
jorytindall Jun 13, 2025
b69694e
Testing: concat title with aria label when present
jorytindall Jun 16, 2025
a83eff8
Restructured the HomeLink to recieve text and isIconOnly arguments, r…
jorytindall Jun 18, 2025
28a86b2
Lint
jorytindall Jun 18, 2025
61e279a
Changeset
jorytindall Jun 18, 2025
183c5fb
Make text argument required
jorytindall Jun 18, 2025
3a0055c
Remove unused min/max width declarations for the logo
jorytindall Jun 18, 2025
bd78286
Updated ariaLabel property in component mock
jorytindall Jun 18, 2025
0cb7bb6
Lint showcase
jorytindall Jun 18, 2025
b8e55a8
Removed errant =
jorytindall Jun 18, 2025
0642018
format showcase
jorytindall Jun 18, 2025
893cee4
Removed trailing space
jorytindall Jun 18, 2025
4e9ca60
simplified conditional logic for rendering the icon + text
jorytindall Jun 18, 2025
8da8a7f
Removed disabled state variants of the home link
jorytindall Jun 19, 2025
7df890c
Updated tests
jorytindall Jun 19, 2025
79d5d18
Fix assertion
jorytindall Jun 19, 2025
fec2164
lint showcase
jorytindall Jun 20, 2025
be2ac96
Fix tests!
jorytindall Jun 20, 2025
0306fb1
Updated examples in the showcase
jorytindall Jun 20, 2025
58891d8
Revise changelog
jorytindall Jun 20, 2025
60dce9d
Removed explicit class on the text element, set isIconOnly to true by…
jorytindall Jun 20, 2025
30d1ba7
linter
jorytindall Jun 20, 2025
a122314
linter format
jorytindall Jun 20, 2025
07adb46
Removed all instances where isIconOnly is true because its the default
jorytindall Jun 23, 2025
92bb602
Added more explicit assertion for the icon argument
jorytindall Jun 23, 2025
184601c
lint
jorytindall Jun 23, 2025
9cc3a79
Cleanup of layouts and content in the showcase
jorytindall Jun 24, 2025
142389f
Lint
jorytindall Jun 24, 2025
5797efd
Updated contextual component naming conventions
jorytindall Jun 25, 2025
ccb3046
Fixed placement of the badge example
jorytindall Jun 26, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/dry-spiders-tell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@hashicorp/design-system-components": minor
---

`AppHeader` - Refactored the Home Link, removed the `@ariaLabel` argument, added
`@text` (should replace `@ariaLabel`) and `@isIconOnly` arguments.
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
@href={{@href}}
@isHrefExternal={{@isHrefExternal}}
...attributes
aria-label={{this.ariaLabel}}
aria-label={{if this.isIconOnly this.text null}}
>
<Hds::Icon @name={{@icon}} @color={{@color}} @stretched={{true}} />
{{#unless this.isIconOnly}}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This isn't exactly the same as the conditional logic for the <Hds::Button> but it seemed to make sense given that the icon is always required. But open to suggestions!

Copy link
Contributor

Choose a reason for hiding this comment

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

This makes sense to me as well.

<Hds::Text::Display @size="100" @color="foreground-high-contrast">{{this.text}}</Hds::Text::Display>
{{/unless}}
</Hds::Interactive>
28 changes: 22 additions & 6 deletions packages/components/src/components/hds/app-header/home-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,37 @@ import type { HdsInteractiveSignature } from '../interactive/';
export interface HdsAppHeaderHomeLinkSignature {
Args: HdsInteractiveSignature['Args'] & {
icon: HdsIconSignature['Args']['name'];
isIconOnly?: boolean;
color?: string;
ariaLabel: string;
text: string;
};
Element: HdsInteractiveSignature['Element'];
}

export default class HdsAppHeaderHomeLink extends Component<HdsAppHeaderHomeLinkSignature> {
get ariaLabel(): string {
const { ariaLabel } = this.args;
get text(): string {
const { text } = this.args;

assert(
'@ariaLabel for "Hds::AppHeader::HomeLink" ("Logo") must have a valid value',
ariaLabel !== undefined
'@text for "Hds::AppHeader::HomeLink" must have a valid value',
text !== undefined
);

return ariaLabel;
return text;
}

get icon(): HdsIconSignature['Args']['name'] {
const { icon } = this.args;

assert(
'@icon name for "Hds::AppHeader::HomeLink" must be provided',
icon !== undefined
);

return icon;
}

get isIconOnly(): boolean {
return this.args.isIconOnly ?? true;
}
}
8 changes: 4 additions & 4 deletions packages/components/src/styles/components/app-header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
.hds-app-header__utility-actions {
display: flex;
gap: inherit;
align-items: center;
}

// Dropdown & Button color theming overrides
Expand Down Expand Up @@ -144,12 +145,11 @@
.hds-app-header__home-link {
@include hds-interactive-dark-theme($add-visible-border: false);
display: flex;
gap: 8px;
align-items: center;
justify-content: center;

// Set home link container size:
width: var(--token-app-header-home-link-size);
height: var(--token-app-header-home-link-size);
padding: 3px;
text-decoration: none;

// disabled state:
&:disabled,
Expand Down
3 changes: 2 additions & 1 deletion showcase/app/components/mock/app/header/app-header.gts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export default class MockAppHeaderAppHeader extends Component<MockAppHeaderAppHe
<:logo>
<HdsAppHeaderHomeLink
@icon="hashicorp"
@ariaLabel="HashiCorp home menu"
@text="HashiCorp home menu"
@isIconOnly={{true}}
@href="#"
/>
</:logo>
Expand Down
152 changes: 135 additions & 17 deletions showcase/app/templates/components/app-header/index.hbs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{{!
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: MPL-2.0
Copyright (c) HashiCorp, Inc.
SPDX-License-Identifier: MPL-2.0
}}

{{page-title "AppHeader Component"}}
Expand Down Expand Up @@ -43,7 +43,7 @@
<SG.Item @label="With minimum recommended phase 1 content">
<Hds::AppHeader @hasA11yRefocus={{false}}>
<:logo>
<Hds::AppHeader::HomeLink @icon="hashicorp" @ariaLabel="HashiCorp home menu" @href="#" />
<Hds::AppHeader::HomeLink @icon="hashicorp" @text="HashiCorp home menu" @href="#" />
</:logo>
<:globalActions>
<Hds::Dropdown @enableCollisionDetection={{true}} as |dd|>
Expand Down Expand Up @@ -80,7 +80,7 @@
<SG.Item @label="With max recommended phase 1 content & Terraform logo">
<Hds::AppHeader @hasA11yRefocus={{false}}>
<:logo>
<Hds::AppHeader::HomeLink @icon="terraform" @ariaLabel="Terraform home menu" @href="#" />
<Hds::AppHeader::HomeLink @icon="terraform" @text="Terraform home menu" @href="#" />
</:logo>
<:globalActions>
<Hds::Dropdown @enableCollisionDetection={{true}} as |dd|>
Expand Down Expand Up @@ -119,7 +119,7 @@
<SG.Item @label="With max proposed future content">
<Hds::AppHeader @hasA11yRefocus={{false}}>
<:logo>
<Hds::AppHeader::HomeLink @icon="hashicorp" @ariaLabel="HashiCorp home menu" @href="#" />
<Hds::AppHeader::HomeLink @icon="hashicorp" @text="HashiCorp home menu" @href="#" />
</:logo>
<:globalActions>
<Hds::Dropdown @enableCollisionDetection={{true}} as |dd|>
Expand Down Expand Up @@ -171,7 +171,7 @@
<SG.Item @label="40 characters long organization name with dashes">
<Hds::AppHeader @hasA11yRefocus={{false}}>
<:logo>
<Hds::AppHeader::HomeLink @icon="hashicorp" @ariaLabel="HashiCorp home menu" @href="#" />
<Hds::AppHeader::HomeLink @icon="hashicorp" @text="HashiCorp home menu" @href="#" />
</:logo>
<:globalActions>
<Hds::Dropdown @enableCollisionDetection={{true}} as |dd|>
Expand Down Expand Up @@ -207,7 +207,7 @@
<SG.Item @label="40 characters long organization name with no dashes">
<Hds::AppHeader @hasA11yRefocus={{false}}>
<:logo>
<Hds::AppHeader::HomeLink @icon="hashicorp" @ariaLabel="HashiCorp home menu" @href="#" />
<Hds::AppHeader::HomeLink @icon="hashicorp" @text="HashiCorp home menu" @href="#" />
</:logo>
<:globalActions>
<Hds::Dropdown @enableCollisionDetection={{true}} as |dd|>
Expand Down Expand Up @@ -241,6 +241,91 @@
</SG.Item>
</Shw::Grid>

<Shw::Divider @level="2" />

<Shw::Text::H3>With text</Shw::Text::H3>

<Shw::Grid @columns={{1}} {{style gap="2rem"}} as |SG|>

<SG.Item>
<Hds::AppHeader @hasA11yRefocus={{false}}>
<:logo>
<Hds::AppHeader::HomeLink @icon="terraform" @text="Terraform Admin Console" @isIconOnly={{false}} @href="#" />
</:logo>
<:utilityActions>
<Hds::Dropdown @enableCollisionDetection={{true}} as |dd|>
<dd.ToggleIcon @icon="user" @text="user menu" />
<dd.Title @text="Signed In" />
<dd.Description @text="[email protected]" />
<dd.Interactive @href="#">Account Settings</dd.Interactive>
</Hds::Dropdown>
</:utilityActions>
</Hds::AppHeader>
</SG.Item>

<SG.Item>
<Hds::AppHeader @hasA11yRefocus={{false}}>
<:logo>
<Hds::AppHeader::HomeLink @icon="hashicorp" @text="Admin UI" @isIconOnly={{false}} @href="#" />
</:logo>
<:globalActions>
<Hds::Dropdown @enableCollisionDetection={{true}} as |dd|>
<dd.ToggleButton @text="Choose an organization" @icon="org" />
<dd.Checkmark>
organizationName
</dd.Checkmark>
</Hds::Dropdown>
</:globalActions>
<:utilityActions>
<Hds::Dropdown @enableCollisionDetection={{true}} as |dd|>
<dd.ToggleIcon @icon="help" @text="help menu" />
<dd.Title @text="Help & Support" />
<dd.Interactive @href="#">Documentation</dd.Interactive>
<dd.Interactive @href="#">Tutorials</dd.Interactive>
<dd.Interactive @href="#">Terraform Provider</dd.Interactive>
<dd.Interactive @href="#">Changelog</dd.Interactive>
<dd.Separator />
<dd.Interactive @href="#">Create support ticket</dd.Interactive>
<dd.Interactive @href="#">Give feedback</dd.Interactive>
</Hds::Dropdown>

<Hds::Dropdown @enableCollisionDetection={{true}} as |dd|>
<dd.ToggleIcon @icon="user" @text="user menu" />
<dd.Title @text="Signed In" />
<dd.Description @text="[email protected]" />
<dd.Interactive @href="#">Account Settings</dd.Interactive>
</Hds::Dropdown>
</:utilityActions>
</Hds::AppHeader>
</SG.Item>

<SG.Item>
<Hds::AppHeader @hasA11yRefocus={{false}}>
<:logo>
<Hds::AppHeader::HomeLink @icon="boundary-color" @text="Boundary Desktop" @isIconOnly={{false}} @href="#" />
</:logo>
<:utilityActions>
<Hds::Button @color="secondary" @icon="search" @isIconOnly={{true}} @text="Search" />
</:utilityActions>
</Hds::AppHeader>
</SG.Item>

<SG.Item>
<Hds::AppHeader @hasA11yRefocus={{false}}>
<:logo>
<Hds::AppHeader::HomeLink
@icon="hashicorp"
@text="HashiCorp Cloud Platform"
@isIconOnly={{false}}
@href="#"
/>
<Hds::Badge @text="Assuming Role: Admin" @color="highlight" @icon="eye" @type="filled" />
</:logo>
</Hds::AppHeader>
</SG.Item>

</Shw::Grid>

<Shw::Divider />

<Shw::Text::H2>Options</Shw::Text::H2>
Expand All @@ -249,7 +334,7 @@
<SG.Item @label="With custom breakpoint (menu button is visible at wide screen width)">
<Hds::AppHeader @hasA11yRefocus={{false}} @breakpoint="20000px">
<:logo>
<Hds::AppHeader::HomeLink @icon="hashicorp" @ariaLabel="HashiCorp home menu" @href="#" />
<Hds::AppHeader::HomeLink @icon="hashicorp" @text="HashiCorp home menu" @href="#" />
</:logo>
<:globalActions>
<Hds::Dropdown @enableCollisionDetection={{true}} as |dd|>
Expand Down Expand Up @@ -285,9 +370,8 @@
</Shw::Grid>

<Shw::Divider />
</section>

<Shw::Divider />
</section>

{{! For some reason, Ember tests don't play well with iframes (URL not found) so we can't take snapshots of these examples in Percy }}
<section>
Expand Down Expand Up @@ -337,51 +421,67 @@

<Shw::Text::H2>Base elements</Shw::Text::H2>

<Shw::Text::H3>SideNav::Header::HomeLink</Shw::Text::H3>
<Shw::Text::H3>AppHeader::HomeLink</Shw::Text::H3>

<Shw::Text::H4>Content</Shw::Text::H4>

<Shw::Flex as |SF|>
<SF.Item @label="Icon">
<div class="hds-app-header">
<Hds::AppHeader::HomeLink @icon="hashicorp" @ariaLabel="HashiCorp" @href="#" />
<Hds::AppHeader::HomeLink @icon="hashicorp" @text="HashiCorp" @href="#" />
</div>
</SF.Item>

<SF.Item @label="Custom color">
<div class="hds-app-header">
<Hds::AppHeader::HomeLink
@icon="boundary"
@ariaLabel="Boundary"
@text="Boundary"
@color="var(--token-color-boundary-brand)"
@href="#"
/>
</div>
</SF.Item>
</Shw::Flex>

<Shw::Text::H4>Text</Shw::Text::H4>

<Shw::Flex as |SF|>
<SF.Item>
<div class="hds-app-header">
<Hds::AppHeader::HomeLink @icon="hashicorp" @text="HashiCorp" @href="#" @title="Admin UI" />
</div>
</SF.Item>

<SF.Item>
<div class="hds-app-header">
<Hds::AppHeader::HomeLink @icon="terraform" @text="Terraform" @href="#" @title="Terraform Admin Console" />
</div>
</SF.Item>
</Shw::Flex>

<Shw::Text::H4>States</Shw::Text::H4>

<Shw::Flex as |SF|>
{{#let (array "default" "hover" "active" "focus" "disabled") as |states|}}
{{#let (array "default" "hover" "active" "focus") as |states|}}
{{#each states as |state|}}
<SF.Item @label={{state}}>
<div class="hds-app-header">
<Hds::AppHeader::HomeLink @icon="hashicorp" @ariaLabel="HashiCorp" @href="#" mock-state-value={{state}} />
<Hds::AppHeader::HomeLink @icon="hashicorp" @text="HashiCorp" @href="#" mock-state-value={{state}} />
</div>
</SF.Item>
{{/each}}
{{/let}}
</Shw::Flex>

<Shw::Flex as |SF|>
{{#let (array "default" "hover" "active" "focus" "disabled") as |states|}}
{{#let (array "default" "hover" "active" "focus") as |states|}}
{{#each states as |state|}}
<SF.Item>
<div class="hds-app-header">
<Hds::AppHeader::HomeLink
@icon="boundary"
@ariaLabel="Boundary"
@text="Boundary"
@color="var(--token-color-boundary-brand)"
@href="#"
mock-state-value={{state}}
Expand All @@ -392,6 +492,24 @@
{{/let}}
</Shw::Flex>

<Shw::Flex as |SF|>
{{#let (array "default" "hover" "active" "focus") as |states|}}
{{#each states as |state|}}
<SF.Item @label={{state}}>
<div class="hds-app-header">
<Hds::AppHeader::HomeLink
@icon="terraform"
@text="Terraform Admin Console"
@isIconOnly={{false}}
@href="#"
mock-state-value={{state}}
/>
</div>
</SF.Item>
{{/each}}
{{/let}}
</Shw::Flex>

<Shw::Divider @level="2" />

<Shw::Text::H3>Buttons within AppHeader</Shw::Text::H3>
Expand Down
Loading