MetaMask / MetaMask/metamask-design-system

Refactor: Remove Tailwind class variable antipattern in React Native components

Open
#885 0 comments 0 reactions 0 assignees View on GitHub
team-design-system
Dominant language
TypeScript
Stars
37
Forks
14
Avg merge
1d 9h
Merged PRs (30d)
60

Description

### **Description**

Refactor React Native components to remove the Tailwind class variable antipattern. Some components store Tailwind classes in variables and use string interpolation, which breaks critical developer tooling (VSCode IntelliSense, ESLint validation, auto-fixing).

**The antipattern (breaks tooling):**
```tsx
const twContainerClassNames = 'flex-1 bg-default p-4';

```

**Accepted patterns:**

1. **Component props first (preferred):**
```tsx
// ✅ Best - Use Box component props when available

Content

```

2. **tw.style() for conditionals:**
```tsx
// ✅ Great for interactive states and prop-based styling

tw.style(
'flex-1 bg-default p-4',
pressed && 'bg-pressed',
)
}
>
Content

```

3. **Direct template literals (simple cases):**
```tsx
// ✅ Good for simple static styles on raw React Native components

Content

```

4. **twClassName prop (Box components):**
```tsx
// ✅ Good when Box props don't cover the style

Content

```

### **Technical Details**

**Why the antipattern breaks tooling:**
- ❌ VSCode Tailwind IntelliSense (bradlc.vscode-tailwindcss) cannot detect classes in variables
- ❌ ESLint tailwindcss plugin cannot lint or validate classes
- ❌ Tailwind class ordering cannot be auto-fixed

**Why ESLint linting is CRITICAL:**
- 🚨 ESLint `eslint-plugin-tailwindcss` is our **only type safety** for Tailwind classes in React Native
- There are no TypeScript types for twrnc class names (unlike component props)
- If the linter can't detect classes (like in variables), we lose all validation
- This means typos, invalid classes, and breaking changes can slip through undetected
- **Without linting, there is zero compile-time or runtime validation of Tailwind classes**

**Why accepted patterns work:**
- ✅ Autocomplete/IntelliSense works inside `tw.style('...')`, `tw\`...\``, and `twClassName="..."`
- ✅ Syntax highlighting for Tailwind classes
- ✅ **Validation and warnings for invalid classes (our only type safety!)**
- ✅ Class definitions on hover
- ✅ ESLint tailwindcss plugin validation
- ✅ Component props provide type safety and design token enforcement

**VSCode configuration:**

Location: `.vscode/settings.json`

The `tailwindCSS.classFunctions` setting tells the VSCode Tailwind CSS IntelliSense extension which functions contain Tailwind classes:

```json
"tailwindCSS.classFunctions": [
"tw", // tw`...` template literals
"tw`", // explicit template literal notation
"twClassName", // Box component twClassName prop
"twMerge", // utility function
"tw.style" // ✅ Added for conditional styling support (9ecbb849)
]
```

**Implementation approach:**
1. Search for pattern: `tw\`${variableName}\`` or similar string interpolation
2. Determine the best replacement pattern:
- **Prefer**: Box component props (backgroundColor, padding, etc.) - TypeScript validated
- **Use tw.style()**: For conditionals or interactive states - ESLint validated
- **Use tw\`...\`**: For simple static styles on raw components - ESLint validated
- **Use twClassName**: When Box props don't exist - ESLint validated
3. Extract variable contents and inline them using chosen pattern
4. Convert any conditionals to appropriate pattern
5. Test that IntelliSense and linting work

### **Acceptance Criteria**

- [x] VSCode configuration updated to support all patterns (commit 9ecbb849)
- [ ] All instances of Tailwind class variables with string interpolation identified
- [ ] Components refactored using appropriate pattern (props > tw.style() > tw\`\` > twClassName)
- [ ] VSCode Tailwind IntelliSense provides autocomplete in all refactored code
- [ ] **ESLint tailwindcss plugin validates all refactored code (critical for type safety)**
- [ ] All affected components still render correctly
- [ ] Storybook stories updated if affected

### **References**

- Documentation: `.cursor/rules/styling.md` (React Native patterns section)
- VSCode config: `.vscode/settings.json` (tailwindCSS.classFunctions)
- ESLint config: `.eslintrc.js` (eslint-plugin-tailwindcss rules)
- Related PR: #882 (styling.md cursor rule)
- VSCode config commit: 9ecbb849
- Example: `apps/storybook-react-native/stories/WalletHome.stories.tsx` (shows proper pattern usage)

Contributor guide

Open the contributing guide

Research direction

Start by searching the React Native components for tw template literals containing interpolated class variables, then compare affected code with apps/storybook-react-native/stories/WalletHome.stories.tsx and the patterns in .cursor/rules/styling.md. Check .vscode/settings.json and .eslintrc.js while refactoring, then run the relevant linting and Storybook checks; done means all instances use accepted patterns and affected stories still render correctly.

Written by the indexing model from the issue text.

Assessment

Tech stack
react-native, tailwindcss, typescript
Domain
frontend, mobile
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.