Contributing
In the first place, thank you for your interest in contributing! 🙏
Development Environment
Overview
All development is done inside the container named devcontainer which
contains all necessary tools and dependencies. All commands in the documentation
are container-agnostic and are meant to be run directly inside the devcontainer.
The devcontainer orchestrates other service containers behind the scenes via
Docker-from-Docker. Other containers are implementation details and should not
be accessed directly.
There are two supported ways to access the development environment. The recommended way is to use Development Containers with an IDE, which provides a more seamless experience. The alternative is to use Docker Compose directly, which is suitable for cases when IDE integration is not needed (e.g. terminal-only workflows).
Requirements
- Docker
- Docker Compose
- Development Containers (Are recommended)
Setup
Automatic setup
You can skip this section when using Development Containers. They run this script automatically the first time the project is opened.
Run the setup script to automatically create and configure all necessary files and build Docker images:
bash setup.sh
Manual setup
If you prefer to set up the project manually:
-
Create
.envfile and configure it:cp .env.dist .env -
Create
docker-compose.ymland configure it:cp docker-compose.yml.dist docker-compose.yml -
Build Docker images:
bash docker/build-docker-images.sh
Environment
The .env file configures services (ports, UID/GID, source mapping),
the devcontainer shell, editor and SSH agent forwarding, as well as application
settings. See .env.dist for available options.
Accessing the Development Environment
Using Development Containers
Open the project in an IDE that supports Development Containers (e.g.
Visual Studio Code, JetBrains IDEs).
The IDE will automatically set up the environment using the configuration in
.devcontainer/devcontainer.json.
Using Docker Compose
-
Start the
devcontainerin the background:docker compose up -d -
Open a shell inside the
devcontainer:docker compose exec devcontainer bash -
To stop the environment:
docker compose down
Customization
To customize the devcontainer, create a
docker/react_ui_devcontainer_local/Dockerfile that extends the base image:
# Image name `react-ui_devcontainer` might differ based on Docker compose project name
FROM react-ui_devcontainer as react-ui_devcontainer_local
# Add your customizations here
Then ensure docker-compose.yml has the build directive for the devcontainer
service:
devcontainer:
extends:
file: docker-compose.base.yml
service: devcontainer
build:
context: ./docker/react_ui_devcontainer_local/
dockerfile: Dockerfile
Rebuild the images after making changes:
bash docker/build-docker-images.sh
If you need to persist additional data across container restarts, see how it is
done in docker-compose.base.yml. You will need to add a volume mapping to the
devcontainer service and add a corresponding named volume definition.
What the devcontainer Contains
The devcontainer is built in the following layers:
Base Layer (react-ui_devcontainer)
General-purpose development layer. Makes the environment container-agnostic by wrapping commands to run in the appropriate service containers.
- OS: Debian Bookworm
- Shells: Bash, Zsh (with Oh My Zsh), Fish
- Editors: Vim, Nano
- Tools: Git, SSH client, Docker CLI (Docker-from-Docker)
- AI coding assistants: Claude Code, GitHub Copilot CLI, Open Code
Local Layer (react-ui_devcontainer_local)
Optional layer that allows individual developers to customize the environment. See Customization for details.
Service Containers
The devcontainer depends on the following service containers defined in
docker-compose.base.yml:
| Container | Purpose |
|---|---|
node |
Runs Node.js commands (npm, node) |
playwright |
Runs Playwright and Lighthouse tests |
docs |
Serves documentation via MkDocs |
All service containers mount the workspace at /workspace so that file changes
are shared.
Automatic Service Bootstrap
You can skip this section if you do not want to automatically install dependencies, build, and run the application, or if you are not an experienced developer. If you do use it, you can skip those sections as well, since the steps they describe are performed automatically.
Setting COMPOSE_AUTOSTART=true in .env makes the node and docs
service containers automatically install dependencies, build, and run the
application when they start. The default is false.
Setting COMPOSE_AUTOSTART=true comes with the following trade-offs:
- Changes to dependencies require a container restart. The watcher owns the
service container's entrypoint, so updating dependencies (e.g. pulling a
branch that changes
package-lock.json, or runningnpm install <pkg>) only takes effect after restarting thenodeservice container. The same applies to changes that affect the documentation server. - Service logs are not directly visible. The watcher and docs server run in
their own service containers rather than in your
devcontainershell, so their output is not shown alongside your regular terminal work. You have to inspect it viadocker compose logs <service>from the host.
If something is not working as expected, or you are not sure what is going on, set
COMPOSE_AUTOSTART=false, restart the containers, and follow the manual steps in the sections below instead.
Installing Dependencies
Run it on initial setup or when dependencies have changed:
npm ci
Building
To build the JavaScript code:
npm run build
To build the documentation:
mkdocs build
Running
To start building JavaScript files in watch mode:
npm start
To start the documentation server:
mkdocs serve
Testing
Please check out our Testing Guidelines. It includes testing guidelines and information on how to run tests.
Git Workflow
In order for the automation to work in the best possible way (we use GitHub Actions), please follow these guidelines:
-
One pull request per subject. Don't combine unrelated changes in a single PR unless they are really subtle details such as fix of a typo.
-
Only PRs into
masterbranch are listed in changelog. PRs into other branches are not picked up by release automation. -
Name your branches according to nature of change. Choose one of:
bc/*for breaking changesfeature/*for featuresbugfix/*for bugfixesrefactoring/*for refactoring of the librarydocs/*ordocumentation/*for changes in docsmaintenance/*for maintenance (builds, dependencies, automation, etc.)release/*for releases (administrators only)
-
Write clear, helpful and descriptive commit messages.
- Use imperative and write in English, e.g. Update dependencies or Claim support for controlled components only.
- If an issue exists for your changes, append the issue number in parentheses to the end of the commit message, e.g. Update dependencies (#261).
- Optionally use Markdown code blocks to emphasize, e.g.
Create
ScrollViewcomponent (#53). - When a commit fixes a commit already on the current branch (review feedback, a bug or typo in earlier work, a follow-up), commit it as a fixup so history stays atomic after the pre-merge squash, instead of a standalone "fix" commit.
-
Write clear, helpful and descriptive PR names.
- All rules for commit messages apply also for PR names.
- Always check that PR name meets the requirements above because PR names are used in changelog. GitHub automatically truncates long PR names and picks up branch name for multi-commit PRs, so it's necessary to make sure the PR name is what we want to have in the changelog.
- If an issue exists for your changes, append this text to PR
description (the topmost comment in the PR) in order for the issue
to be
closed automatically once the PR is merged:
Closes #<ISSUE NUMBER>. You will know the issue is linked correctly when it appears in the Linked issues section of the PR. (Having the issue mentioned in commit message and/or PR name does not have this effect.) - If there is no issue for your changes, please add your PR to
The BoardGitHub project in the Projects section of the PR. The correct board column will be selected automatically. This helps us keep track of what is in development.
Pull requests are labelled automatically. You can add more labels to better
qualify the nature of the change — in such case, it will be included in all
corresponding changelog groups. Or use the skip changelog label to exclude a
pull request from the changelog.
Package Linking
The best way for development of React UI is to link react-ui into your
application with npm link so you can see it in action.
- In React UI repository on your host machine, run
npm link - In your application, run
npm link @react-ui-org/react-ui
To prevent Invalid Hook Call Warning when React UI is linked, add the following code to your app's Webpack config:
const path = require('path');
module.exports = {
resolve: {
alias: {
react: path.resolve('./node_modules/react'),
'react-dom': path.resolve('./node_modules/react-dom'),
},
},
};
General Guidelines
To keep React UI consistent and predictable the following guidelines should be observed:
- If component accepts the
childrenprop it should be either required or the element should returnnullwhen no children are provided. - When forwarding HTML attributes to the component the following rules should
be observed:
- If the component internally instantiates one or more interactive (clickable/editable) elements, the attributes should be forwarded to all of them.
- If the component does not internally instantiate an interactive (clickable/editable) element, the attributes should be forwarded to the root element of the component.
Documenting
We use combination of Material for MkDocs and Docoff as the documentation platform.
Do see their respective documentation for details.