Quick Tools imports graphs or cards from JSON files and builds diagrams on a Miro board. The application uses the Eclipse Layout Kernel (ELK) to arrange nodes and edges automatically. Shapes are generated from templates and each element can carry metadata that controls its appearance and placement.
- Node.js 20.x
The app builds to static assets served by Vite in development and by any static host in production. All board interactions happen client-side through the Miro Web SDK.
Create a .env file at the repository root if you need to override defaults. All variables must use the VITE_ prefix so Vite exposes them to the client. Common options:
VITE_PORT=3000
VITE_LOGFIRE_SERVICE_NAME=miro-frontend
VITE_LOGFIRE_SEND_TO_LOGFIRE=false
Run the Vite dev server:
npm install
npm run devProduction build and local preview:
npm run build
npm run preview- Click the app icon on your Miro board.
- In the Create tab choose whether to import a diagram or cards.
- Select a
.jsonfile. Diagrams requirenodesandedgeswhile the cards option expects an object with acardsarray. - Once processed, widgets are placed on the board using the selected mode.
Cards are automatically arranged in a grid with a calculated number of
columns. Pass
columnswhen invoking the importer to override this value. - An example card structure is shown below.
Each card entry must specify a title. All other properties are optional:
description: Markdown or plain text bodytags: array of tag names to assign. These are mapped to the widget'stagIdsfield when cards are created or updatedstyle: card appearance (theme and background)fields: custom preview fields shown on the cardtaskStatus: Kanban status such asto-do
Omitting the fields property leaves the card without preview items.
The layout step leverages the ELK algorithm to compute positions for all nodes. You can provide layout hints in each node's metadata to influence spacing or layering. The engine runs automatically when a graph is uploaded. For an overview of available layout algorithms see docs/LAYOUT_OPTIONS.md. The ELK engine is dynamically imported from the jsDelivr CDN so it is excluded from the application bundle.
Shape templates live in
templates/shapeTemplates.json. Each template
defines the shape type, size and base styles. These templates also act as style
presets, exposing the buttons on the Style tab. When a node specifies a
template value in its metadata the corresponding template is applied. Edit
this file or add new entries to customise the available shapes. Connector
appearance is configured in
templates/connectorTemplates.json which
controls line colour, caps and font. The templates now include Decision and
StartEnd shapes useful for flowcharts. To add your own templates create new
entries in these JSON files and reference them by name in your graph metadata.
The app reloads templates on startup so changes are picked up automatically.
Additional details and a sample dataset are provided in
docs/TEMPLATES.md.
When Use existing widgets is enabled the importer caches all basic shapes on the board and matches them by their text content. The cache prevents duplicates during placement and is cleared once processing finishes.
Widgets no longer rely on metadata. Shapes and groups are matched purely by
their text content. When updating a diagram the importer searches for a shape
whose content matches the node label. Cards continue to encode their identifier
in the description using the ID: prefix.
{
"nodes": [
{ "id": "n1", "label": "Customer", "type": "Role" },
{ "id": "n2", "label": "Service", "type": "BusinessService" }
],
"edges": [{ "from": "n1", "to": "n2", "label": "uses" }]
}Hierarchical data where children are contained within parent shapes can be visualised using the Nested layout option in the Diagram tab. Positions and container sizes are computed entirely by the ELK engine for consistent spacing. Nodes are sorted alphabetically by default or via a custom metadata key.
The import panel is keyboard accessible. The drop area includes an ARIA label and hidden instructions so screen readers announce how to operate it. Focus the area with the Tab key and press Enter to open the file picker. The mode selection radios are grouped with a descriptive label.
The sidebar exposes extra tabs to manipulate existing widgets:
- Resize allows copying a widget size and applying it to others. You can
also type width and height manually. When a size is copied the same button
becomes a Reset Copy action so you can quickly revert. The tool displays
conversions between board units, millimetres and inches based on the ratio
96 units = 1 inch. - Style sets common style properties like fill colour or border width on all selected items. The tab shows the current fill colour swatch and updates when the selection changes. A slider lightens or darkens the colour while keeping the text readable.
- Grid arranges widgets into a grid with options for sorting and grouping the result.
- Frames renames or locks selected frames via helper utilities.
- Search finds text across the board and can replace all matches.
- Unit tests use Vitest.
- Run tests:
npm run test - Coverage report (HTML + lcov):
npm run coveragethen opencoverage/index.html. - Client tests that touch the DOM use jsdom; add
// @vitest-environment jsdomat the top of those files. - Focus initial coverage on utilities and hooks that donβt require the live Miro SDK (e.g., color/ratio helpers, template resolution, notifications, logger, UI utils).
Utility helpers searchBoardContent and replaceBoardContent can query or
update widgets by text. They support filtering by widget type, tag ID, fill
colour, assignee, creator and last modifier. Searches may be case sensitive,
whole-word or regular expression based and can be limited to the current
selection. The search tab exposes checkboxes for these modes alongside Next
to jump through results and Replace for single substitutions. During
replacements the board viewport focuses on each matched item so you can review
changes. See the Search tab walkthrough for the
complete UI flow.
The CSS for this project imports @mirohq/design-system-themes/light.css in
src/assets/style.css
to match the Miro UI. Components are sourced from @mirohq/design-system.
Avoid custom CSS when a component or token already exists. Wrapper components
in src/ui/components abstract the design-system primitives so
upgrades happen in one place.
When creating forms use the wrapper components so your inputs and buttons match the rest of the UI. These guidelines help keep layouts consistent:
- Use
InputFieldto pair labels with their controls. Provide the input component via theasprop and pass component props throughoptions. ButtonandInputFieldwrap the design-system components so events and sizing tokens behave consistently.- Group related fields using
FormGroupto maintain spacing and a clear vertical rhythm. - Arrange elements with the 12βcolumn grid classes (
cs*/ce*) so forms remain responsive. - Use values from
@mirohq/design-tokensfor margins and padding instead of hardβcoded numbers. - Layout wrappers such as
PanelorSectionexpose apaddingprop. Pass a token from@mirohq/design-tokensso spacing stays consistent. - Avoid passing custom
classNameorstyleprops to these wrappers; spacing decisions belong inside the component. - Keep wrapper nesting shallow; avoid unnecessary layers.
- When customisation is needed prefer extending design-system tokens over creating bespoke CSS classes.
- Stick to the provided
Buttoncomponent and choose theprimaryvariant for the main action. Place secondary actions on the right using thebuttonswrapper as seen in the tabs. - Keep labels short and descriptive. When extra context is required add a
Paragraphelement next to the fields. - Use real heading tags with visible text so screen readers announce sections.
- For dragβandβdrop zones include an ARIA label and hidden instructions so screen readers describe the workflow.
- Node.js 20.x
- Run
npm installto install dependencies. Thepackage-lock.jsonfile ensures everyone installs the same versions. - Run
npm run devto start the development server. Your URL should be similar to this example:
http://localhost:3000
- Open the
app manifest editor
by clicking Edit in Manifest.
In the app manifest editor, configure the app as follows, and then click save:
# See https://developers.miro.com/docs/app-manifest on how to use this
appName: JSON Diagram
sdkVersion: SDK_V2
sdkUri: http://localhost:3000
scopes:
- boards:read
- boards:write- Go back to your app home page, and under the
Permissionssection, you will see a blue button that saysInstall app and get OAuth token. Click that button. Then click onAddas shown in the video below. In the video we install a different app, but the process is the same regardless of the app.β οΈ We recommend to install your app on a developer team while you are developing or testing apps.β οΈ https://github.com/miroapp/app-examples/assets/10428517/1e6862de-8617-46ef-b265-97ff1cbfe8bf - Go to your developer team, and open your boards.
- Click on the plus icon from the bottom section of your left sidebar. If you
hover over it, it will say
More apps. - Search for your app
JSON Diagramor whatever you chose to name it. Click on your app to use it, as shown in the video below. In the video we search for a different app, but the process is the same regardless of the app. https://github.com/horeaporutiu/app-examples-template/assets/10428517/b23d9c4c-e785-43f9-a72e-fa5d82c7b019
Run the test suite:
npm testThe root AGENTS.md lists the commands to run before committing. Be sure to
install dependencies first:
npm installThen validate the codebase with:
npm run typecheck --silent
npm test --silent
npm run lint --silent
npm run format --silentThe Husky hooks live under the repository's .husky/ folder. Hooks are installed automatically on npm install via the prepare script so each commit is validated. The pre-commit hook runs type checking, tests, ESLint and Prettier. Execute the Vitest suite yourself before committing. Aim for at least 90Β % line and branch coverage and keep cyclomatic complexity under eight (see docs/ARCHITECTURE.md). Sonar rules such as using readonly class fields, optional chaining, semantic HTML tags and stable React keys. Run these checks before committing so code conforms to the repository guidelines.
CI merges coverage from all test shards. The build doesn't fail based on coverage numbers, so developers must keep both codebases above 90Β % coverage
With package-lock.json checked in you can run npm audit after each install
to scan dependencies for vulnerabilities. Include the lock file in commits so
everyone uses the exact dependency versions when installing.
All runtime messages are emitted through a shared logger defined in
src/logger.ts. Set the
LOG_LEVEL environment variable to trace, debug, info, warn, error or
silent to control verbosity. It defaults to info.
Example:
LOG_LEVEL=debug npm run devCommit messages must follow the Conventional Commits specification. A
commit-msg hook runs commitlint automatically (installed via npm install). Verify the latest commit
manually by running:
npm run commitlint -- --edit $(git rev-parse --verify HEAD)The CI pipeline also enforces commitlint via
\.github/workflows/commitlint.yml.
All Node jobs run from the repository root so caching and dependency
installs share the same lockfile.
.
βββ docs/
βββ src/
β βββ app/
β βββ assets/
β βββ board/
β βββ components/
β βββ core/
β βββ stories/
β βββ ui/
β βββ web/
βββ templates/
- Architecture explains how the source modules are organised.
- Tab Overview describes the sidebar tabs and their purpose.
- Deployment Guide describes building and hosting the React client.
- Web SDK Architecture explains the client-only structure.
- Miro API Costs explains why we cache shapes and avoid expensive board calls.
- Components Catalogue documents reusable React components.
- Design Foundation explains tokens and theming rules.
- Code Style outlines formatting and naming rules.
- UI Patterns shows common layouts and best practices.
Run the component explorer to preview the UI library. Storybook exposes interactive examples for each component and includes a toolbar toggle for the design-system light and dark themes. Add stories for any new UI element so reviewers can verify visuals.
npm run storybookGenerate a static Storybook site for publishing with:
npm run build-storybookRun the helper script to reproduce the GitHub Actions pipeline locally. It executes lint checks, type verification, unit tests, and the production build in sequence (Storybook build optional). Semantic release is intentionally skipped.
Pull requests trigger the unified ci.yml workflow to run linting, type checks,
unit tests and the production build for the React client. Pushes to main
additionally invoke repo-sonar.yml, repo-codeql.yml and repo-release.yml
for coverage, static analysis and release tasks.
npm run ci:localRelease notes are generated by
semantic-release and
appended to CHANGELOG.md in the repository root. Manual updates are no longer
required.
Please read CONTRIBUTING.md for contribution guidelines and the development workflow.
This software is released into the public domain under The Unlicense. See the LICENSE file for details.