Conversation
Bump react-native and the @react-native/* presets to 0.86.0. React stays at 19.2.3 and there are no native template changes between 0.85.3 and 0.86.0. Bump react-native-reanimated to 4.4.1 and react-native-worklets to 0.9.2 for RN 0.86 support. In the example, bump react-native-gesture-handler to 2.32.0 (RN 0.86 removed the legacy renderer shim that 2.31.x imported) and align the Expo SDK 56 packages to their latest patch versions.
reanimated 4.x and worklets ship "type": "module" builds with extensionless relative imports, which webpack 5 rejects under its fully-specified ESM rule and breaks the docs build. Disable fullySpecified for just those two packages so their .web.js variants resolve.
stateLayerPressed pre-baked onSurface at the pressed opacity because PlatformColor can't be alpha-manipulated in JS. RN 0.86's android_ripple alpha makes that workaround unnecessary, so the field is dropped from the theme. TouchableRipple now defaults its ripple to onSurface and applies the opacity separately.
Replace the rippleAlpha prop with the MD3 pressed opacity applied automatically, so the public API is just an opaque rippleColor plus the raw background escape hatch. - Extract a shared TouchableRippleCommonProps type so web and native expose one API, and type background as PressableAndroidRippleConfig instead of Object. - Multiply the opacity into the color's own alpha (matching Android's android_ripple.alpha) so a transparent rippleColor stays invisible on web; fill the pressed opacity into a custom background only when it doesn't set its own alpha.
Add a stateLayer role to each FAB variant (the container's on-color) and resolve it following the container, ignoring a contentColor override. Shell passes it as rippleColor so the pressed and hover state layers match the variant instead of always using onSurface.
JKobrynski
force-pushed
the
@adrcotfas/chore_rn86
branch
from
August 24, 2026 12:31
fd30f65 to
cee50c6
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Four unresolved moderate findings affect ripple contrast, compatibility, and custom underlay behavior.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Updates MD3 ripple opacity handling with android_ripple.alpha, removes the precomputed theme token, and adds variant-aware FAB state layers.
Changes:
- Applies pressed/hover opacity in native and web ripples.
- Adds FAB variant state-layer roles.
- Updates ripple types, dependencies, tests, and tooling configuration.
Review findings:
- Moderate (3 votes):
FAB.Menumorphing triggers can use the wrong close-state ripple color. - Moderate (3 votes): FAB menu items do not receive the resolved variant state layer.
- Moderate (2 votes): Older React Native versions lack an opacity fallback while the peer requirement remains unrestricted.
- Moderate (1 vote): Explicit
underlayColorvalues now receive unintended opacity.
File summaries
| File | Description |
|---|---|
yarn.lock |
Locks updated dependencies. |
src/theme/types/color.ts |
Removes stateLayerPressed. |
src/theme/tokens/sys/color.ts |
Stops precomputing the state-layer color. |
src/components/TouchableRipple/utils.ts |
Defaults ripple colors to opaque onSurface. |
src/components/TouchableRipple/types.ts |
Adds shared typed ripple props. |
src/components/TouchableRipple/TouchableRipple.tsx |
Applies web opacity handling. |
src/components/TouchableRipple/TouchableRipple.native.tsx |
Configures native ripple alpha. |
src/components/FAB/utils.ts |
Resolves FAB state-layer colors. |
src/components/FAB/tokens.ts |
Adds variant-specific state-layer roles. |
src/components/FAB/Shell.tsx |
Passes state-layer colors to ripples. |
src/components/__tests__/TouchableRipple.test.tsx |
Tests ripple opacity and configuration. |
src/components/__tests__/FABUtils.test.tsx |
Tests state-layer resolution. |
src/components/__tests__/__snapshots__/ListSection.test.tsx.snap |
Updates theme snapshots. |
package.json |
Updates React Native dependencies. |
example/package.json |
Updates example dependencies. |
docs/plugins/docusaurus-react-native-plugin.js |
Adjusts webpack dependency resolution. |
Review details
Suppressed comments (1)
src/components/TouchableRipple/TouchableRipple.native.tsx:107
- This applies the 0.1 opacity to explicit
underlayColorvalues too. Previously a custom underlay was rendered directly, sounderlayColor="purple"now becomes a 10%-opacity layer even though this separate override is documented as the underlay color. Apply the opacity only to the default underlay, or explicitly document this breaking behavior.
opacity: state.opacity.pressed,
- Files reviewed: 15/16 changed files
- Comments generated: 3
- Review effort level: Lite (auto)
Note
Copilot is running an experiment and ran this review at Lite.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| <TouchableRipple | ||
| borderless | ||
| background={background} | ||
| rippleColor={colors.stateLayer} |
| export type ResolvedColors = { | ||
| container: ColorValue; | ||
| content: ColorValue; | ||
| stateLayer: ColorValue; |
| color: calculatedRippleColor, | ||
| borderless, | ||
| foreground: useForeground, | ||
| alpha: state.opacity.pressed, |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
MD3 interaction state layers are an opaque color drawn at a fixed opacity (0.1 pressed, 0.08 hover). Previously the theme shipped a pre-baked
stateLayerPressedcolor (onSurfaceat 0.1 alpha) becausePlatformColorcan't be alpha-manipulated in JS, so the opacity had to be baked into the token ahead of time.React Native 0.86's
android_ripple.alpha(react/react-native#56395) removes that limitation: the alpha can now be applied at draw time, even over aPlatformColor. This lets us drop the pre-baked theme color and giveTouchableRippleownership of the state-layer opacity, so any component can pass its own opaque state-layer color and get the correct pressed/hover opacity for free.This PR does that in three steps:
stateLayerPressedfrom the theme.TouchableRipplenow defaults its ripple toonSurfaceand applies the pressed opacity itself, so the workaround color is no longer needed.TouchableRippleAPI. The ripple color is treated as opaque and the MD3 pressed opacity is applied automatically (multiplied into the color's own alpha, matchingandroid_ripple.alpha), so atransparentripple color stays invisible on web too. The public surface is justrippleColorplus the rawbackgroundescape hatch. Web and native now share oneTouchableRippleCommonPropstype, andbackgroundis typed asPressableAndroidRippleConfiginstead ofObject.stateLayerrole (the container's on-color), resolved following the container and ignoring acontentColoroverride, and passed toTouchableRippleasrippleColor. The pressed/hover state layer now matches the variant (e.g. primary → onPrimary, tonalPrimary → onPrimaryContainer) instead of always usingonSurface.Test plan
lint, typescript and tests pass
Postponed until #4996 is merged