This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is the FluentUI React Native repository, a monorepo containing React Native components that implement Microsoft's Fluent Design System. The repository supports multiple platforms including iOS, Android, macOS, Windows, and Win32.
/apps/ - Demo and test applications
/fluent-tester/ - Main test app for component development
/E2E/ - End-to-end testing setup using Appium/WebDriverIO
/win32/ - Win32-specific test app
/component-generator/ - Tool to generate new components
/packages/ - Core library packages
/components/ - UI component implementations (Button, Checkbox, Avatar, etc.)
/framework/ - Core theming and composition framework
/composition/ - Component composition factory (current approach)
/theme/ - Theme system
/use-tokens/ - Token-based styling hooks
/use-slots/ - Slot-based component composition
/theming/ - Theme definitions for different platforms
/android-theme/
/apple-theme/
/default-theme/
/win32-theme/
/experimental/ - Components under active development
/deprecated/ - Old framework code (foundation-compose, foundation-composable)
/utils/ - Shared utilities and tools
/scripts/ - Build and development scripts (fluentui-scripts CLI)
/docs/ - Component and theming documentation
Composition Framework: The repository uses @fluentui-react-native/composition (located at packages/framework/composition/) for building components. This is the current approach and is simpler than the older foundation-compose/foundation-composable frameworks in /deprecated/.
Slots: The slot pattern is used to compose higher-order components. A slot represents an inner component (actual entry in the render tree). For example, a Button might have slots for root, icon, and content. This allows advanced customization scenarios. Components wrapping a single native component typically have one slot.
Tokens: Design tokens handle styling and customization. Tokens are design-time values set via theme or component customization (e.g., "brandColor"). Tokens can also be props (specified via "TokensThatAreAlsoProps"). This system enables simpler customization and better memoization.
Platform-Specific Files: Components use platform-specific files with extensions like .ios.ts, .android.ts, .win32.ts, .macos.ts for platform-specific implementations.
Legacy vs V1: Many components have both legacy and V1 implementations (e.g., Button and ButtonV1). The V1 versions use the newer composition framework and are preferred.
The project uses Yarn 4 (Berry) in pnpm mode with Lage as the task runner for orchestrating builds across the monorepo. The pnpm mode provides better disk space efficiency and stricter dependency management.
yarn build # TypeScript build for all packages (outputs to lib/ and lib-commonjs/)
yarn test # Build, lint, and run tests across all packages
yarn lint # ESLint across all packages
yarn bundle # Bundle all packages
yarn buildci # Full CI pipeline: build + test + lint + bundle + depcheck + check-publishing
yarn clean # Clean build artifactsyarn format # Format code with oxfmt
yarn depcheck # Check for unused dependencies across packages
yarn depcheck-fix # Fix depcheck issues automatically
yarn align-deps # Align React Native dependencies using @rnx-kit/align-deps
yarn changeset # Generate changeset files (required before PR merge)The build pipeline is defined in lage.config.js:
- Tasks have dependency ordering (e.g.,
testdepends onbuild) - Lage uses caching to avoid redundant steps
- Add
--no-cacheto bypass caching - Add
--verbosefor detailed output
Individual packages use fluentui-scripts (in /scripts/) which provides:
yarn build- TypeScript compilation tolib/(ESM) andlib-commonjs/(CJS)- The build script automatically sets
--moduleResolutionto match--modulefor TypeScript 5.8+ compatibility - ESM builds use
--module esnext --moduleResolution bundler - CJS builds use
--module node16 --moduleResolution node16
- The build script automatically sets
yarn lint- ESLintyarn lint-package- Lint package configuration (includes align-deps and depcheck)- Use
--fixflag to automatically fix issues - Validates dependencies, scripts, entry points, and build configuration
- Use
yarn test- Jest tests (where applicable)yarn depcheck- Check for unused dependenciesyarn format- Check code formattingyarn format:fix- Fix code formatting
The repository uses TypeScript 5.8+ with @typescript/native-preview for improved performance and React Native compatibility. The native preview is automatically added to packages with a tsconfig.json via dynamic package extensions.
- Base configuration in
/scripts/configs/tsconfig.json - Module system:
node16with matchingmoduleResolution: node16 - Target:
es2022 - Strict mode enabled (with some exceptions for legacy code compatibility)
- TypeScript Native Preview: Packages automatically receive
@typescript/native-previewas a development dependency
- The
suppressImplicitAnyIndexErrorsoption has been removed (deprecated in TS 5.8+) - Module resolution must match module format when using Node16 resolution
- Stricter type checking for platform values (e.g.,
Platform.OSdoesn't include 'win32' in React Native types, but react-native-windows does support it at runtime) - TypeScript native preview provides better performance for large React Native codebases
The composition framework uses precise types for better type safety:
SlotFn<TProps>: Slot functions returnReact.ReactElement | null(notReactNode)- This reflects the actual behavior: slots always return elements via staged render or
React.createElement - Provides better type inference when accessing slot props (e.g.,
Slots.root({}).props)
- This reflects the actual behavior: slots always return elements via staged render or
FinalRender<TProps>: Final render functions in staged components returnJSX.Element | null- Used in composition framework's
useRenderfunctions - Ensures type compatibility between staged components and the composition system
- Used in composition framework's
- Clone repository
- Run
yarnto install dependencies - Run
yarn buildto build all packages - Launch FluentUI Tester app for component testing (see
/apps/fluent-tester/README.md)
Component Location: Components are in /packages/components/ (stable) or /packages/experimental/ (under development).
Component Structure: Each component typically has:
package.json- Package definition with workspace dependenciessrc/index.ts- Main export filesrc/<Component>.tsx- Component implementation (requires/** @jsxImportSource @fluentui-react-native/framework-base */pragma)src/<Component>.types.ts- TypeScript type definitionssrc/<Component>.styling.ts- Styling and token definitionssrc/<Component>.<platform>.ts- Platform-specific implementationsSPEC.md- Component specification and usage documentationMIGRATION.md- Migration guide (for V1 components)tsconfig.json,babel.config.js,jest.config.js,eslint.config.js
Using Composition Framework: Use @fluentui-react-native/composition for new components. For simpler components without slots/tokens, use the stagedComponent pattern from @fluentui-react-native/use-slot.
JSX Runtime: All components use the modern automatic JSX runtime:
- Add
/** @jsxImportSource @fluentui-react-native/framework-base */at the top of.tsxfiles - The custom jsx-runtime intercepts JSX calls to optimize slot rendering
- No need to import
withSlots- it's handled automatically by the runtime - Components using React Fragments (
<>...</>) work automatically (Fragment is re-exported from the jsx-runtime) - Packages using the jsx-runtime need
@fluentui-react-native/framework-baseindevDependencies
TypeScript Patterns:
- Slot functions automatically return
React.ReactElement, so you can access.propsdirectly without type assertions - When checking for win32 platform:
Platform.OS === ('win32' as any)- TypeScript doesn't recognize 'win32' but react-native-windows supports it - Final render functions should return
FinalRender<TProps>with children as rest parameters:(props: TProps, ...children: React.ReactNode[])
Native Modules: Components with native code (iOS/Android/Windows):
- Typically have one root slot wrapping the native component
- Use
codegenNativeComponentfor new architecture compatibility - May use
constantsToExportfor default values from native side - iOS/macOS: Include
.podspecfiles - Must be added to FluentTester's Podfile (transitive dependencies aren't autolinked)
- Create directory:
/packages/components/<ComponentName>or/packages/experimental/<ComponentName> - Copy structure from existing component (e.g., Shimmer, Button)
- Update
package.jsonwith correct name and dependencies (useworkspace:*for internal packages) - Create source files in
src/ - Add test page to FluentTester at
/apps/fluent-tester/src/TestComponents/<ComponentName>/ - Register test page in
testPages.tsxand platform-specifictestPages.<platform>.tsx - Add E2E tests (see E2E Testing section)
- Run
yarnandyarn buildfrom root - For Apple platforms: run
pod installin test app directories
Platform-specific themes are in /packages/theming/:
android-theme/- Android themingapple-theme/- iOS and macOS themingwin32-theme/- Win32 themingdefault-theme/- Cross-platform defaultstheme-tokens/- Token definitionstheme-types/- TypeScript types for themes
Components require ThemeProvider from @fluentui-react-native/theme to work properly.
Manual Testing: Use FluentUI Tester app (/apps/fluent-tester/) for interactive component testing. Test pages are in /apps/fluent-tester/src/TestComponents/.
E2E Testing: Required for all new components. Uses Appium + WebDriverIO.
- E2E tests live in
/apps/E2E/src/<ComponentName>/ - Each component needs:
- Page Object (
<Component>PageObject.<platform>.ts) - Interface to interact with test page - Spec Document (
<Component>Spec.<platform>.ts) - Jasmine test cases - Constants file in test component (
/apps/fluent-tester/src/TestComponents/<Component>/consts.ts)
- Page Object (
- Test pages must include:
testIDon first section matching page object's_pageName- Optional
e2eSectionsprop for dedicated E2E test elements
- Run E2E tests:
yarn e2etest:<platform>from/apps/E2E/
Unit Tests: Component-specific Jest tests where present, typically in src/ directories.
iOS/macOS:
- May wrap native controls from FluentUI Apple
- Requires
.podspecfiles for native modules - Run
pod installafter adding dependencies
Android:
- Platform-specific styling and tokens
- Uses
accessibilityLabelfor E2E selectors (other platforms usetestID)
Win32:
- Separate test app at
/apps/win32/ - Uses WinAppDriver for E2E testing
Windows (UWP):
- Separate test app configuration
- Legacy support
Changesets: Used for change logs and versioning.
- Run
yarn changesetto create changeset files when modifying packages - Changesets are required before merging PRs (validated in CI)
- Changesets config in
.changeset/config.json - Major versions are disallowed (validated in CI via
.github/scripts/validate-changesets.mts) - Version bump PRs are created automatically by GitHub Actions
- Publishing happens in Azure Pipelines using
changeset publish
- This is an alpha-stage library under active development
- Requires TypeScript 5.8+ with
@typescript/native-previewfor proper type checking and module resolution - Uses Yarn 4 in pnpm mode for dependency management (configured in
.yarnrc.yml) - Uses modern automatic JSX runtime - all components should use
@jsxImportSource @fluentui-react-native/framework-base - Dynamic package extensions: Common dev dependencies (TypeScript, Jest, ESLint, Prettier) are automatically added via
scripts/dynamic.extensions.mjs - Integrated linting:
yarn lint-packagenow includes align-deps and depcheck validation - Follow existing component patterns for consistency
- Test components using FluentUI Tester app before submitting PRs
- Platform differences should be documented in component
SPEC.mdfiles - Use the newer composition framework (
@fluentui-react-native/composition) for new components, not the deprecated foundation frameworks - When importing V1 components, consider aliasing:
import { ButtonV1 as Button } - Slot functions return
React.ReactElement- you can safely access.propswithout type assertions