sam-datepicker-v2 renders with no styling at all. Its template asks for a full set of bespoke .datepicker__* classes that are not defined in any stylesheet — not in this repo, not in sam-styles/, not in @gsa-sam/sam-styles, and not in any node_modules of either workspace.
Measured on the /datepicker gallery route added in #666 (Chromium, real browser):
popup: 684 x 2081 px
.datepicker__calendar position: static (needs absolute)
.datepicker__calendar__month__day display: block, width: 684px
Day cells stack vertically down the page instead of forming a 7-column grid, and the popup is not positioned over the input.
Root cause
sam-datepicker-v2 is a fork of angular2-material-datepicker (MIT). The animation trigger is byte-identical, keyframe offsets and all:
// upstream and SAM, identical
trigger('calendarAnimation', [
transition('* => left', [ animate(180, keyframes([
style({ transform: 'translateX(105%)', offset: 0.5 }),
style({ transform: 'translateX(-130%)', offset: 0.51 }),
style({ transform: 'translateX(0)', offset: 1 }) ]))]),
Upstream carried its CSS inline in styles: [...] — 25 .datepicker__* rules, including the structural ones:
.datepicker { position: relative; display: inline-block; }
.datepicker__calendar { position: absolute; overflow: hidden; z-index: 1000;
top: 1.9em; left: 0; height: 24.25em; width: 20.5em;
background-color: #fff; box-shadow: 0 3px 6px rgba(0,0,0,.16), 0 3px 6px rgba(0,0,0,.23); }
SAM's fork (3ba95ec0, Feb 2019, "PR for adding date range component related to IAE-14621" #263) moved the inline template out to picker.template.html and dropped the styles: block entirely, without re-adding it to either the component or sam-styles/. The class names came along, so the markup still requests CSS that has never existed in this repo. date-range-v2.component.scss has been 0 bytes since that same commit and picker.component.ts has no styleUrls.
Why this went unnoticed for ~7 years
Nothing rendered it. test-app could not render any library component until #665, and the sole tracked consumer does not use this component:
scripts/consumer-deep-imports.json tracks 3 consumers, all the same app (iae-sam-front-end, -front-end3, -front-end-uat).
- Zero occurrences of
sam-datepicker-v2 or sam-date-range-v2 in that app's source. It uses the stable control instead: 32x <sam-date>, 8x <sam-date-range>.
SamUIKitModule -> SamExperimentalModule does register SamDateRangeV2Module, so it is compiled into the consumer bundle and available in templates — just never used.
- Five other SAM frontends checked (
-search, -admin, -integrity, -systemaccounts, -role-management-service) do not depend on sam-ui-elements at all.
Contrast with the stable sam-date, which also has no styleUrls but whose markup uses USWDS classes (usa-form-group, usa-form-control) that every consumer already loads globally. That is why sam-date renders fine with no CSS from this library and sam-datepicker-v2 does not.
Decision needed first
Given zero known consumers, "write calendar CSS" may not be the right answer. Pick one:
- Restore the lost upstream CSS as component
styleUrls (matches experimental/tabs, which does self-style; Angular's _ngcontent scoping avoids any global-namespace collision). Upstream is MIT — attribute it.
- Add it to
sam-styles/themes/sam-gov, matching the library's dominant global-CSS model (that is how iae-sam-front-end styles the kit: @import '@gsa-sam/sam-ui-elements/sam-styles/themes/sam-gov'). Riskier — global namespace.
- Deprecate
date-range-v2. It is experimental/, forked, unstyled, and unused. Removal is a breaking change for the deep-import contract, so check scripts/consumer-deep-imports.json first (it currently lists no date-range-v2 paths).
Two smaller, separable gaps
These are legitimately the consumer's responsibility, but the harness needs them for manual testing either way:
.fa fa-calendar — a SAM addition (upstream had no icon; it clicked the input). @fortawesome/fontawesome-free is a root peerDependency, so consumers load the webfont CSS. test-app has only fontawesome-svg-core (JS/SVG API), so no glyph renders.
.sr-only — Bootstrap-era class. @gsa-sam/sam-styles ships only USWDS .usa-sr-only, so nothing defines it and the screen-reader label renders as the visible text "Calendar" next to the input.
Acceptance criteria
Context
Found while manually testing #666, which added the /datepicker gallery route — the first time this component had ever been rendered in a browser in CI or locally. Deliberately kept out of #666 to hold that PR to its two event-handling fixes.
sam-datepicker-v2renders with no styling at all. Its template asks for a full set of bespoke.datepicker__*classes that are not defined in any stylesheet — not in this repo, not insam-styles/, not in@gsa-sam/sam-styles, and not in anynode_modulesof either workspace.Measured on the
/datepickergallery route added in #666 (Chromium, real browser):Day cells stack vertically down the page instead of forming a 7-column grid, and the popup is not positioned over the input.
Root cause
sam-datepicker-v2is a fork ofangular2-material-datepicker(MIT). The animation trigger is byte-identical, keyframe offsets and all:Upstream carried its CSS inline in
styles: [...]— 25.datepicker__*rules, including the structural ones:SAM's fork (
3ba95ec0, Feb 2019, "PR for adding date range component related to IAE-14621" #263) moved the inline template out topicker.template.htmland dropped thestyles:block entirely, without re-adding it to either the component orsam-styles/. The class names came along, so the markup still requests CSS that has never existed in this repo.date-range-v2.component.scsshas been 0 bytes since that same commit andpicker.component.tshas nostyleUrls.Why this went unnoticed for ~7 years
Nothing rendered it.
test-appcould not render any library component until #665, and the sole tracked consumer does not use this component:scripts/consumer-deep-imports.jsontracks 3 consumers, all the same app (iae-sam-front-end,-front-end3,-front-end-uat).sam-datepicker-v2orsam-date-range-v2in that app's source. It uses the stable control instead: 32x<sam-date>, 8x<sam-date-range>.SamUIKitModule->SamExperimentalModuledoes registerSamDateRangeV2Module, so it is compiled into the consumer bundle and available in templates — just never used.-search,-admin,-integrity,-systemaccounts,-role-management-service) do not depend onsam-ui-elementsat all.Contrast with the stable
sam-date, which also has nostyleUrlsbut whose markup uses USWDS classes (usa-form-group,usa-form-control) that every consumer already loads globally. That is whysam-daterenders fine with no CSS from this library andsam-datepicker-v2does not.Decision needed first
Given zero known consumers, "write calendar CSS" may not be the right answer. Pick one:
styleUrls(matchesexperimental/tabs, which does self-style; Angular's_ngcontentscoping avoids any global-namespace collision). Upstream is MIT — attribute it.sam-styles/themes/sam-gov, matching the library's dominant global-CSS model (that is howiae-sam-front-endstyles the kit:@import '@gsa-sam/sam-ui-elements/sam-styles/themes/sam-gov'). Riskier — global namespace.date-range-v2. It isexperimental/, forked, unstyled, and unused. Removal is a breaking change for the deep-import contract, so checkscripts/consumer-deep-imports.jsonfirst (it currently lists nodate-range-v2paths).Two smaller, separable gaps
These are legitimately the consumer's responsibility, but the harness needs them for manual testing either way:
.fa fa-calendar— a SAM addition (upstream had no icon; it clicked the input).@fortawesome/fontawesome-freeis a root peerDependency, so consumers load the webfont CSS.test-apphas onlyfontawesome-svg-core(JS/SVG API), so no glyph renders..sr-only— Bootstrap-era class.@gsa-sam/sam-stylesships only USWDS.usa-sr-only, so nothing defines it and the screen-reader label renders as the visible text "Calendar" next to the input.Acceptance criteria
.datepicker,.datepicker__calendar, nav/arrow/chevron,__labels/__label,__month/__month__day, and__cancelall render as a positioned 7-column calendar overlaytest-apploads FontAwesome webfont CSS and an.sr-onlyrule so/datepickeris manually testable without DevTools injectionposition: absoluteon the popup, popup width, day-cell width ~14.28%) — per AGENTS.md's Vitest/Playwright boundarytest-app/e2e/datepicker.spec.tsstill fails when thecontains()fix inpicker.component.tsis reverted. It clicks the.sr-onlychild explicitly for exactly this reason; adding an.sr-onlyrule collapses that span to 1x1, and a centre click on.fa-calendarwould pass even with the defect reintroduced. Verify by reverting the fix locally.Context
Found while manually testing #666, which added the
/datepickergallery route — the first time this component had ever been rendered in a browser in CI or locally. Deliberately kept out of #666 to hold that PR to its two event-handling fixes.