Skip to content

feat: FormTextField migration#1197

Merged
kirillzyusko merged 4 commits into
mainfrom
feat/form-text-field-migration
Jun 3, 2026
Merged

feat: FormTextField migration#1197
kirillzyusko merged 4 commits into
mainfrom
feat/form-text-field-migration

Conversation

@kirillzyusko

@kirillzyusko kirillzyusko commented Jun 1, 2026

Copy link
Copy Markdown
Collaborator

Description

Added FormTextField component to DSR.

Related issues

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

Manual testing steps

  1. Open storybook
  2. Check new component

Screenshots/Recordings

Before

After

Screen.Recording.2026-06-01.at.14.11.12.mov

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
New UI primitive with tests and migration guidance; no auth, data, or runtime behavior changes outside the design-system package.

Overview
Adds FormTextField to @metamask/design-system-react as a labeled form control built from Label, TextField, and optional HelpText, with isError driving danger styling and aria-invalid on the input.

The API uses isDisabled / isReadOnly / isError, TextFieldSize (no separate FormTextFieldSize), a fixed column root via Box, and discriminated types so id is required when label is set. labelProps, helpTextProps, and textFieldProps forward extras; root ref vs inputRef match TextField. MIGRATION.md documents extension → design-system moves (imports, prop renames, removed polymorphic/defaultValue behavior).

Ships unit tests, Storybook stories/README, and a public export from the package index.

Reviewed by Cursor Bugbot for commit f21ecdd. Bugbot is set up for automated code reviews on this repo. Configure here.

@kirillzyusko kirillzyusko self-assigned this Jun 1, 2026
@kirillzyusko kirillzyusko added the documentation Improvements or additions to documentation label Jun 1, 2026
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@kirillzyusko kirillzyusko marked this pull request as ready for review June 1, 2026 11:10
@kirillzyusko kirillzyusko requested a review from a team as a code owner June 1, 2026 11:10
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

Comment thread packages/design-system-react/src/components/FormTextField/FormTextField.tsx Outdated
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@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.

Solid implementation 🔥 the discriminated union enforcing id when label is present is a nice accessibility touch, FormTextFieldInnerTextFieldProps preventing textFieldProps duplication is well thought through, and the migration docs are thorough. Approved with option to merge and create follow-up PRs or address in this one up to you.

import type { FormTextFieldProps } from './FormTextField.types';
import README from './README.mdx';

function ControlledFormTextField(props: FormTextFieldProps) {

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.

non-blocking: Same feedback as the TextFieldSearch PR — the Default story already manages state inline correctly, worth extending that pattern to Label, HelpText, IsError, IsDisabled, and Size instead of routing through ControlledFormTextField. Each story should show exactly what a consumer would copy-paste.

label="Amount"
value="Read-only value"
/>
),

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.

non-blocking: Layout wrapper here could be a Box instead of a raw <div> per the styling conventions.

);

const root = screen.getByTestId(ROOT_TEST_ID);
const fieldContainer = root.querySelector('.inline-flex');

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.

suggestion: .querySelector('.inline-flex') and the h-12 assertion test TextField's internal implementation rather than FormTextField's contract. The size forwarding is already covered by TextField's own tests — removing this test or replacing the selector with a data-testid on the TextField root would make it less brittle. The same applies to the textFieldProps.className test at line 157.


type Story = StoryObj<FormTextFieldProps>;

export const Default: Story = {

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.

non-blocking: The Default story (label="Amount", no helpText) and the README quick-start example (label="Email", helpText="We never share your email.") are out of sync with each other. The README code block should be the Default story verbatim. Worth aligning both to a single representative example that includes helpText — the extension's default story shows label + placeholder + help text together and is a good reference: https://metamask.github.io/metamask-storybook/?path=/docs/components-componentlibrary-formtextfield--docs (will attach screenshot).

@kirillzyusko kirillzyusko enabled auto-merge (squash) June 3, 2026 07:48
@github-actions

github-actions Bot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

📖 Storybook Preview

@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.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f21ecdd. Configure here.

className={className}
style={style}
{...rest}
>

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.

Top-level onClick not forwarded

Medium Severity

FormTextField inherits onClick from TextFieldProps but does not destructure or pass it to the inner TextField. It remains in ...rest and is applied to the root Box, so clicks on the label or help text invoke the handler, and clicks on a disabled field can still fire it because TextField’s disabled guard never runs.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit f21ecdd. Configure here.

@kirillzyusko kirillzyusko merged commit 1d6427a into main Jun 3, 2026
36 checks passed
@kirillzyusko kirillzyusko deleted the feat/form-text-field-migration branch June 3, 2026 07:52
@georgewrmarshall georgewrmarshall mentioned this pull request Jun 4, 2026
18 tasks
georgewrmarshall added a commit that referenced this pull request Jun 4, 2026
## Release 43.0.0

This release drops Node.js 18 support across the release line, adds
several new components, and includes a small set of breaking API changes
that are documented in the migration guides.

### 📦 Package Versions

- `@metamask/design-system-shared`: **0.21.0**
- `@metamask/design-system-react`: **0.25.0**
- `@metamask/design-system-react-native`: **0.28.0**
- `@metamask/design-tokens`: **8.5.0**
- `@metamask/design-system-tailwind-preset`: **0.9.0**
- `@metamask/design-system-twrnc-preset`: **0.5.0**

### 🔄 Shared Type Updates (0.21.0)

#### Added

- Added `ContentPropsShared` and `ContentVerticalAlignment` for React
Native list-style rows and related layout patterns
([#1192](#1192))

#### Changed

- **BREAKING:** Dropped Node.js 18 support for the release line;
consumers must run Node 20 or newer
([#1206](#1206))
- **BREAKING:** Updated `TextAreaPropsShared` to remove `inputElement`
so React Native `TextArea` can render the root `TextInput` directly
([#1205](#1205))

### 🌐 React Web Updates (0.25.0)

#### Added

- Added `Popover` for anchored overlays such as menus, tooltips, and
dialogs
([#1153](#1153))
- Added `TextArea` for controlled multiline text entry
([#1036](#1036))
- Added `TextFieldSearch` for controlled search-field flows on top of
`TextField`
([#1171](#1171))
- Added `FormTextField` for labeled form controls built from `Label`,
`TextField`, and `HelpText`
([#1197](#1197))

#### Changed

- **BREAKING:** Dropped Node.js 18 support for the release line;
consumers must run Node 20 or newer
([#1206](#1206))
- Updated avatar fallback handling so `AvatarToken`, `AvatarNetwork`,
and `AvatarFavicon` resolve consistently when the requested image is
unavailable
([#1212](#1212))

### 📱 React Native Updates (0.28.0)

#### Added

- Added `Content` for composing scrollable and padded content sections
on React Native screens; it is closely related to the upcoming
`ListItem` work
([#1192](#1192))

#### Changed

- **BREAKING:** Dropped Node.js 18 support for the release line;
consumers must run Node 20 or newer
([#1206](#1206))
- Added default padding and `isInteractive` support to `SectionHeader`
so section rows match the new mobile layout patterns
([#1210](#1210))
- **BREAKING:** Flattened `TextArea` so it renders the root `TextInput`
directly; pass `TextInput` props on `TextArea`, use the component `ref`
for the input, and stop relying on `inputProps` or `inputElement`
([#1205](#1205))
- Updated avatar fallback handling so `AvatarToken`, `AvatarNetwork`,
and `AvatarFavicon` resolve consistently when the requested image is
unavailable
([#1212](#1212))

### ⚠️ Breaking Changes

#### Node.js 18 support removed

**What Changed:**

- The release line now requires Node 20 or newer.
- This applies across the monorepo, including the shared package, web
package, React Native package, tokens, and both preset packages.

**Impact:**

- Consumers still on Node 18 must upgrade their runtime before
installing or developing against this release line.
- Node 18 is end-of-life, so this change aligns the repo with the
supported app runtimes.

#### React Native `TextArea` flattening

**What Changed:**

- `TextArea` now renders the root `TextInput` directly.
- `inputProps` and `inputElement` are removed.
- `inputRef` is replaced by the component `ref`.

**Migration:**

```tsx
// Before (0.27.0)
<TextArea
  inputProps={{ placeholder: 'Message' }}
  inputElement={<CustomInput />}
/>

// After (0.28.0)
<TextArea placeholder="Message" ref={inputRef} />
```

**Impact:**

- Affects React Native consumers using `TextArea`.
- Call sites that depended on the wrapper/input split need to be
updated.

See migration guides for complete instructions:

- [React Migration
Guide](./packages/design-system-react/MIGRATION.md#from-version-0220-to-0230)
- [React Native Migration
Guide](./packages/design-system-react-native/MIGRATION.md#from-version-0270-to-0280)

### ✅ Checklist

- [x] Changelogs updated with human-readable descriptions
- [x] Changelog validation passed (`yarn changelog:validate`)
- [x] Version bumps follow semantic versioning
- [x] design-system-shared: minor (0.20.0 → 0.21.0) - shared type
additions and breaking TextArea/shared runtime baseline
- [x] design-system-react: minor (0.24.0 → 0.25.0) - new components and
release-line update
- [x] design-system-react-native: minor (0.27.0 → 0.28.0) - new
component, SectionHeader update, and breaking TextArea change
- [x] Breaking changes documented with migration guidance
- [x] Migration guides updated with before/after examples (if breaking
changes)
- [x] PR references included in changelog entries

## **Pre-merge author checklist**

- [x] I've followed [MetaMask Contributor
Docs](https://github.com/MetaMask/contributor-docs)
- [x] I've reviewed the [Release
Workflow](./.cursor/rules/release-workflow.md) cursor rule
- [ ] All tests pass (`yarn build && yarn test && yarn lint`)
- [x] Changelog validation passes (`yarn changelog:validate`)

## **Pre-merge reviewer checklist**

- [x] I've reviewed the [Reviewing Release
PRs](./docs/reviewing-release-prs.md) guide
- [x] Package versions follow semantic versioning
- [x] Changelog entries are consumer-facing (not commit message
regurgitation)
- [x] Breaking changes are documented in MIGRATION.md with examples
- [x] All unreleased changes are accounted for in changelogs

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Breaking React Native TextArea and Node 18 removal affect consumer
upgrades; most diff is release metadata with coordinated peer dependency
bumps.
> 
> **Overview**
> **Release 43.0.0** bumps the monorepo root to **43.0.0** and publishes
coordinated semver bumps across design-system packages, with
**yarn.lock** peer ranges updated for
`@metamask/design-system-tailwind-preset` **^0.9.0** and
`@metamask/design-system-twrnc-preset` **^0.5.0**.
> 
> Across the release line, changelogs record **Node.js 18 dropped**
(Node **20+** required). **@metamask/design-system-react** **0.25.0**
documents new **`Popover`**, **`TextArea`**, **`TextFieldSearch`**, and
**`FormTextField`**, plus avatar fallback fixes.
**@metamask/design-system-react-native** **0.28.0** adds **`Content`**,
updates **`SectionHeader`** (default padding, **`isInteractive`**), and
includes a **breaking** **`TextArea`** flattening (`inputProps` /
`inputElement` / `inputRef` removed; props and **`ref`** target the root
**`TextInput`**). **@metamask/design-system-shared** **0.21.0** adds
**`ContentPropsShared`** / **`ContentVerticalAlignment`** and removes
**`inputElement`** from shared **`TextArea`** props.
> 
> Migration guide edits in this diff: React Native **0.27.0 → 0.28.0**
**`TextArea`** guidance; React version heading **0.22.0 → 0.23.0** for
**`BannerBase`** (changelog-driven **0.25.0** items are not new
migration sections here).
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
23b0cda. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants