vue-mermaid-steps
v0.3.0
Published
A reactive Vue 3 component for progressively revealing Mermaid diagrams.
Maintainers
Readme
vue-mermaid-steps
A Vue 3 component for progressively revealing Mermaid diagrams. Nodes and edges in completed steps stay fully visible; future steps are dimmed.
Renders with Mermaid v12 directly; Mermaid is loaded lazily on the client when the component mounts. The diagram is rendered once, unchanged; step visibility and styles are applied to the rendered SVG, so moving between steps does not re-render the diagram. Requires Vue 3.5 or later and an ESM-capable Vue application.
Live playground | npm package | GitHub repository
Installation
Install vue-mermaid-steps from npm:
pnpm add vue-mermaid-stepsUsage
<script setup lang="ts">
import { ref } from 'vue'
import MermaidSteps from 'vue-mermaid-steps'
const steps = 3
const currentStep = ref(0)
const diagram = ref(`flowchart LR
Start step1E@--> Plan:::step1
Plan step2E@--> Build:::step2
Build step3E@--> Ship:::step3
classDef step1 fill:#f99
classDef step2 fill:#9f9
classDef step3 fill:#99f
`)
</script>
<template>
<button @click="currentStep = Math.max(0, currentStep - 1)">Previous</button>
<button @click="currentStep = Math.min(steps, currentStep + 1)">Next</button>
<MermaidSteps
:diagram="diagram"
:steps="steps"
:current-step="currentStep"
/>
</template>Both default and named imports are available:
import { MermaidSteps } from 'vue-mermaid-steps'The same component works in Slidev: import it in a slide's <script setup> and
bind current-step to reactive state (or Slidev's $clicks).
Props
All props are reactive. diagram and steps are required; all other props are
optional.
| Prop | Type | Meaning |
| --- | --- | --- |
| diagram | string | Mermaid source code. |
| steps | number | Non-negative integer number of step classes to generate. |
| currentStep | number | Optional integer number of steps to reveal, normally from 0 to steps. Defaults to 0 (all steps dimmed). |
| edgesPerStep | number | Non-negative safe integer number of edge IDs to map per step, including the base ID. Defaults to 8. |
| inactiveOpacity | number | Opacity of future steps, from 0 (transparent) to 1 (fully visible). Defaults to 0.2. Invalid values raise a RangeError. |
| currentStepStyle | string | CSS declarations for nodes in exactly the current step. Defaults to ''. |
| dimmedStepsStyle | string | CSS declarations for nodes in future (dimmed) steps. Defaults to ''. |
| currentStepEdgeStyle | string | CSS declarations for edges in exactly the current step. Defaults to ''. |
| dimmedStepsEdgeStyle | string | CSS declarations for edges in future (dimmed) steps. Defaults to ''. |
| options | MermaidConfig | Options passed to mermaid.initialize before rendering. Defaults to Mermaid's own defaults. |
Step classes
- Assign nodes to
step1,step2, etc. using:::step1orclass. - Name edges
step1E,step2E, etc. using Mermaid'sid@-->syntax. The component automatically treats these IDs as edges of the corresponding step. - Elements in steps up to
currentStephave opacity1. - Later steps use
inactiveOpacity(default0.2); completed steps stay at1. - Custom style strings are applied after the default opacity declaration and can override it. Current-step style props do not apply to completed steps.
- At step
0, all numbered steps are dimmed. Atsteps, all are visible. - Elements without step classes are unaffected.
steps: 0leaves the rendered diagram unstyled.- Values of
currentStepbelow0dim every step; values abovestepsreveal every step.
Edge naming convention
By default, each step maps 8 unique edge IDs: the base stepNE plus stepNEa
through stepNEg, where N is the step number. For step 1 these are:
step1E, step1Ea, step1Eb, step1Ec, step1Ed, step1Ee, step1Ef, step1EgAdjust dimming independently of the current step:
<MermaidSteps :diagram="diagram" :steps="3" :inactive-opacity="0.4" />Customize the current and dimmed steps using semicolon-separated CSS declarations (no selectors or braces):
<MermaidSteps
:diagram="diagram"
:steps="3"
:current-step="currentStep"
current-step-style="fill: #ffe08a; stroke: #d97706; stroke-width: 3px"
dimmed-steps-style="opacity: 0.1"
/>Both props affect only the corresponding nodes; edges are unchanged. Completed steps
receive neither custom style string. Changing or clearing these props updates
the rendered diagram without re-rendering; an empty string retains the default
opacity behavior.
At step 0, only dimmedStepsStyle applies; above steps, neither applies.
Style nodes and edges independently with the specific props:
<MermaidSteps
:diagram="diagram"
:steps="3"
:current-step="currentStep"
current-step-style="fill: #ffe08a; stroke: #d97706"
current-step-edge-style="stroke: #d97706; stroke-width: 3px"
dimmed-steps-style="opacity: 0.1"
dimmed-steps-edge-style="opacity: 0.3; stroke: #999"
/>Node and edge styles are independent and applied after default opacity.
Later declarations override earlier ones for the same property while retaining
other existing Mermaid class styles. Node styles target the same elements as a
Mermaid classDef stepN would (the node's shape and label); edge styles target
the edge path. Empty strings add no declarations, leaving
default opacity behavior intact. All four props follow the same current/future
step rules and update reactively. There is no shared node-and-edge style prop.
Edge styles support automatic IDs and manual class customId stepNE
mappings, including when edgesPerStep is 0. Invalid CSS declarations are
ignored by the browser's CSS parser. Treat CSS strings as trusted input, just
like diagram content.
Mermaid edge IDs must be unique within the diagram. Use a different suffix for
each edge in the same step; all configured IDs are automatically treated as
edges of step N. Only use the IDs you need; unused IDs have no effect.
The IDs are case-sensitive, with an uppercase E and lowercase suffixes.
Pass :edges-per-step="16" to map the base ID plus a through o, or use a
larger count as needed. Suffixes continue a ... z, aa, ab, ...; for
example, 28 includes stepNEaa. The count includes the unsuffixed base ID.
Changing this prop updates the styled edges. 0 disables automatic edge
mappings while keeping node opacity and manual edge mappings. Invalid
counts (negative, fractional, or non-finite) raise a RangeError.
<MermaidSteps :diagram="diagram" :steps="3" :edges-per-step="16" />For example, two branches can reveal together without manual class mappings:
flowchart LR
Idea step1E@--> Plan:::step1
Plan step2E@--> Frontend:::step2
Plan step2Ea@--> Backend:::step2
Frontend step3E@--> Ship:::step3
Backend step3Ea@--> ShipIDs beyond edgesPerStep are not automatically mapped. Edges with other IDs can
be assigned to a step with a manual class customId stepNE statement; the
component reads these statements from the diagram source.
How styles are applied
Mermaid renders the diagram source exactly as given. The component then sets
step opacity and custom styles as inline !important styles on the rendered SVG
elements, which is required to override Mermaid's own inlined classDef styles.
Original inline styles are restored before styles are reapplied, so existing
colors and other class styles are preserved unless overridden by the custom
style props. Classes beyond the configured steps are not modified.
Renderer options and events
Attributes such as class and style are applied to the diagram's wrapper
element. The options prop is passed to mermaid.initialize. The diagram is
re-rendered only when the diagram source or the options values change; a new
options object with the same values does not re-render. The component emits:
renderedafter a new SVG has been inserted and step styles applied;parse-errorwith the error thrown by Mermaid when a diagram cannot be rendered.
For example:
<MermaidSteps
:diagram="diagram"
:steps="3"
:current-step="currentStep"
:options="{ theme: 'dark' }"
@parse-error="handleParseError"
/>On errors, the previously rendered diagram stays visible. Handle parse-error
for custom error reporting. Mermaid click callbacks are not wired to Vue
events. Only render diagram content from sources you trust; Mermaid's
securityLevel can be configured with options.
Development
Run commands from this directory. Node.js 22.12+ and pnpm are required; no Slidev installation or files from a parent repository are needed.
pnpm install --frozen-lockfile
pnpm run typecheck
pnpm test
pnpm run buildpnpm run test:watchruns tests in watch mode.pnpm run buildcreates an ESM library and TypeScript declarations indist/.- Vue and Mermaid are externalized from the build.
- Component tests mock Mermaid with an SVG fixture that mirrors Mermaid's output structure to verify applied step styles, prop reactivity, re-render rules, attribute forwarding, errors, and events without coupling to SVG layout.
- Playground tests cover editing, step controls, validation, and error recovery.
GitHub build
The build workflow runs on pushes, pull requests, and manual dispatch. It installs from the lockfile, checks types, runs tests, builds, and uploads an npm tarball as an artifact. It does not publish to npm and requires no registry credentials.
Live playground and GitHub Pages
The playground includes an editable Mermaid source, step-count input, current-step and inactive-opacity sliders, previous/next and hide/show controls, four CSS style inputs below the chart, resettable example, and explicit validation/rendering errors. Source changes are applied with Apply diagram; step, opacity, and style changes update the preview immediately. Style inputs accept semicolon-separated CSS declarations and are reflected in the usage example. Clear them to restore default styling, or use Reset example to reset all controls.
pnpm run dev
pnpm run build:playground
pnpm run previewThe production demo is written to playground-dist/, separately from the npm
library in dist/. Relative asset URLs support both project Pages URLs
(https://OWNER.github.io/REPOSITORY/) and custom domains. No repository name
needs to be hardcoded. The playground is excluded from the npm tarball.
To publish the standalone repository's demo:
- In GitHub Settings > Pages > Build and deployment, select GitHub Actions as the source.
- Push to the repository's default branch, or manually run the Build workflow on that branch.
- Open the URL reported by the workflow's github-pages deployment.
The build job checks types, runs tests, and builds both the library and demo on every push and pull request. Only default-branch pushes and manual runs deploy the playground. The deploy job uses GitHub's built-in token and OIDC permissions; no personal access token or npm credentials are needed.
When extracting this directory, copy its entire contents, including .github,
.gitignore, and pnpm-lock.yaml, to the root of the new repository.
GitHub only discovers workflows in a repository's root .github/workflows;
the nested workflow is inactive while this project remains inside another
repository.
Packaging and publication
pnpm pack --dry-run
pnpm packPacking automatically builds the library. Only dist/, this README, the changelog,
the license, and package metadata are included. Install the resulting .tgz in a Vue application to test
the distributable before releasing it.
Releases
release-it manages version bumps,
the changelog, release commits, v-prefixed tags, GitHub
releases, and public npm publication with provenance. Release tooling requires
Node.js 22 (22.22.2+), 24 (24.15.0+), or 26+; the release workflow uses Node.js 24.
The library's runtime requirements are unchanged.
One-time setup in the standalone MurzNN/vue-mermaid-steps repository:
- On npm, open vue-mermaid-steps > Settings > Trusted Publisher and select
GitHub Actions. Set the owner to
MurzNN, repository tovue-mermaid-steps, and workflow filename torelease.yml. Leave the environment name empty, since the workflow does not use a GitHub environment. See npm trusted publishing. - Ensure repository rules allow the workflow's
GITHUB_TOKENto push release commits tomainand createv*tags. The job requestscontents: writefor Git/GitHub releases andid-token: writefor npm OIDC authentication. It does not need anNPM_TOKENor personal access token.
To release:
- Merge changes into
mainusing Conventional Commits (feat:,fix:,feat!:, or aBREAKING CHANGE:footer) so release notes can be generated. - Open Actions > Release > Run workflow on
mainand choosepatch,minor, ormajor. Dry run is enabled by default: inspect the proposed version and notes without publishing, committing, or pushing. - Run again with Dry run disabled to publish. The workflow installs from
the lockfile, builds, checks types, and runs tests before release-it updates
the version/changelog, publishes to npm, commits, tags, pushes, and creates
a GitHub release using the generated notes. Packing also rebuilds the
library via
prepack.
The workflow only runs on the default branch, and release-it requires main.
Update both settings if the repository's release branch changes. Concurrent
releases are serialized; each run checks out the latest default-branch commit.
The existing Build/Pages workflow remains separate; GitHub does not trigger
push workflows for commits pushed with GITHUB_TOKEN.
For a local preview after installing dependencies:
pnpm run release:dry-run patch --ci --github.release=falseThis runs type checks and tests, then previews the release without needing
GitHub or npm credentials. Use a clean, up-to-date main checkout with an
upstream remote. npm authentication checks are disabled in release-it because
trusted publishing obtains credentials at publish time; actual publishing
must run in the configured GitHub workflow.
If publication fails after a commit, tag, or npm version has already been created, inspect the remote Git tags, GitHub releases, and npm version before retrying. Do not blindly rerun with another increment: release steps across GitHub and npm are not transactional.
For an npm-only retry when the previous publish failed before any version or tag was created, select the same increment and enable npm-only (disable Dry run to publish). This prepares the version and changelog in the runner and publishes to npm, but does not commit, tag, push, or create a GitHub release. The repository version remains unchanged; reconcile it with the published version before a subsequent full release.
The historical v0.1.0 and v0.2.0 tags point to the source commits recorded
in npm's gitHead metadata. Version 0.2.0 was prepared only in the publishing
runner, so its tagged source still declares 0.1.0. A subsequent reconciliation
commit updates the repository version and splits the changelog at these tags;
the already-published npm packages are unchanged.
License
MIT, copyright 2026 Alexey Korepov.
