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 xcodeto openapps/example/ios/EnrichedTextInputExample.xcworkspacein Xcode. Find the sources under Pods > Development Pods > ReactNativeEnrichedHtml. - Android - run
yarn android-studioto openapps/example/androidin 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
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.
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/binis in yourPATH. - iOS - Xcode, with
xcrunavailable (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/sdkon macOS) and add these to yourPATH:$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.
| Platform | Device | OS |
|---|---|---|
| iOS | iPhone 17 | iOS 26.2 |
| Android | Pixel 9 | API 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.
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_.jsonfiles. Filenames are kebab-case. - If you make any changes, run
yarn buildbefore opening a pull request, to make sure the project successfully builds.
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
Working on your first pull request? Learn how from this free series: How to Contribute to an Open Source Project on GitHub.
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.