Web components : Add usa-alert component#271
Conversation
Move "sass" from dependencies to devDependencies in package.json to reflect it's a build-time tool. Update UsaBanner to use Lit's boolean attribute binding (?hidden) driven by isOpen and remove the manual DOM attribute toggle in toggle(). Correct spacing token "05" from .025rem to .25rem in tokens/dimension/spacing.json.
Introduce a new UsaAlert web component (LitElement) with status variants (info, warning, error, success, emergency), slim, no-icon, and closeable options. Ship styles, Storybook stories, and unit tests; dispatches a close event and uses role=alert/status for accessibility. Also register/export the component, add a Vite build entry with size limit, and update custom-elements.json and a changeset.
|
Introduce an async updateComplete() helper that awaits getAlert().updateComplete in src/components/usa-alert/usa-alert.spec.ts, and replace repeated await getAlert().updateComplete calls with await updateComplete() to reduce duplication and improve test readability/maintainability.
Update usa-alert.css to replace calc(var(--usa-alert-padding-x) + 1.5rem + 0.5rem) with calc(var(--usa-alert-padding-x) + 2rem) for .usa-alert--slim .usa-alert__body. This simplifies the expression by combining the two fixed offsets into a single value, keeping the computed spacing unchanged and improving readability.
Switch the private role getter from `_role` to the ECMAScript private accessor `#role` and update the template reference accordingly. Also remove the `aria-hidden="true"` attribute from the close-icon span so the icon is not explicitly hidden; the close button still uses an `aria-label` for its accessible name.
|
Localization-strategy-wise, let's ping @ethangardner and/or @heymatthenry to chat with me to determine a call on that. May take us a minute to reply, but we'll put it on the list. Thanks for this work, both of you! |
|
I did a spike of an Alert component last year, and I wanted to share my PR in case it's helpful! There are a bunch of remaining issues with my approach that I haven't gotten to resolve though, I've got those tracked over here: |
ethangardner
left a comment
There was a problem hiding this comment.
Really nice work here, @ericsorenson. I think you made some great design choices, and I appreciated your test coverage and thoroughness. There are a few changes below, but this is a great start on this component. Also, thanks for your patience waiting for the code review.
|
|
||
| private _handleClose() { | ||
| this.dispatchEvent( | ||
| new CustomEvent("close", { bubbles: true, composed: true }), |
There was a problem hiding this comment.
This is the first instance of a custom event in this project, and we don't have an established convention for naming them yet. I'll write an ADR for this in a follow up PR, but researching other design systems, the safest option in terms of avoiding a collision with other libraries is to prefix the event with the tag name i.e. new CustomEvent("usa-alert-close", { bubbles: true, composed: true }).
That way, if someone uses document.addEventListener("close", () => {}) we will avoid any unwanted side effects. The native <dialog> tag fires a close event for example.
| this._visible = true; | ||
| } | ||
|
|
||
| private get #role(): string { |
There was a problem hiding this comment.
It appears that we don't have a build check running in CI, but when I built this locally with npm run build I got the error below.
src/components/usa-alert/index.ts:70:3 - error TS18010: An accessibility modifier cannot be used with a private identifier.
There was a problem hiding this comment.
Fixed, I'll be sure to check for this in the future.
| --usa-alert-icon-color: var(--usa-alert-emergency-icon); | ||
|
|
||
| & .usa-alert__body { | ||
| color: #fff; |
There was a problem hiding this comment.
Since the background and border colors are configurable, we should also expose the body color via a prop so there's a way to ensure adequate contrast if the bg color is changed.
| expect(alertDiv?.classList.contains("usa-alert--info")).toBe(true); | ||
| }); | ||
|
|
||
| it("has role=status for info alerts", () => { |
There was a problem hiding this comment.
Nit: this seems to be similar to L82-87 below. I know this tests when there is no status attribute present whereas the one below uses an explicit status=info. Is there a way to rephrase the description so it's clear that this is the default? I'd be ok with consolidating this in the test on L32 if that makes more sense.
Drop the redundant 'private' modifier from the '#role' getter in the UsaAlert component. Combining the TS 'private' keyword with an ECMAScript private identifier ('#') is invalid and caused a syntax/compile error, so this change makes the accessor valid.
Rename the private field in custom-elements.json from `_role` to `#role` to match private field syntax. In usa-alert.css add a new `--usa-alert-emergency-text-color` variable (defaulting to #fff) and replace hardcoded `#fff` uses in emergency alert styles (body text, slotted headline, and close-icon background) so the emergency text color can be themed via CSS variables.
Merge the default info status and role assertion into a single test and remove the duplicate ARIA role test for info in src/components/usa-alert/usa-alert.spec.ts. This reduces redundancy and simplifies the test suite by combining related assertions into one spec.
Rename the alert close event from "close" to "usa-alert-close" to avoid generic event name collisions. Update the @fires JSDoc, the dispatched CustomEvent in UsaAlert, and the unit test to listen for "usa-alert-close".
ethangardner
left a comment
There was a problem hiding this comment.
Thanks, @ericsorenson . LGTM!
Summary
New alert component. Added usa-alert with support for info, warning, error, success, and emergency statuses, including slim, no-icon, and closeable variants.
Related issue
N/A
Preview link
N/A
Problem statement
The library currently has one real component (usa-banner). The alert pattern is one of the most commonly used USWDS components and its absence blocks adoption. Additionally, the architecture needed validation from a second non-trivial component to confirm that patterns around slots, CSS custom properties, variant attributes, and event dispatch work correctly.
Solution
Ported the VADS va-alert (Stencil) component to Lit as usa-alert, using USWDS core's alert pattern as the visual/behavioral reference. Key design decisions:
Major changes
Testing and review