dev.cds-mobile
$
npx mdskill add coinbase/cds/dev.cds-mobile<!-- TODO: nested AGENTS.md files should work but they seem a little flaky at the moment. Intelligent mdc files are working better -->
SKILL.md
.github/skills/dev.cds-mobileView on GitHub ↗
---
name: dev.cds-mobile
description: USE THIS when asked to work on a new or existing (MOBILE) CDS React component in packages/mobile
---
<!-- TODO: nested AGENTS.md files should work but they seem a little flaky at the moment. Intelligent mdc files are working better -->
# CDS Mobile Package Guidelines
Mobile-specific patterns for `@coinbase/cds-mobile`.
## Component Config Adoption (Mobile)
Use this guidance when adding `ComponentConfigProvider` defaults for the specific component you are editing.
### Required implementation pattern
1. Register the component in `packages/mobile/src/core/componentConfig.ts` using its `*BaseProps`:
```ts
import type { MyComponentBaseProps } from '../category/MyComponent';
export type ComponentConfig = {
MyComponent?: ConfigResolver<MyComponentBaseProps>;
};
```
1. Adopt `useComponentConfig` in the component and destructure from merged props:
```tsx
import { useComponentConfig } from '../hooks/useComponentConfig';
export const MyComponent = memo((_props: MyComponentProps) => {
const mergedProps = useComponentConfig('MyComponent', _props);
const { style, ...props } = mergedProps;
return <Pressable style={style} {...props} />;
});
```
### Rules to preserve behavior
- Provider config supplies defaults only; local props must continue to win.
- Use `_props` as the input variable and `mergedProps` as the configured output.
- Type resolver entries with `*BaseProps` (not full `*Props`).
- Keep scope to prop-level theming defaults; do not alter component behavior or control flow.
- When practical during the same change, prefer arrow-function component declarations.
## Styling with StyleSheet
Use `StyleSheet.create` for static styles and `useTheme()` for dynamic values:
```tsx
import { StyleSheet, type StyleProp, type ViewStyle } from 'react-native';
const styles = StyleSheet.create({
container: { position: 'relative', width: '100%' },
});
// Dynamic styles via theme hook
const theme = useTheme();
const dynamicStyle = {
backgroundColor: theme.color.bgPrimary,
padding: theme.space[2],
};
<View style={[styles.container, dynamicStyle, style]} />;
```
### Inline styles
- Mobile components should all expose a `style` and `styles` object props for overriding default styles.
- As styling is a concern of that specific component, the `style` and `styles` props should never be on the `*BaseProps` type.
- `styles` can be used for granular overrides on child elements within the component.
- **Always** merge styles into a react-native style array with `useMemo` in the correct order (default styles => `style` prop => `styles[ELEMENT_NAME]` prop).
**Example:**
```tsx
type ComponentProps = ComponentBaseProps & {
style?: StyleProp<ViewStyle>;
styles?: {
root?: StyleProp<ViewStyle>;
label?: StyleProp<TextStyle>;
};
};
const theme = useTheme();
const containerStyles = useMemo(
() => [
{ backgroundColor: theme.color.bgPrimary }, // default styles
style, // from props
styles.root, // from props
],
[theme.color.bgPrimary, animatedStyles, style]
);
// Apply to component
<Box style={containerStyles}>
```
## Animation
### React Native Reanimated
```tsx
import Animated, { useAnimatedStyle, useSharedValue, withTiming } from 'react-native-reanimated';
const opacity = useSharedValue(0);
const animatedStyle = useAnimatedStyle(() => ({
opacity: opacity.value,
transform: [{ translateY: withTiming(opacity.value * -8) }],
}));
<Animated.View style={animatedStyle} />;
```
We DO NOT use React-Spring anymore for animations on mobile.
## Gesture Handling
Use `react-native-gesture-handler`:
```tsx
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
const panGesture = useMemo(
() =>
Gesture.Pan()
.onStart(() => {
/* ... */
})
.onUpdate(({ translationX }) => {
/* ... */
})
.onEnd(({ translationX, velocityX }) => {
/* ... */
})
.withTestId(testID)
.runOnJS(true),
[dependencies],
);
<GestureDetector gesture={panGesture}>
<Animated.View>{/* ... */}</Animated.View>
</GestureDetector>;
```
## Layout Measurement
Use `onLayout` callback instead of ResizeObserver:
```tsx
const [size, onLayout] = useLayout();
<View onLayout={onLayout} />
// Or inline
<View onLayout={(e) => setHeight(e.nativeEvent.layout.height)} />
```
## Accessibility
- Use appropriate accessibilityLabel, accessibilityHint, and accessibilityRole, accessibilityState props
- Support screen readers (VoiceOver and TalkBack)
- Ensure touch targets meet minimum size requirements (44x44 points)
**Example:** Use React Native accessibility props:
```tsx
<View
accessible
accessibilityRole="adjustable"
accessibilityLabel="Product carousel"
accessibilityLiveRegion="polite"
>
<Pressable
accessibilityState={{ selected: isActive, disabled }}
accessibilityActions={[{ name: 'activate' }]}
onAccessibilityAction={handleAccessibilityAction}
/>
</View>
```
### Screen Reader Content
```tsx
// Hide visual content from screen readers
<View accessibilityElementsHidden importantForAccessibility="no-hide-descendants">
{/* Animated/visual content */}
</View>
// Provide accessible alternative
<Text
importantForAccessibility="yes"
accessibilityLiveRegion="polite"
style={{ color: 'transparent', position: 'absolute' }}
>
{accessibleLabel}
</Text>
```
## Reference Components
- **SlideButton**: gesture handling, spring animations, accessibility actions
- **RollingNumber**: Reanimated, measurement patterns, screen reader content
- **Select** (alpha/): controlled/uncontrolled, Drawer integration
- **Stepper**: direction-based defaults, shared logic from cds-common
- **Tour**: animations, complexity
- **DatePicker**: complexity
More from coinbase/cds
- cds-accessibility|
- cds-code|
- cds-design-to-code|
- cds-docs|
- cds-migrator-transform|
- components.best-practicesUse this skill whenever working on CDS React components in any package.
- components.stylesGuidelines writing styles API (styles, classNames, and static classNames) for a CDS component. Use this skill when adding customization options to a React component via `styles` or `classNames` props or when needing to update the docsite with component styles documentation.
- components.write-docsGuidelines for creating or updating documentation for a CDS component on the docsite (apps/docs/). Use this skill after creating or making updates to a CDS React component to write high quality documentaiton in the CDS docsite.
- deprecate-cds-api|
- dev.cds-webUSE THIS when asked to work on a new or existing (WEB) CDS React component in packages/web