[Bpk-checkbox-card][CLOV-1271]Adding bpk-checkbox-card#4256
[Bpk-checkbox-card][CLOV-1271]Adding bpk-checkbox-card#4256
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a new bpk-component-checkbox-card package to Backpack, implementing a selectable “checkbox card” pattern with a compound-component API, optional theming, and Storybook examples.
Changes:
- Introduces
BpkCheckboxCardcompound components (Root,Control,Content,Label,Description,Indicator) plus aBpkCheckboxCardSimplewrapper. - Adds styling, tests (unit/form/a11y), Storybook stories/examples, and Figma Code Connect.
- Adds extensive specification/planning docs under
specs/001-checkbox-card/and updates eslint ignores.
Reviewed changes
Copilot reviewed 36 out of 36 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| typecheck.txt | Adds a checked-in typecheck output artifact (should not be committed). |
| specs/001-checkbox-card/tasks.md | Implementation task breakdown for the component. |
| specs/001-checkbox-card/styling-guide.md | Styling guide / token mapping / SCSS patterns. |
| specs/001-checkbox-card/spec.md | Full requirements/specification for checkbox card. |
| specs/001-checkbox-card/research.md | Research notes on existing patterns/components. |
| specs/001-checkbox-card/plan.md | Implementation plan summary. |
| specs/001-checkbox-card/examples/variants.tsx | Spec examples demonstrating visual variants. |
| specs/001-checkbox-card/examples/interactive-states.tsx | Spec examples for interactive states and selection patterns. |
| specs/001-checkbox-card/examples/edge-cases.tsx | Spec examples for edge cases. |
| specs/001-checkbox-card/examples/basic-usage.tsx | Spec examples for basic usage and disabled states. |
| specs/001-checkbox-card/examples/accessibility.tsx | Spec examples for keyboard/form accessibility scenarios. |
| specs/001-checkbox-card/checklists/requirements.md | Spec quality checklist. |
| specs/001-checkbox-card/api-design.md | Proposed API design and usage examples. |
| packages/bpk-component-checkbox-card/src/themeAttributes.ts | Theme attributes + theme factory for BpkThemeProvider. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCardSimple/BpkCheckboxCardSimple.tsx | Simple wrapper API around the compound component. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/subcomponents/Root.tsx | Core state/ARIA handling and interaction logic. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/subcomponents/Label.tsx | Label slot component using BpkText. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/subcomponents/Indicator.tsx | Optional corner indicator slot. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/subcomponents/Description.tsx | Description slot component using BpkText. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/subcomponents/Control.tsx | Hidden checkbox input for form submission. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/subcomponents/Content.tsx | Content wrapper slot. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/subcomponents/CheckboxCardContext.tsx | React context powering the compound API. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/index.ts | Re-exports compound component API. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/form-test.tsx | Form integration tests. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/common-types.ts | Public constants/types for variants/radius/size. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/accessibility-test.tsx | jest-axe accessibility tests. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/snapshots/BpkCheckboxCard-test.tsx.snap | Snapshots for compound component. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/BpkCheckboxCard.tsx | Compound component composition/export surface. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/BpkCheckboxCard.module.scss | CSS Modules styling for the checkbox card. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/BpkCheckboxCard.figma.tsx | Figma Code Connect integration. |
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/BpkCheckboxCard-test.tsx | Unit + interaction tests (click/keyboard/uncontrolled). |
| packages/bpk-component-checkbox-card/index.ts | Package-level exports (compound, simple wrapper, types, theming). |
| packages/bpk-component-checkbox-card/README.md | Component README (currently documents an outdated API). |
| examples/bpk-component-checkbox-card/stories.tsx | Storybook stories wiring. |
| examples/bpk-component-checkbox-card/examples.tsx | Storybook example implementations incl. theming and indicator. |
| .eslintignore | Ignores specs/ from eslint. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| disabled | ||
| />, | ||
| ); | ||
| const results = await axe(container); |
There was a problem hiding this comment.
In the “when disabled” test, axe is called without AXE_OPTIONS, while the other cases disable the nested-interactive rule. This inconsistency can cause flaky failures (or hide real issues in other cases). Use the same AXE_OPTIONS consistently across all the tests, or document why the disabled case is intentionally different.
| const results = await axe(container); | |
| const results = await axe(container, AXE_OPTIONS); |
| const computedAriaLabelledby = ariaLabelledby ?? labelId; | ||
| const computedAriaDescribedby = ariaDescribedby ?? descriptionId; | ||
|
|
||
| return ( | ||
| <CheckboxCardContext.Provider value={contextValue}> | ||
| <div | ||
| role="checkbox" | ||
| aria-checked={checked} | ||
| aria-disabled={disabled || undefined} | ||
| tabIndex={disabled ? -1 : 0} | ||
| aria-label={ariaLabel} | ||
| aria-labelledby={ariaLabel ? undefined : computedAriaLabelledby} | ||
| aria-describedby={computedAriaDescribedby} | ||
| className={rootClassName} |
There was a problem hiding this comment.
aria-describedby and (when aria-label isn’t provided) aria-labelledby default to generated IDs even when no corresponding Description/Label element is rendered. This produces invalid ARIA IDREFs (and an unlabeled checkbox in the “empty content” case). Consider only setting aria-describedby/aria-labelledby when the consumer explicitly provides them, or introduce a mechanism to know whether the Label/Description slots are present (e.g., register via context/useEffect) before wiring up these attributes; otherwise require aria-label for cards without a visible label.
packages/bpk-component-checkbox-card/src/BpkCheckboxCardSimple/BpkCheckboxCardSimple.tsx
Outdated
Show resolved
Hide resolved
|
|
||
| > backpack@0.0.1 typecheck | ||
| > tsc | ||
|
|
||
| examples/bpk-component-checkbox-card/examples.tsx(22,30): error TS7016: Could not find a declaration file for module '../../packages/bpk-theming'. '/Users/gert-janvercauteren/conductor/workspaces/backpack/copenhagen/packages/bpk-theming/index.js' implicitly has an 'any' type. | ||
| examples/bpk-component-checkbox-card/stories.tsx(28,8): error TS2307: Cannot find module './new-api-examples' or its corresponding type declarations. | ||
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/BpkCheckboxCard-test.tsx(82,41): error TS2339: Property 'withBackground' does not exist on type '{ readonly onCanvasDefault: "on-canvas-default"; readonly onCanvasContrast: "on-canvas-contrast"; readonly onSurfaceContrast: "on-surface-contrast"; }'. | ||
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/BpkCheckboxCard-test.tsx(94,41): error TS2339: Property 'noBackground' does not exist on type '{ readonly onCanvasDefault: "on-canvas-default"; readonly onCanvasContrast: "on-canvas-contrast"; readonly onSurfaceContrast: "on-surface-contrast"; }'. | ||
| packages/bpk-component-checkbox-card/src/BpkCheckboxCard/BpkCheckboxCardPrice.tsx(19,22): error TS7016: Could not find a declaration file for module '../../../bpk-component-price'. '/Users/gert-janvercauteren/conductor/workspaces/backpack/copenhagen/packages/bpk-component-price/index.js' implicitly has an 'any' type. | ||
| packages/bpk-component-checkbox-card/src/BpkCheckboxCardSimple/BpkCheckboxCardSimple.tsx(156,32): error TS2322: Type '{ children: (false | "" | 0 | Element | null | undefined)[]; orientation: string; align: string; gap: string; }' is not assignable to type 'IntrinsicAttributes & BpkCheckboxCardContentProps'. | ||
| Property 'orientation' does not exist on type 'IntrinsicAttributes & BpkCheckboxCardContentProps'. | ||
| packages/bpk-component-checkbox-card/src/BpkCheckboxCardSimple/BpkCheckboxCardSimple.tsx(157,19): error TS2741: Property 'icon' is missing in type '{ children: ReactElement<any, string | JSXElementConstructor<any>>; }' but required in type 'BpkCheckboxCardIconProps'. | ||
| packages/bpk-component-checkbox-card/src/BpkCheckboxCardSimple/BpkCheckboxCardSimple.tsx(167,20): error TS2741: Property 'price' is missing in type '{ children: string | number | true | ReactElement<any, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal; }' but required in type 'BpkCheckboxCardPriceProps'. | ||
| packages/bpk-component-checkbox-card/src/BpkCheckboxCardSimple/BpkCheckboxCardSimple.tsx(169,24): error TS2339: Property 'Indicator' does not exist on type '(({ children, checked: controlledChecked, defaultChecked, onCheckedChange, disabled, required, name, value, variant, radius, width, height, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledby, "aria-describedby": ariaDescribedby, }: BpkCheckboxCardRootProps) => Element) & { Root: ({ children, checked: control...'. |
There was a problem hiding this comment.
This PR adds typecheck.txt containing local tsc output/errors. This looks like a build artifact rather than a source file, and committing it risks masking the real expectation that the repo should typecheck cleanly. Please remove this file from the PR (and ensure typecheck output is handled by CI rather than checked in).
|
Visit https://backpack.github.io/storybook-prs/4256 to see this build running in a browser. |
|
Visit https://backpack.github.io/storybook-prs/4256 to see this build running in a browser. |
|
Visit https://backpack.github.io/storybook-prs/4256 to see this build running in a browser. |
|
Visit https://backpack.github.io/storybook-prs/4256 to see this build running in a browser. |
|
Visit https://backpack.github.io/storybook-prs/4256 to see this build running in a browser. |
c1e435c to
5ed5af9
Compare
|
Visit https://backpack.github.io/storybook-prs/4256 to see this build running in a browser. |
|
Visit https://backpack.github.io/storybook-prs/4256 to see this build running in a browser. |
|
Visit https://backpack.github.io/storybook-prs/4256 to see this build running in a browser. |
Code reviewFound 2 issues:
Lines 1 to 14 in 553e81e
Lines 4 to 6 in 553e81e 🤖 Generated with Claude Code - If this code review was useful, please react with 👍. Otherwise, react with 👎. |
| export default { | ||
| title: 'bpk-component-checkbox-card', | ||
| component: BpkCheckboxCard, | ||
| decorators: [(Story: () => JSX.Element) => <BpkProvider><Story /></BpkProvider>], |
There was a problem hiding this comment.
Perhaps we could change this to (Story: any)?

Summary
Introduces
bpk-component-checkbox-card— a new Backpack component providing a selectable card UI pattern currently implemented ad-hoc across Hotels, Flights, and Car Hire verticals.What's included
Compound component API (primary)
BpkCheckboxCard.Root<div role="checkbox">— state provider, handles click/keyboardBpkCheckboxCard.Control<input>for native form submission (aria-hidden)BpkCheckboxCard.ContentBpkCheckboxCard.Labelaria-labelledbyBpkCheckboxCard.Descriptionaria-describedbyBpkCheckboxCard.IndicatorSimple API
BpkCheckboxCardSimple— props-based wrapper for common icon + label + price layouts.Variants & customisation
onCanvasDefault,onCanvasContrast,onSurfaceContrastsm,mdrounded,squarecreateCheckboxCardTheme/CHECKBOX_CARD_THEME_ATTRIBUTESchecked/onCheckedChange) and uncontrolled (defaultChecked) modesTests & documentation
Accessibility
role="checkbox"witharia-checked,aria-disabled,aria-requiredSpaceandEntertoggle selectionaria-labelledby/aria-describedbyauto-wired from Label/Description subcomponentstabIndex={-1}andaria-disabled(remain in DOM for AT announcements)Figma
https://www.figma.com/design/ITvypOGdga42nM2ipBM4uk/Bpk-2.0?node-id=90-7627&m=dev
Remember to include the following changes:
[Clover-123][BpkButton] Updating the colourREADME.md(If you have created a new component)README.md