Conversation
📖 Storybook Preview |
packages/design-system-react/src/components/HeaderBase/HeaderBase.tsx
Outdated
Show resolved
Hide resolved
| <View | ||
| style={[ | ||
| tw.style(resolvedTwClassName), | ||
| includesTopInset && { marginTop: insets.top }, |
There was a problem hiding this comment.
Top inset uses outer margin
Medium Severity
When includesTopInset is enabled, HeaderBase applies marginTop: insets.top instead of internal top padding. This moves the whole header down rather than expanding it, which breaks safe-area behavior and can create unintended spacing gaps in parent layouts.
There was a problem hiding this comment.
This is intended
packages/design-system-react-native/src/components/HeaderBase/HeaderBase.tsx
Show resolved
Hide resolved
📖 Storybook Preview |
📖 Storybook Preview |
📖 Storybook Preview |
📖 Storybook Preview |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
📖 Storybook Preview |
📖 Storybook Preview |
📖 Storybook Preview |
📖 Storybook Preview |
📖 Storybook Preview |
📖 Storybook Preview |
| > | ||
| {renderEndContent()} | ||
| </View> | ||
| </View> |
There was a problem hiding this comment.
Wrapper style overridden by spread props
Medium Severity
startAccessoryWrapperProps and endAccessoryWrapperProps are spread after the wrapper View’s own style, so a consumer-provided style in those props overwrites the internal width/alignment styles used to keep the title centered, causing layout balancing to break when wrapper styles are customized.
georgewrmarshall
left a comment
There was a problem hiding this comment.
Looking good. Left some comments
There was a problem hiding this comment.
remove image as it can become out dated
| export const TwClassName: Story = { | ||
| render: () => ( | ||
| <HeaderBase twClassName="bg-info-default px-4"> | ||
| Header with Custom Styles | ||
| </HeaderBase> | ||
| ), | ||
| }; |
There was a problem hiding this comment.
Don't think we need this story for the twClassName prop just let the readme template explain it. If this was created by the cursor rule, let's update the rule to exclude these props that are taken care of by readme
| ), | ||
| }; | ||
|
|
||
| export const EndButtonIconProps: Story = { |
There was a problem hiding this comment.
maybe we can be a bit more selective on stories and improve the cursor rule here to exclude prop object, twClassName and style props
| const START_ACCESSORY_TEST_ID = 'start-accessory-wrapper'; | ||
| const END_ACCESSORY_TEST_ID = 'end-accessory-wrapper'; | ||
| const BUTTON_ICON_TEST_ID = 'button-icon'; | ||
| const CUSTOM_CONTENT_TEST_ID = 'custom-content'; | ||
| const START_CONTENT_TEST_ID = 'start-content'; | ||
| const END_CONTENT_TEST_ID = 'end-content'; |
There was a problem hiding this comment.
I prefer this over keeping the test id consts in the const file.
| includesTopInset = false, | ||
| startAccessoryWrapperProps, | ||
| endAccessoryWrapperProps, | ||
| testID = HEADERBASE_TEST_ID, |
There was a problem hiding this comment.
We should never set a default testID, will add this to the cursor rules and check the component script
| <Box twClassName="flex-1 items-center"> | ||
| {typeof children === 'string' ? ( | ||
| <Text | ||
| variant={HEADERBASE_TITLE_TEXT_VARIANT} | ||
| testID={HEADERBASE_TITLE_TEST_ID} | ||
| style={tw.style('text-center')} | ||
| > | ||
| {children} | ||
| </Text> | ||
| ) : ( | ||
| children | ||
| )} | ||
| </Box> |
There was a problem hiding this comment.
Not sure where we got to on this pattern but I think it's likely better to provide a title prop than do this type checking and rendering.
| * | ||
| * @default false | ||
| */ | ||
| includesTopInset?: boolean; |
There was a problem hiding this comment.
Do we need this in react?
| /** | ||
| * Optional test ID for the header container (maps to data-testid). | ||
| */ | ||
| testID?: string; |
There was a problem hiding this comment.
We should use 'data-testid'?: string; here
Added "Anti-Patterns to Avoid" section with 3 key patterns identified in PR reviews: 1. SAMPLE_PROPS constants - Use component default parameters instead 2. Default test IDs - No defaults, consumer provides when needed, React uses data-testid 3. String children type checking - Use explicit props or require Text composition Also condensed Benefits and Quick Decision Rules sections to keep file at 398 lines (within 200-400 target). References: - PR #909 review: #909 (review) - PR #908 discussion: #908 (comment)


Description
This PR adds the HeaderBase component to both
@metamask/design-system-react(web) and@metamask/design-system-react-native(mobile).Reason for the change: A shared, reusable header component is needed across MetaMask products to keep a consistent layout (title with optional start/end accessories) and to avoid duplicating header logic.
What’s included:
children), and optional end accessory. Supports custom content viastartAccessory/endAccessoryor built-in ButtonIcon usage viastartButtonIconProps/endButtonIconProps.Box,Text,ButtonIcon; supportsclassName,style,includesTopInset(padding), anddata-testidviatestID.Box,Text,ButtonIcon,useSafeAreaInsetsfor optional top safe area inset (includesTopInset); supportstwClassName,style, and layout balancing so the title stays centered when accessories have different widths.Related issues
Fixes: N/A (or add ticket link if applicable)
Manual testing steps
yarn storybookand open HeaderBase under the design-system-react components. Confirm default, with start/end ButtonIcons, with custom accessories, and with top inset variants.yarn storybook:iosoryarn storybook:androidand open HeaderBase under the design-system-react-native components. Confirm the same variants and that the header respects safe area whenincludesTopInsetis true.yarn jest(or run tests for the two packages).Screenshots/Recordings
Before
N/A — new component; no prior header in the design system packages.
After
DSR
Screen.Recording.2026-02-16.at.5.01.38.PM.mov
DSRN
Simulator.Screen.Recording.-.iPhone.15.Pro.Max.-.2026-02-16.at.15.59.59.mov
Pre-merge author checklist
Pre-merge reviewer checklist
Note
Medium Risk
Adds a new cross-package UI component and updates RN Jest transforms/mocks and testing-library versions, which can cause subtle test or layout regressions despite being largely additive.
Overview
Adds a new
HeaderBasecomponent to both the web (design-system-react) and React Native (design-system-react-native) design system packages, providing a centered title area with optional start/end accessories orButtonIcon-driven actions, optional safe-area top inset handling, and standard test IDs.Includes Storybook stories and docs for both implementations, adds comprehensive unit tests, exports the component from each package’s
components/index.ts, and updates the RN testing setup (Jest transform/mocks) plus bumps@testing-library/react-nativeto^13.2.0(and corresponding lockfile changes) to support the new safe-area dependency usage.Written by Cursor Bugbot for commit a957f35. This will update automatically on new commits. Configure here.