Thank you for your interest in contributing to SuperDoc! Whether you're fixing a bug, improving documentation, or adding a feature, we appreciate your help.
- Ways to Contribute
- Architecture Overview
- Contribution Areas
- Your First PR
- Development Setup
- Pull Request Process
- Release Process
- Style Guidelines
- Community
Contributing isn't just about writing code. Here are several ways you can help:
Report bugs with reproduction files Open a .docx in SuperDoc and compare it with Microsoft Word. If something looks different, open an issue with the file attached. Good bug reports with reproduction files are incredibly valuable.
Improve documentation
Our docs live in apps/docs/ (docs.superdoc.dev) and are built with Mintlify. Fix typos, add code examples, improve explanations, or write guides. Run pnpm run dev:docs to preview locally. Documentation PRs are always welcome and a great way to get started.
Add examples and integrations
Create example projects showing SuperDoc with different frameworks (Next.js, Nuxt, Remix, etc.) in the examples/ directory.
Add test coverage Write unit tests or visual regression tests for existing features. Better test coverage helps everyone.
Fix bugs and implement features Check our good first issues for approachable tasks, or help wanted for meatier items.
Help the community Answer questions on Discord.
SuperDoc is a document editing and rendering library for the web. Understanding its architecture will help you find the right place to make changes.
SuperDoc uses its own rendering pipeline -- ProseMirror is NOT used for visual output:
DOCX File
β super-converter (parse OOXML into ProseMirror document)
β pm-adapter (convert PM nodes into FlowBlocks)
β layout-engine (paginate FlowBlocks into Layouts)
β DomPainter (render Layouts to DOM)
A hidden ProseMirror Editor instance manages document state and editing commands, but its DOM is never shown to the user. All visual rendering goes through DomPainter.
packages/
superdoc/ Main entry point (npm: superdoc)
react/ React wrapper (@superdoc-dev/react)
super-editor/ ProseMirror editor core
src/editors/v1/
core/
super-converter/ DOCX import/export (OOXML β ProseMirror)
extensions/ Editing behaviors (bold, lists, tables, etc.)
layout-engine/ Layout & pagination pipeline
pm-adapter/ ProseMirror β Layout bridge
layout-engine/ Pagination algorithms
painters/dom/ DOM rendering (DomPainter)
style-engine/ OOXML style resolution & cascade
contracts/ Shared type definitions
ai/ AI integration
collaboration-yjs/ Collaboration server
shared/ Internal utilities
examples/ Framework integration examples
tests/visual/ Visual regression tests (Playwright)
| What you want to change | Where to look |
|---|---|
| How something looks (visual rendering) | layout-engine/painters/dom/ |
| Style resolution (fonts, colors, borders) | layout-engine/style-engine/ |
| Data flowing from editor to renderer | layout-engine/pm-adapter/ |
| Editing behavior (keyboard, commands) | super-editor/src/editors/v1/extensions/ |
| DOCX import/export | super-editor/src/editors/v1/core/super-converter/ |
| React integration | packages/react/ |
| Main entry point (Vue) | packages/superdoc/ |
| Visual regression tests | tests/visual/ |
The importer stores raw OOXML properties. The style-engine resolves them at render time.
The converter (super-converter/) parses and stores only what is explicitly in the XML. The style-engine (layout-engine/style-engine/) handles all cascade logic (defaults -> table style -> conditional formatting -> inline overrides). Don't resolve styles during import -- it bakes them into node attributes and loses the original document intent on export.
These are areas where community contributions are especially welcome. Check issues labeled good first issue for specific tasks.
| Area | Difficulty | Where to Look | What to Do |
|---|---|---|---|
| Documentation | Easy | docs.superdoc.dev | Fix gaps, add code examples, improve explanations |
| Examples | Easy | examples/ |
Create framework integration examples |
| Test coverage | Easy-Medium | tests/visual/ |
Add tests for existing features |
| Rendering parity | Medium | layout-engine/painters/dom/ |
Open a .docx in Word and SuperDoc, fix visual differences |
| Browser compatibility | Medium | super-editor/, layout-engine/ |
Fix Firefox/Safari-specific bugs |
| Copy/paste | Medium | super-editor/src/editors/v1/extensions/ |
Fix formatting loss when pasting from Word, Google Docs, browsers |
| DOCX import coverage | Medium-Hard | super-editor/src/editors/v1/core/super-converter/ |
Support additional OOXML tags and elements |
Here's a step-by-step walkthrough to make your first contribution:
- Browse good first issues
- Or pick from the contribution areas above
- Comment on the issue to let others know you're working on it
# Fork the repo on GitHub, then:
git clone https://github.com/<your-username>/superdoc.git
cd superdoc
# Install dependencies (pnpm 9+ required)
pnpm install
# Start the dev server
pnpm devThe dev server gives you a live editor to test changes.
git checkout -b fix/your-change-description
# or: feat/your-change-description
# or: docs/your-change-descriptionUse the architecture overview and the "Where to Make Changes" table to locate the right files. When in doubt, search for keywords:
# Find files by name
find packages/ -name "*.js" | xargs grep -l "your-keyword"
# Search file contents
grep -r "your-keyword" packages/ --include="*.js" -l- Follow existing code patterns in the file you're editing
- Keep changes focused -- one fix or feature per PR
- Add or update tests for your changes
# Run the full test suite
pnpm test
# Run tests for a specific package
pnpm run test:editor # super-editor tests
pnpm run test:superdoc # superdoc package tests
# Check formatting and linting
pnpm run format:check
pnpm run lintgit add <files>
git commit -m "fix: describe your change"
git push origin fix/your-change-descriptionFollow Conventional Commits for your commit message (see Commit Messages below).
Open a PR against the main branch. In the description:
- Describe what you changed and why
- Link to the related issue (e.g.,
Closes #123) - Include screenshots for visual changes
- Add a test plan if applicable
CI will run automatically. A maintainer will review your PR and provide feedback.
git clone https://github.com/<your-username>/superdoc.git
cd superdoc
pnpm install
pnpm devpnpm dev # Start dev server (from examples/)
pnpm build # Build all packages
pnpm test # Run all tests
pnpm run lint # Run ESLint
pnpm run format # Run PrettierIf your PR adds a new public export from superdoc (a new @typedef in packages/superdoc/src/index.js, a new value re-exported from a public subpath, or a new subpath in package.json exports), it must ship with a type test that exercises the new surface under strict mode.
The consumer matrix at tests/consumer-typecheck/ is the regression net. Two automated checks enforce this on every PR:
check-public-types.mjs-- the assertion list intests/consumer-typecheck/src/all-public-types.tsis auto-derived from the@typedefblock inpackages/superdoc/src/index.js. Adding a new typedef without regenerating the list fails CI. Runnpm run check:types:writefrom insidetests/consumer-typecheck/(ornode tests/consumer-typecheck/check-public-types.mjs --writefrom the repo root) and commit the regenerated file.typecheck-matrix.mjs-- every typed public subpath in the RFC inventory has at least one matrix scenario. If you add a new subpath, add a fixture undertests/consumer-typecheck/src/and a corresponding entry in the matrix, and update the inventory indocs/architecture/package-boundaries.md.
The point of these gates is to keep customer TypeScript builds working. A new export that ships without a type test can collapse to any (or fail to resolve) for consumers without the team noticing.
feature/descriptionfor new featuresfix/descriptionfor bug fixesdocs/descriptionfor documentation changesperf/descriptionfor performance improvements
Follow Conventional Commits:
feat: add real-time cursor sharing
- Implement cursor position tracking
- Add websocket connection for updates
Closes #123
Your commit type determines the version bump on release:
| Commit Type | Version Bump | Example |
|---|---|---|
fix: |
Patch (0.0.X) | fix: resolve cursor positioning bug |
feat: |
Minor (0.X.0) | feat: add PDF export functionality |
feat!: or BREAKING CHANGE: |
Major (X.0.0) | feat!: redesign document API |
chore:, docs:, refactor:, test: |
No version change | docs: update README |
When you open a PR, the following checks run automatically:
- Commit message validation
- Code formatting (Prettier)
- Linting (ESLint)
- Unit tests
- Visual regression tests (if UI changes)
- Changes are focused (one fix/feature per PR)
- Tests added or updated
- Test suite passes locally (
pnpm test) - Code is formatted (
pnpm run format:check) - Commit messages follow conventional commits
- PR description links to related issue
- If you added a public API, the consumer-typecheck gates pass (see Adding a public API)
SuperDoc uses automated CI/CD with semantic-release. No manual version bumps are needed.
mainbranch -> Pre-release versions (@nexttag on npm)stablebranch -> Stable versions (@latesttag on npm)
Every merge to main publishes a pre-release automatically. Stable releases are promoted from main via a GitHub Actions workflow.
- Use JavaScript with JSDoc type annotations for all new code
- Follow the existing code style (enforced by ESLint and Prettier)
- Use ES6+ features
- Document public APIs using JSDoc
- Keep lines under 100 characters
# Check formatting
pnpm run format:check
# Auto-fix formatting
pnpm run format
# Run linting
pnpm run lint
# Fix linting issues
pnpm run lint:fixThis project and everyone participating in it are governed by our Code of Conduct. By participating, you are expected to uphold this code. Please report unacceptable behavior to support@superdoc.dev.
We value every contribution. Community contributors are featured in our README and recognized on Discord.
Questions? Join our Discord.