Skip to main content

Contributing

Contributions are always welcome, no matter how large or small. This page will walk you through the development workflow. Before contributing, please read the code of conduct.

Development workflow

The project is a monorepo managed with Yarn workspaces. It contains four packages:

  • the library package, in the root directory;
  • a native example app, in apps/example/;
  • a web example app, in apps/example-web/;
  • this documentation site, in docs/ (a standalone project with its own dependencies - see Documentation).

Install dependencies for the monorepo workspaces by running yarn in the root directory:

yarn

The native example app demonstrates the library on iOS and Android and is how you test any changes you make there. The web example app does the same for the web. Both are configured to use the local version of the library, so your source changes are reflected there:

  • JavaScript changes show up without a rebuild.
  • Native changes (Objective-C, Swift, Java, Kotlin) require rebuilding the native example app.

The web example is a Vite + React app; changes to the library's web source are hot-reloaded by its dev server.

Editing native code

To edit the native code in an IDE:

  • iOS - run yarn xcode to open apps/example/ios/EnrichedTextInputExample.xcworkspace in Xcode. Find the sources under Pods > Development Pods > ReactNativeEnrichedHtml.
  • Android - run yarn android-studio to open apps/example/android in Android Studio. Find the sources under react-native-enriched-html in the Android view.

Running the native example app

Start the Metro bundler:

yarn example start

Run the app:

# Android
yarn example android

# iOS
yarn example ios
iOS

Before running the app for the first time - or after updating native dependencies - install CocoaPods dependencies:

cd apps/example/ios
pod install

Running the web example app

Start the Vite dev server:

yarn example-web dev

The app is then served at http://localhost:5173.

Linting, types, and tests

Make sure your code passes TypeScript and ESLint:

yarn typecheck
yarn lint

Fix formatting errors automatically:

yarn lint --fix

Add tests for your change where possible, and run the unit tests:

yarn test

The project uses TypeScript for type checking, ESLint with Prettier for linting and formatting, and Jest for testing.

note

Pre-commit hooks verify that the linter and typecheck pass when you commit.

End-to-end tests

Mobile (Maestro)

We use Maestro for mobile end-to-end testing. Flows live in .maestro/enrichedInput/flows/ and .maestro/enrichedText/flows/. Shared subflows live in .maestro/subflows/, with component-specific subflows in .maestro/enrichedInput/subflows/ and .maestro/enrichedText/subflows/.

Prerequisites:

  • Maestro CLI (v2.3.0+) - follow the Getting Started guide, then ensure ~/.maestro/bin is in your PATH.
  • iOS - Xcode, with xcrun available (it ships with the Xcode Command Line Tools).
  • Android - the Android SDK with SDK Command-line Tools, Platform-Tools, and Emulator. Set ANDROID_HOME (typically $HOME/Library/Android/sdk on macOS) and add these to your PATH:
    • $ANDROID_HOME/cmdline-tools/latest/bin
    • $ANDROID_HOME/platform-tools
    • $ANDROID_HOME/emulator

You must run tests on exactly these devices - do not substitute other simulators or emulators. The suite includes visual regression tests that compare screenshots against saved baselines, so using the same screen dimensions and resolution is crucial.

PlatformDeviceOS
iOSiPhone 17iOS 26.2
AndroidPixel 9API 36 "Baklava" (Android 16)

Running the tests - start the Metro bundler first, then run a suite. Each command sets up the device and runs all Maestro flows, building only when necessary:

yarn example start

# Both platforms sequentially
yarn test:e2e:mobile

# Single platform
yarn test:e2e:ios
yarn test:e2e:android

Target a specific flow or force a rebuild:

# Run a single flow
yarn test:e2e:ios .maestro/enrichedInput/flows/core_controls_smoke.yaml

# Force a fresh build even if the app is already installed
yarn test:e2e:android --rebuild

Visual regression tests - some flows compare a screenshot of the component against a saved baseline in .maestro/enrichedInput/screenshots/ or .maestro/enrichedText/screenshots/. By default the baseline is asserted; pass --update-screenshots to capture new baselines instead:

# Update baselines on both platforms
yarn test:e2e:mobile --update-screenshots

# Single platform
yarn test:e2e:ios --update-screenshots
yarn test:e2e:android --update-screenshots .maestro/enrichedInput/flows/inline_styles_visual.yaml

Always review newly saved screenshots before committing them.

Running Android tests on macOS

macOS may throttle the Android emulator via App Nap when its window isn't visible, which can cause test timeouts. Either keep the emulator window visible while tests run, or disable App Nap for the emulator:

defaults write com.google.android.emulator NSAppSleepDisabled -bool YES

This requires an emulator restart and may drain your battery, so you may want to re-enable it afterwards with -bool NO.

Web (Playwright)

We use Playwright for end-to-end testing of the web example. Tests live in .playwright/tests/. Install the browser binaries once:

yarn playwright install

Run the suite from the root directory:

yarn test:e2e:web

Visual regression tests - some tests compare a screenshot of the component against a saved baseline in .playwright/screenshots/. By default the baseline is asserted; pass --update-screenshots to capture new baselines instead:

yarn test:e2e:web --update-screenshots

Append --ui for Playwright's UI mode (pick tests, watch runs, inspect traces). The Playwright config starts the Vite dev server automatically, so you don't need to run yarn example-web dev separately.

Documentation

The site you're reading is built with Docusaurus and lives in the docs/ directory. It's a standalone project with its own yarn.lock, separate from the monorepo workspace, so install its dependencies from inside the folder:

cd docs
yarn

Then start the local dev server:

yarn start

A few things worth knowing:

  • Pages are Markdown / MDX files in docs/docs/; the navigation is generated from the folder structure and _category_.json files. Filenames are kebab-case.
  • If you make any changes, run yarn build before opening a pull request, to make sure the project successfully builds.
info

When you change the public API or behaviour, please update the documentation in the same pull request whenever possible. Keeping the docs in sync with the code is one of the most valuable ways to contribute.

Commit message convention

We follow the conventional commits specification. Pre-commit hooks verify the format when you commit:

  • fix: bug fixes, e.g. fix crash due to deprecated method.
  • feat: new features, e.g. add a new method to the module.
  • refactor: code refactor, e.g. migrate from class components to hooks.
  • docs: documentation changes, e.g. add a usage example for the module.
  • test: adding or updating tests, e.g. add integration tests.
  • chore: tooling changes, e.g. change CI config.

Scripts

The package.json file contains scripts for common tasks:

  • yarn - set up the project by installing dependencies.
  • yarn typecheck - type-check files with TypeScript.
  • yarn lint - lint files with ESLint.
  • yarn test - run unit tests with Jest.
  • yarn example start - start the Metro server for the native example app.
  • yarn example android - run the native example app on Android.
  • yarn example ios - run the native example app on iOS.
  • yarn example-web dev - start the Vite dev server for the web example app.
  • yarn test:e2e - run all E2E tests (mobile + web) sequentially.
  • yarn test:e2e:mobile - run mobile E2E tests on iOS and Android sequentially.
  • yarn test:e2e:android - run E2E tests on Android.
  • yarn test:e2e:ios - run E2E tests on iOS.
  • yarn test:e2e:web - run E2E tests on the web example with Playwright.

Sending a pull request

tip

Working on your first pull request? Learn how from this free series: How to Contribute to an Open Source Project on GitHub.

note

If something is unclear or you're not sure about the correct API, feel free to open a GitHub issue or start a discussion.

The maintainers will be happy to help.

When you send a pull request:

  • Prefer small pull requests focused on one change.
  • Verify that linters and tests are passing.
  • Review the documentation to make sure it looks good.
  • Follow the pull request template when opening a pull request.
  • For pull requests that change the API or implementation, discuss with the maintainers first by opening an issue.