Skip to content

feat: RadioButton#926

Merged
georgewrmarshall merged 2 commits into
MetaMask:mainfrom
kirillzyusko:feat/radio-button
Feb 23, 2026
Merged

feat: RadioButton#926
georgewrmarshall merged 2 commits into
MetaMask:mainfrom
kirillzyusko:feat/radio-button

Conversation

@kirillzyusko

@kirillzyusko kirillzyusko commented Feb 20, 2026

Copy link
Copy Markdown
Collaborator

Description

Added RadioButton component

Related issues

Fixes: https://consensyssoftware.atlassian.net/browse/DSYS-297

Manual testing steps

  1. Open StoryBook app
  2. Open RadioButton example

Screenshots/Recordings

Before

After

image

Pre-merge author checklist

  • I've followed MetaMask Contributor Docs
  • I've completed the PR template to the best of my ability
  • I’ve included tests if applicable
  • I’ve documented my code using JSDoc format if applicable
  • I’ve applied the right labels on the PR (see labeling guidelines). Not required for external contributors.

Pre-merge reviewer checklist

  • I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed).
  • I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots.

Note

Low Risk
Adds a new UI component with isolated exports/stories/tests; minimal risk beyond potential visual/a11y regressions in consumers adopting it.

Overview
Adds a new RadioButton component to design-system-react-native, including state styling for checked/disabled/read-only/danger, accessibility (role="radio", accessibilityState), and optional label rendering.

Wires the component into the public exports (components/index.ts), adds Storybook stories (and updates the generated storybook.requires.js to include them), plus unit tests and a README documenting props and usage.

Written by Cursor Bugbot for commit 78c89de. This will update automatically on new commits. Configure here.

@kirillzyusko kirillzyusko self-assigned this Feb 20, 2026
@kirillzyusko kirillzyusko marked this pull request as ready for review February 20, 2026 15:17
@kirillzyusko kirillzyusko requested a review from a team as a code owner February 20, 2026 15:17
@kirillzyusko kirillzyusko changed the title [WIP] feat: RadioButton feat: RadioButton Feb 20, 2026
)}
</View>
{label ? (
<TextOrChildren textProps={{ ...labelProps, twClassName: 'ml-3' }}>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

User's labelProps.twClassName silently overwritten by hardcoded value

Medium Severity

The expression { ...labelProps, twClassName: 'ml-3' } always overwrites any twClassName the user passes via labelProps. For example, the README documents labelProps={{ twClassName: 'text-error-default' }}, but this would be silently replaced with just 'ml-3', discarding the user's custom class. The two values need to be merged rather than one replacing the other.

Additional Locations (1)

Fix in Cursor Fix in Web

accessibilityRole="radio"
accessibilityState={{
checked: isChecked,
disabled: isDisabled,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessibility state misreports read-only as enabled

Medium Severity

The disabled prop on the TouchableOpacity is isDisabled || isReadOnly, correctly preventing interaction for both states. However, accessibilityState.disabled only reflects isDisabled, not isReadOnly. When isReadOnly is true but isDisabled is false, screen readers announce the radio button as enabled even though it cannot be pressed — a mismatch between actual and communicated interactivity.

Fix in Cursor Fix in Web

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

isChecked={isChecked}
onPress={() => setIsChecked(!isChecked)}
/>
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Story args changes won't update checked state

Low Severity

RadioButtonStory initializes local state from args.isChecked once, so changing the isChecked control in Storybook after the first render won’t update the rendered checked state, leading to controls that appear unresponsive or out of sync.

Fix in Cursor Fix in Web

@georgewrmarshall georgewrmarshall left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@georgewrmarshall georgewrmarshall enabled auto-merge (squash) February 23, 2026 21:07
@georgewrmarshall georgewrmarshall merged commit 044213b into MetaMask:main Feb 23, 2026
43 checks passed
@georgewrmarshall georgewrmarshall mentioned this pull request Feb 25, 2026
5 tasks
georgewrmarshall added a commit that referenced this pull request Feb 25, 2026
## Release 21.0.0

This release includes breaking changes, new features, and refactoring
improvements across the design system packages.

### 📦 Package Versions

- `@metamask/design-system-react`: **0.9.0**
- `@metamask/design-system-react-native`: **0.8.0**
- `@metamask/design-system-shared`: **0.2.0**

### ⚠️ Breaking Changes

#### BadgeStatus Migration to String Union Types (#912)

The `BadgeStatus` component has been migrated from TypeScript enums to
string union types with const objects, implementing ADR-0003 and
ADR-0004:

**What Changed:**
- `BadgeStatusStatus` and `BadgeStatusSize` enums replaced with const
objects
- Types now centralized in `@metamask/design-system-shared` package
- Enables structural typing - both const values and string literals now
accepted

**Migration Required:**
- ✅ **Recommended**: Import from shared package
  ```typescript
  import { BadgeStatusStatus } from '@metamask/design-system-shared'
  ```
- ⚠️ **Still works** but deprecated: Importing from component packages
will re-export from shared
- Const object values remain the same: `BadgeStatusStatus.Active` still
works
- String literals now supported: `'active'` accepted where
`BadgeStatusStatus.Active` is expected

**Affected Packages:**
- `@metamask/design-system-react@0.9.0`
- `@metamask/design-system-react-native@0.8.0`
- `@metamask/design-system-shared@0.2.0`

### ✨ New Features

#### RadioButton Component (#926)
- Added `RadioButton` component to React Native
- Supports checked, disabled, read-only, and danger states
- Full accessibility support with `role="radio"` and
`accessibilityState`
- Optional label rendering

### 🔨 Refactoring

#### BottomSheetFooter Reorganization (#933)
- Moved `BottomSheetFooter` from `BottomSheets/BottomSheetFooter/` to
`BottomSheetFooter/`
- Updated import paths and Storybook title
- No breaking changes - all package imports continue to work

### 📚 References

- ADR-0003: Enum to String Union Migration
- ADR-0004: Centralized Types Architecture
- [MetaMask Decisions Repository](https://github.com/MetaMask/decisions)

### ✅ Checklist

- [x] All changelogs updated with human-readable descriptions
- [x] Breaking changes clearly documented
- [x] Changelog validation passed (`yarn changelog:validate`)
- [x] All packages built successfully
- [x] Migration paths provided for breaking changes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Release/version bumps are low risk, but the documented **breaking**
`BadgeStatus` type export change and updated peer dependency ranges can
cause downstream TypeScript/build breakages for consumers.
> 
> **Overview**
> Bumps the monorepo release to `21.0.0` and publishes new package
versions: `@metamask/design-system-react@0.9.0`,
`@metamask/design-system-react-native@0.8.0`, and
`@metamask/design-system-shared@0.2.0`.
> 
> Updates changelogs to document a **breaking** `BadgeStatus` type
migration (enums → const objects + derived string unions, centralized in
`design-system-shared`), plus a React Native `RadioButton` addition and
a `BottomSheetFooter` re-org. Also bumps `design-system-react` peer
dependency ranges for `@metamask/design-system-tailwind-preset` and
`@metamask/design-tokens`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6a887c7. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude <noreply@anthropic.com>
@georgewrmarshall georgewrmarshall mentioned this pull request Feb 25, 2026
6 tasks
georgewrmarshall added a commit that referenced this pull request Feb 25, 2026
## Release 21.0.0

This release includes breaking changes, new features, and refactoring
improvements across the design system packages.

**Note:** This is a corrected resubmission of #938 without peer
dependency updates that caused yarn.lock modifications in CI.

### 📦 Package Versions

- `@metamask/design-system-react`: **0.9.0**
- `@metamask/design-system-react-native`: **0.8.0**
- `@metamask/design-system-shared`: **0.2.0**

### ⚠️ Breaking Changes

#### BadgeStatus Migration to String Union Types (#912)

The `BadgeStatus` component has been migrated from TypeScript enums to
string union types with const objects:

**What Changed:**
- `BadgeStatusStatus` and `BadgeStatusSize` enums replaced with const
objects
- **No migration required** - continue importing from your current
package
- Const object values remain the same: `BadgeStatusStatus.Active` still
works
- String literals now also accepted: `'active'` works where
`BadgeStatusStatus.Active` is expected
- We are still evaluating best practices for const objects vs string
literals

**Affected Packages:**
- `@metamask/design-system-react@0.9.0`
- `@metamask/design-system-react-native@0.8.0`
- `@metamask/design-system-shared@0.2.0`

**Learn More:**
- [ADR-0003: Enum to String Union
Migration](https://github.com/MetaMask/decisions/blob/main/decisions/design-system/0003-enum-to-string-union-migration.md)
- [ADR-0004: Centralized Types
Architecture](https://github.com/MetaMask/decisions/blob/main/decisions/design-system/0004-centralized-types-architecture.md)

### ✨ New Features

#### RadioButton Component (#926)
- Added `RadioButton` component to React Native
- Supports checked, disabled, read-only, and danger states
- Full accessibility support with `role="radio"` and
`accessibilityState`
- Optional label rendering

### 🔨 Refactoring

#### BottomSheetFooter Reorganization (#933)
- Moved `BottomSheetFooter` from `BottomSheets/BottomSheetFooter/` to
`BottomSheetFooter/`
- Updated import paths and Storybook title
- No breaking changes - all package imports continue to work

### ✅ Checklist

- [x] All changelogs updated with human-readable descriptions
- [x] Breaking changes clearly documented
- [x] Changelog validation passed (`yarn changelog:validate`)
- [x] All packages built successfully
- [x] Migration paths provided for breaking changes
- [x] No peer dependency changes to avoid yarn.lock modifications

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> This PR only changes package versions and changelog entries; no
runtime code is modified.
> 
> **Overview**
> Bumps the monorepo release to `21.0.0` and updates package versions
for `@metamask/design-system-react` to `0.9.0`,
`@metamask/design-system-react-native` to `0.8.0`, and
`@metamask/design-system-shared` to `0.2.0`.
> 
> Updates the React and React Native changelogs to document a
**breaking** `BadgeStatus` type migration (enums → const objects +
derived string unions), plus RN-only release notes for adding
`RadioButton` and a `BottomSheetFooter` location refactor; also updates
changelog compare links to start from the new versions.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
35569fb. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude <noreply@anthropic.com>
georgewrmarshall added a commit that referenced this pull request Mar 3, 2026
## Release 21.0.0

This release includes breaking changes, new features, and refactoring
improvements across the design system packages.

### 📦 Package Versions

- `@metamask/design-system-react`: **0.9.0**
- `@metamask/design-system-react-native`: **0.8.0**
- `@metamask/design-system-shared`: **0.2.0**

### ⚠️ Breaking Changes

#### BadgeStatus Migration to String Union Types (#912)

The `BadgeStatus` component has been migrated from TypeScript enums to
string union types with const objects, implementing ADR-0003 and
ADR-0004:

**What Changed:**
- `BadgeStatusStatus` and `BadgeStatusSize` enums replaced with const
objects
- Types now centralized in `@metamask/design-system-shared` package
- Enables structural typing - both const values and string literals now
accepted

**Migration Required:**
- ✅ **Recommended**: Import from shared package
  ```typescript
  import { BadgeStatusStatus } from '@metamask/design-system-shared'
  ```
- ⚠️ **Still works** but deprecated: Importing from component packages
will re-export from shared
- Const object values remain the same: `BadgeStatusStatus.Active` still
works
- String literals now supported: `'active'` accepted where
`BadgeStatusStatus.Active` is expected

**Affected Packages:**
- `@metamask/design-system-react@0.9.0`
- `@metamask/design-system-react-native@0.8.0`
- `@metamask/design-system-shared@0.2.0`

### ✨ New Features

#### RadioButton Component (#926)
- Added `RadioButton` component to React Native
- Supports checked, disabled, read-only, and danger states
- Full accessibility support with `role="radio"` and
`accessibilityState`
- Optional label rendering

### 🔨 Refactoring

#### BottomSheetFooter Reorganization (#933)
- Moved `BottomSheetFooter` from `BottomSheets/BottomSheetFooter/` to
`BottomSheetFooter/`
- Updated import paths and Storybook title
- No breaking changes - all package imports continue to work

### 📚 References

- ADR-0003: Enum to String Union Migration
- ADR-0004: Centralized Types Architecture
- [MetaMask Decisions Repository](https://github.com/MetaMask/decisions)

### ✅ Checklist

- [x] All changelogs updated with human-readable descriptions
- [x] Breaking changes clearly documented
- [x] Changelog validation passed (`yarn changelog:validate`)
- [x] All packages built successfully
- [x] Migration paths provided for breaking changes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Release/version bumps are low risk, but the documented **breaking**
`BadgeStatus` type export change and updated peer dependency ranges can
cause downstream TypeScript/build breakages for consumers.
> 
> **Overview**
> Bumps the monorepo release to `21.0.0` and publishes new package
versions: `@metamask/design-system-react@0.9.0`,
`@metamask/design-system-react-native@0.8.0`, and
`@metamask/design-system-shared@0.2.0`.
> 
> Updates changelogs to document a **breaking** `BadgeStatus` type
migration (enums → const objects + derived string unions, centralized in
`design-system-shared`), plus a React Native `RadioButton` addition and
a `BottomSheetFooter` re-org. Also bumps `design-system-react` peer
dependency ranges for `@metamask/design-system-tailwind-preset` and
`@metamask/design-tokens`.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
6a887c7. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude <noreply@anthropic.com>
georgewrmarshall added a commit that referenced this pull request Mar 3, 2026
## Release 21.0.0

This release includes breaking changes, new features, and refactoring
improvements across the design system packages.

**Note:** This is a corrected resubmission of #938 without peer
dependency updates that caused yarn.lock modifications in CI.

### 📦 Package Versions

- `@metamask/design-system-react`: **0.9.0**
- `@metamask/design-system-react-native`: **0.8.0**
- `@metamask/design-system-shared`: **0.2.0**

### ⚠️ Breaking Changes

#### BadgeStatus Migration to String Union Types (#912)

The `BadgeStatus` component has been migrated from TypeScript enums to
string union types with const objects:

**What Changed:**
- `BadgeStatusStatus` and `BadgeStatusSize` enums replaced with const
objects
- **No migration required** - continue importing from your current
package
- Const object values remain the same: `BadgeStatusStatus.Active` still
works
- String literals now also accepted: `'active'` works where
`BadgeStatusStatus.Active` is expected
- We are still evaluating best practices for const objects vs string
literals

**Affected Packages:**
- `@metamask/design-system-react@0.9.0`
- `@metamask/design-system-react-native@0.8.0`
- `@metamask/design-system-shared@0.2.0`

**Learn More:**
- [ADR-0003: Enum to String Union
Migration](https://github.com/MetaMask/decisions/blob/main/decisions/design-system/0003-enum-to-string-union-migration.md)
- [ADR-0004: Centralized Types
Architecture](https://github.com/MetaMask/decisions/blob/main/decisions/design-system/0004-centralized-types-architecture.md)

### ✨ New Features

#### RadioButton Component (#926)
- Added `RadioButton` component to React Native
- Supports checked, disabled, read-only, and danger states
- Full accessibility support with `role="radio"` and
`accessibilityState`
- Optional label rendering

### 🔨 Refactoring

#### BottomSheetFooter Reorganization (#933)
- Moved `BottomSheetFooter` from `BottomSheets/BottomSheetFooter/` to
`BottomSheetFooter/`
- Updated import paths and Storybook title
- No breaking changes - all package imports continue to work

### ✅ Checklist

- [x] All changelogs updated with human-readable descriptions
- [x] Breaking changes clearly documented
- [x] Changelog validation passed (`yarn changelog:validate`)
- [x] All packages built successfully
- [x] Migration paths provided for breaking changes
- [x] No peer dependency changes to avoid yarn.lock modifications

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Low Risk**
> This PR only changes package versions and changelog entries; no
runtime code is modified.
> 
> **Overview**
> Bumps the monorepo release to `21.0.0` and updates package versions
for `@metamask/design-system-react` to `0.9.0`,
`@metamask/design-system-react-native` to `0.8.0`, and
`@metamask/design-system-shared` to `0.2.0`.
> 
> Updates the React and React Native changelogs to document a
**breaking** `BadgeStatus` type migration (enums → const objects +
derived string unions), plus RN-only release notes for adding
`RadioButton` and a `BottomSheetFooter` location refactor; also updates
changelog compare links to start from the new versions.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
35569fb. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants