Migrate React components from external Skyscanner repositories (e.g., carhire-homepage)
into Backpack design system components. Use when: (1) Component exists in app-specific
repo with "unstable_backpack" or similar prefix, (2) Component needs to be promoted to
official Backpack component, (3) Converting app code to follow Backpack constitution,
(4) Extracting reusable UI patterns from product repos. Covers GitHub API access,
Backpack naming conventions, modern Sass API, TypeScript patterns, license headers,
accessibility testing, and Storybook integration. MANDATORY: Component must pass full
test suite (pnpm run lint && pnpm run check-react-versions && pnpm run check-bpk-dependencies
&& pnpm run jest) with 0 errors before acceptance.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Migrate React components from external Skyscanner repositories (e.g., carhire-homepage)
into Backpack design system components. Use when: (1) Component exists in app-specific
repo with "unstable_backpack" or similar prefix, (2) Component needs to be promoted to
official Backpack component, (3) Converting app code to follow Backpack constitution,
(4) Extracting reusable UI patterns from product repos. Covers GitHub API access,
Backpack naming conventions, modern Sass API, TypeScript patterns, license headers,
accessibility testing, and Storybook integration. MANDATORY: Component must pass full
test suite (pnpm run lint && pnpm run check-react-versions && pnpm run check-bpk-dependencies
&& pnpm run jest) with 0 errors before acceptance.
author
Claude Code
version
1.4.0
date
2026-03-02T00:00:00.000Z
changelog
v1.4.0 (2026-03-02):
- Fixed index.ts template: use explicit `import ... + export default` instead of `export { default }` shorthand
- Simplified README template to match standard Backpack format (button/chip pattern)
- README now only includes: Installation + Usage + Props (removed Tracking, Accessibility, Design tokens, Features sections)
- Added "What NOT to include in README" guidance
- Removed README Tracking section from verification checklist
v1.3.0 (2026-02-28):
- Added mandatory data-backpack-ds-component attribute requirement
- Updated TypeScript template to include getDataComponentAttribute usage
- Added README Tracking section template
- Added to verification checklist
v1.2.0 (2026-02-28):
- Closed props interface by default: no className, no HTML element spread
- Added "Why no HTML element spread?" rationale
- Updated TypeScript template to reflect lean props API
- Updated test/example templates to match
- Updated API Encapsulation notes section
v1.1.0 (2026-02-12):
- Added mandatory full test suite acceptance criteria
- Enhanced verification phase with comprehensive debugging steps
- Added common acceptance failure patterns and solutions
- Clarified that 100% component coverage is required
- Added detailed lint failure troubleshooting
- Documented proper handling of generated directories in .eslintignore
- Added guidance for undefined Sass token errors
- Expanded verification checklist with accessibility requirements
v1.0.0 (2026-02-12):
- Initial skill creation from BpkThinking component migration
- Complete workflow from external repo to Backpack standards
Backpack External Component Migration
Problem
Components developed in product-specific repositories (like carhire-homepage) need to be
converted into proper Backpack design system components that follow strict architectural
conventions, accessibility standards, and design system patterns.
Context / Trigger Conditions
Use this workflow when:
Component exists in another Skyscanner repo with path like unstable_backpack/ComponentName
Product team wants to contribute component back to Backpack
Component has been validated in production and ready for design system inclusion
Need to standardize an existing component to Backpack standards
Converting one-off UI patterns into reusable design system components
Common indicators:
Component has unstable_backpack in its path
Uses basic Backpack components but doesn't follow full Backpack structure
Has product-specific dependencies that need to be removed
# Look for similar existing Backpack componentls packages/backpack-web/src/bpk-component-*/
# Study the reference component structure# Good references: bpk-component-chip, bpk-component-button
/*
* Backpack - Skyscanner's Design System
*
* Copyright 2016 Skyscanner Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/importBpkText, { TEXT_STYLES } from'../../bpk-component-text';
import { cssModules, getDataComponentAttribute } from'../../bpk-react-utils';
importSTYLESfrom'./Bpk[ComponentName].module.scss';
const getClassName = cssModules(STYLES);
exporttypeBpk[ComponentName]Props = {
// Only the props this component actually needs — no HTML element spreadsomeRequiredProp: string;
someOptionalProp?: ThingType;
};
constBpk[ComponentName] = ({
someOptionalProp = DEFAULT_VALUE,
someRequiredProp,
}: Bpk[ComponentName]Props) => (
<divclassName={getClassName('bpk-[component-name]')}
{...getDataComponentAttribute('[ComponentName]')}
data-testid="bpk-[component-name]"
>
{/* Component content */}
</div>
);
exportdefaultBpk[ComponentName];
✅ Use cssModules(STYLES) pattern, not custom CSS utility
✅ Add data-testid for testing
✅ Add {...getDataComponentAttribute('[ComponentName]')} to root element (component name WITHOUT "Bpk" prefix)
✅ Keep props interface minimal — only declare props the component genuinely needs
✅ Replace div layout wrappers with BpkLayout components — use BpkHStack for rows, BpkVStack for columns, BpkBox for generic containers. Preserve gap/align/justify by mapping to gap={BpkSpacing.X}, alignItems, justifyContent props. Wrap any usage in <BpkProvider> (Chakra UI context requirement).
❌ NO raw <div> for layout — always prefer BpkLayout components
❌ NO className or style props for new components (API encapsulation, constitution XI)
❌ NO & Omit<ComponentPropsWithoutRef<'div'>, 'children'> — do NOT spread HTML element props. Default to a closed, explicit props interface. Only use element spread when the component is explicitly a thin wrapper that must forward all native attributes (rare).
❌ NO product-specific i18n hooks
Why no HTML element spread?
Extending ComponentPropsWithoutRef<'div'> seems convenient but in practice:
It exposes dozens of irrelevant props (onPointerEnterCapture, aria-*, data-*, etc.)
It lets consumers bypass intentional API constraints
It makes the component contract unclear and harder to evolve
It couples the component to a specific HTML element
Only use it when the component is explicitly a thin wrapper around a native element (e.g. a styled <button> that must accept all button attributes).
✅ Import specific mixins: @use '../../bpk-mixins/tokens'
✅ Use token functions: tokens.bpk-spacing-md()
✅ Use token variables: tokens.$bpk-surface-contrast-day
✅ All sizing in rem, never px (accessibility requirement)
✅ For any rem value, first search @skyscanner/bpk-foundations-web tokens for a matching spacing/size token (e.g. tokens.bpk-spacing-xxl() = 2.5rem, tokens.bpk-spacing-xl() = 2rem). Only use raw rem if no token matches, in which case use tokens.$bpk-one-pixel-rem * <px-value> (e.g. tokens.$bpk-one-pixel-rem * 280 for 280px)
✅ BEM naming: .bpk-[name], .bpk-[name]__[element], .bpk-[name]--[modifier]
✅ Support RTL with @include utils.bpk-rtl
✅ Support reduced motion preference
❌ NO magic numbers - use design tokens
❌ NO inline colors like #FFFFFF - use tokens.$bpk-color-white
Pattern rationale: Matches the majority of Backpack components (button, card, chip, text). Always explicitly import the component, then export default — do not use the export { default } from shorthand.
2.8 Create README
Standard README format (follow button/chip pattern — keep it minimal):
Component handles RTL languages (uses @include utils.bpk-rtl)
Component is responsive at different viewport sizes
Component works on mobile and desktop
Notes
Design Approval Required
CRITICAL: Before starting migration, component MUST have:
Design approval from Backpack squad (#backpack Slack)
Figma designs with all states documented
Accessibility annotations in Figma
Token specifications (no magic numbers in designs)
Do NOT proceed without design approval - this is non-negotiable per constitution.
When to Skip Migration
Don't migrate if:
Component is too product-specific (not reusable)
Component doesn't meet accessibility standards
Design patterns don't align with Backpack philosophy
Component has unstable API still under experimentation
Consider creating as experimental V2 component instead if uncertain.
API Encapsulation for New Components
Per constitution principle XI:
NEW components must NOT expose className or style props
NEW components must NOT spread HTML element props via & Omit<ComponentPropsWithoutRef<'div'>, 'children'> or similar — default to a closed, explicit props interface
Only declare props the component actually uses
Prevents consumers from bypassing the design system's visual constraints
Makes the component contract clear and easy to evolve
Existing components may grandfather className for backward compatibility, but do NOT replicate this in new components
Dependency Removal
Common product-specific dependencies to remove:
@skyscanner-web/*/src/services/i18n → Use content prop instead
Product-specific utility functions → Use Backpack utilities
Custom CSS modules patterns → Use cssModules(STYLES)