Skip to content

bartvanderwal/remark-kroki-a11y

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

104 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

remark-kroki-a11y

npm version license Node.js BDD Tests

A Remark plugin that adds accessible source code details and natural language descriptions to Kroki diagrams.

Note: This plugin has only been tested with Docusaurus. It should work with other unified/remark-based systems, but this has not been verified.

Features

  • Expandable source code - Adds a collapsible <details> block with the diagram source code below each diagram
  • Natural language descriptions - Generates human-readable descriptions for screen readers (currently supports PlantUML state diagrams)
  • Tabs interface - Always uses tabs when source and (generated or fallback) description are available
  • Keyboard accessible - Uses native <details> element that works with Enter/Space
  • Localization - Supports Dutch (nl) and English (en)
  • Per-diagram control - Use hideSource or hideA11y flags to control visibility

Supported Diagram Types

Works with any diagram type supported by Kroki, including:

  • PlantUML
  • Mermaid
  • C4 (via PlantUML)
  • GraphViz
  • And many more...

Current A11y Description Support

Diagram Type PlantUML Mermaid Status
Class diagrams βœ… Full ⚠️ To test Partial
State diagrams βœ… Full ❌ Partial
Sequence diagrams ⚠️ Beta ⚠️ Beta Partial
Activity diagrams ⚠️ Beta ❌ Partial
C4 diagrams ⚠️ Beta N/A Partial
ER diagrams ❌ ❌ Planned
Gantt charts ❌ ❌ Future
Pie charts N/A ❌ Planned
Complete Diagram Type Reference (PlantUML vs Mermaid)

UML Diagrams

Diagram Type PlantUML Mermaid A11y Support
Class Diagram βœ… βœ… βœ… PlantUML, ⚠️ Mermaid
Sequence Diagram βœ… βœ… ⚠️ Beta
Activity Diagram βœ… ❌ 1 ⚠️ Beta
State Diagram βœ… βœ… βœ… PlantUML
Use Case Diagram βœ… ❌ ❌
Object Diagram βœ… ❌ ❌
Component Diagram βœ… ❌ ❌
Deployment Diagram βœ… ❌ ❌

Data & Flow Diagrams

Diagram Type PlantUML Mermaid A11y Support
ER Diagram βœ… βœ… ❌ Planned
Flowchart ❌ βœ… ❌
Pie Chart ❌ βœ… ❌ Planned
Gantt Chart βœ… βœ… ❌
Mind Map βœ… βœ… ❌
Timeline ❌ βœ… ❌
XY Chart ❌ βœ… ❌
Quadrant Chart ❌ βœ… ❌

Architecture & Specialized Diagrams

Diagram Type PlantUML Mermaid A11y Support
C4 Diagram βœ… 2 βœ… (beta) ⚠️ Beta
Git Graph ❌ βœ… ❌
User Journey ❌ βœ… ❌
Sankey Diagram ❌ βœ… (beta) ❌
Block Diagram βœ… βœ… (beta) ❌
BPMN βœ… ❌ ❌
Archimate βœ… ❌ ❌
Network Diagram βœ… ❌ ❌
Wireframe (Salt) βœ… ❌ ❌
WBS βœ… ❌ ❌
JSON/YAML βœ… ❌ ❌
Requirement Diagram ❌ βœ… ❌
Packet Diagram ❌ βœ… (beta) ❌

Legend: βœ… = Full support | ⚠️ = Beta/partial | ❌ = Not supported | N/A = Not applicable

Roadmap

Diagram-as-Code Formats

We support multiple diagram-as-text formats through Kroki:

Format UML Support C4 Other
PlantUML All 14 UML types βœ… via C4-PlantUML Mindmaps, Gantt, etc.
Mermaid Class, Sequence, State, ER βœ… (beta) Flowchart, Pie, etc.

Future Diagram Types (Student Projects Welcome!)

These diagram types don't have good diagram-as-text standards yet:

  • Domain Stories (egon.io) - Visual storytelling for domain modeling
  • User Story Maps - Story mapping for agile planning
  • Event Storming - Domain event visualization

Architecture

We use PlantUML's data structure as internal representation (IR) with adapters for each input format. See ADR-0006 for details.

The official @mermaid-js/parser npm package provides AST parsing for Mermaid diagrams, enabling conversion to our IR.

For comprehensive architecture documentation following Simon Brown's Software Guidebook structure, see the Software Guidebook (includes C4 diagrams, use cases, and component views).

For all architecture decisions, see the Architecture Decision Records (ADRs).

Installation

Install as a development dependency (build-time plugin):

npm install --save-dev remark-kroki-a11y
# or
yarn add --dev remark-kroki-a11y

Note: When using this plugin for build in pipeline ensure CI installs devDependencies, because this plugin runs at build time.

Usage with Docusaurus

In your docusaurus.config.js:

const rehypeRaw = require('rehype-raw').default;

// MDX node types to pass through (not processed by rehype-raw)
const passThrough = [
  'mdxFlowExpression',
  'mdxJsxFlowElement',
  'mdxJsxTextElement',
  'mdxTextExpression',
  'mdxjsEsm',
];

module.exports = {
  presets: [
    [
      'classic',
      {
        docs: {
          remarkPlugins: [
            [require('remark-kroki-a11y'), {
              showSource: true,
              showA11yDescription: true,
              defaultExpanded: false,
              summaryText: '{type} source code for "{title}"',
              a11ySummaryText: 'Natural language description for "{title}"',
              tabSourceLabel: 'Source',
              tabA11yLabel: 'Description',
              cssClass: 'diagram-expandable-source',
              languages: ['kroki'],
              locale: 'en',
              showDiagramModeToggle: false,
              showDiagramLegend: false,
              kroki: {
                krokiBase: 'https://kroki.io',
                lang: 'kroki',
                imgRefDir: '/img/kroki',
                imgDir: 'static/img/kroki',
              },
            }],
          ],
          rehypePlugins: [
            // Enable raw HTML in MDX (needed for remark plugin HTML output)
            [rehypeRaw, { passThrough }],
          ],
        },
      },
    ],
  ],
};

Local Kroki via Docker (recommended for stable local builds)

If kroki.io is unavailable or blocked, run a local Kroki server:

docker compose -f docker-compose.kroki.yml up -d

Verify the server is reachable:

curl http://localhost:8000/health

The compose file also mounts a local include folder and sets KROKI_PLANTUML_INCLUDE_PATH, so PlantUML can resolve:

!include domainStory.puml

Use the local server in docusaurus.config.js:

[require('remark-kroki-a11y'), {
  kroki: {
    krokiBase: 'http://localhost:8000',
    lang: 'kroki',
    imgRefDir: '/img/kroki',
    imgDir: 'static/img/kroki',
  },
}]

Or without editing config, set:

export KROKI_BASE_URL=http://localhost:8000

Stop it when done:

docker compose -f docker-compose.kroki.yml down

Required: Client Module and CSS

The plugin requires a client-side module for tab switching and CSS styling. These are included in the package:

// In docusaurus.config.js
module.exports = {
  clientModules: [
    require.resolve('remark-kroki-a11y/diagramTabs.js'),
  ],
  // ...
};

For CSS, import the provided stylesheet or copy it to your project:

// In your custom.css or via import
@import 'remark-kroki-a11y/diagram-a11y.css';
Custom CSS and Client Module (optional)

If you want to customize the styling or tab behavior, you can copy these files to your project instead:

Client Module (src/clientModules/diagramTabs.js):

export function onRouteDidUpdate() {
  const tabContainers = document.querySelectorAll('.diagram-expandable-source-tabs');

  tabContainers.forEach((container) => {
    const buttons = container.querySelectorAll('.diagram-expandable-source-tab-btn');
    const contents = container.querySelectorAll('.diagram-expandable-source-tab-content');

    buttons.forEach((button) => {
      if (button.dataset.tabListener) return;
      button.dataset.tabListener = 'true';

      button.addEventListener('click', () => {
        const tabId = button.dataset.tab;

        buttons.forEach((btn) => btn.classList.remove('active'));
        button.classList.add('active');

        contents.forEach((content) => {
          content.classList.toggle('active', content.dataset.tab === tabId);
        });
      });
    });
  });
}

CSS Styling:

/* Expandable source code block for diagrams */
.diagram-expandable-source summary {
  cursor: pointer;
  font-weight: 500;
  padding: 0.25rem 0;
  user-select: none;
  font-size: 0.9em;
}

.diagram-expandable-source summary:hover {
  color: var(--ifm-color-primary);
}

.diagram-expandable-source pre {
  background: var(--prism-background-color, #1e1e1e);
  color: var(--prism-color, #d4d4d4);
  padding: 1rem;
  border-radius: 4px;
  overflow-x: auto;
  margin: 0.5rem 0;
}

/* Tabs styling */
.diagram-expandable-source-tab-buttons {
  display: flex;
  border-bottom: 1px solid var(--ifm-color-emphasis-300);
}

.diagram-expandable-source-tab-btn {
  padding: 0.5rem 1rem;
  border: none;
  background: transparent;
  cursor: pointer;
  border-bottom: 2px solid transparent;
}

.diagram-expandable-source-tab-btn.active {
  color: var(--ifm-color-primary);
  border-bottom-color: var(--ifm-color-primary);
}

.diagram-expandable-source-tab-content {
  display: none;
}

.diagram-expandable-source-tab-content.active {
  display: block;
}

Options

Option Type Default Description
showSource boolean true Show source code tab
showA11yDescription boolean true Show natural language description tab
defaultExpanded boolean false Expand details by default
summaryText string '{type} source code for "{title}"' Summary text template
a11ySummaryText string 'Natural language description for "{title}"' A11y summary text template
tabSourceLabel string 'Source' Label for source tab
tabA11yLabel string 'Description' Label for description tab
cssClass string 'diagram-expandable-source' CSS class for the details element
languages string[] ['kroki'] Code block languages to process
locale string 'en' Locale for generated descriptions ('en' or 'nl')
fallbackA11yText object { en: '...', nl: '...' } Override fallback text per locale
showDiagramModeToggle boolean false For PlantUML class diagrams, also render a simplified visual variant and show a For devs/Simpler toggle
showDiagramLegend boolean false For PlantUML class diagrams with mode toggle: add an auto-generated relation legend in For devs mode only
kroki object { krokiBase, lang, imgRefDir, imgDir } Kroki render settings passed to the internally used remark-kroki-plugin

When showDiagramModeToggle is enabled:

  • For devs mode uses an enriched PlantUML view:
    • non-dependency relations are duplicated as attributes in the source class (based on arrow direction)
    • attribute visibility icons (public + / private -) are shown β€” useful for distinguishing access modifiers
  • Simpler mode only simplifies/removes:
    • all more advanced relation types like aggregation (*--), composition (o--), and inheritance/realization (<|..) collapse to simple association (-->)
    • id attributes are removed
    • attribute types are hidden (for example +amount : Decimal becomes +amount)
    • custom stereotypes are hidden (for example Entity and Value Object)
  • Optional legend support:
    • enable globally with showDiagramLegend: true
    • override per diagram with showDiagramLegend / hideDiagramLegend
    • legend is shown only in For devs mode
    • legend content is filtered to only relation arrows that are actually used in that diagram

Note: PlantUML itself already supports manual legends using legend ... endlegend in diagram source. The plugin option above is specifically for auto-generated legends in generated For devs/Simpler class-diagram variants.

Rationale: this follows the spirit of Simon Brown's talk The Lost Art of Software Design, where explicit notation and design communication matter. Relation-arrow semantics are often assumed as shared knowledge, but in practice symbols like *--> and o--> are frequently mixed up. An optional, filtered legend helps make design intent explicit without forcing extra visual noise on every diagram.

Markdown Flags

Control per-diagram behavior using flags in the code block meta:

<!-- Hide source code for this diagram -->
```kroki hideSource imgType="plantuml"
@startuml
...
@enduml
```

<!-- Hide natural language description for this diagram -->
```kroki hideA11y imgType="plantuml"
@startuml
...
@enduml
```

<!-- Override automatic description with custom text -->
```kroki a11yDescriptionOverride="Zie toelichting in tekst voor beschrijving van dit diagram" imgType="plantuml"
@startuml
...
@enduml
```

<!-- Load diagram source from a local file -->
```kroki imgType="plantuml" imgTitle="Order model" src="order-model.puml"
```

<!-- Enable For devs / Simpler diagram visual toggle for this PlantUML class diagram -->
```kroki showDiagramModeToggle imgType="plantuml"
@startuml
class Order {
  +id: UUID
  +total: Money
}
Order o-- OrderLine
@enduml
```

<!-- Enable auto-generated legend for this diagram (when mode toggle is used) -->
```kroki showDiagramModeToggle showDiagramLegend imgType="plantuml"
@startuml
class Order {
  +id: UUID
  +total: Money
}
Order o-- OrderLine
@enduml
```

<!-- Explicitly disable mode toggle for this diagram -->
```kroki hideDiagramModeToggle imgType="plantuml"
@startuml
...
@enduml
```

<!-- Explicitly disable auto legend for this diagram -->
```kroki showDiagramModeToggle hideDiagramLegend imgType="plantuml"
@startuml
...
@enduml
```

External file source with src

You can load diagram source from a local .puml file by setting src="..." on the kroki code block.

  • src is currently supported for imgType="plantuml"
  • src is resolved relative to the current Markdown/MDX file
  • only local .puml files are supported for src
  • the source tab shows the loaded file content (not internal wrapper code)

Example:

```kroki imgType="plantuml" imgTitle="Order model" src="order-model.puml"
```

The a11yDescriptionOverride attribute is useful when:

  • The diagram type is not yet supported for automatic description generation
  • You want to provide a more context-specific description
  • The automatic description doesn't capture the intended meaning

Accessibility

This plugin improves diagram accessibility by:

  1. Providing source code - Screen readers can read the diagram syntax (PlantUML, Mermaid, etc.) which describes the structure
  2. Generating natural language descriptions - For supported diagram types, creates human-readable text descriptions
  3. Keyboard navigation - Uses native <details> elements accessible via keyboard
  4. Config simplification - One remark plugin entry handles both a11y enrichment and Kroki rendering

Documentation Site

This plugin includes a live documentation site built with Docusaurus that besides documenting the plugin also demonstrates all features with working examples.

Running Locally

# From the repository root:
./start-docs.sh

# Or manually:
cd test-docusaurus-site
npm install  # first time only
npm start

The documentation site will be available at http://localhost:3001/remark-kroki-a11y/.

Online Documentation

πŸ“– Live documentation: bartvanderwal.github.io/remark-kroki-a11y

CI/CD Pipeline

The documentation site is automatically built and deployed to GitHub Pages on every push to main.

The pipeline:

  1. Copies hybrid documentation (README, CONTRIBUTING, ADRs) with Docusaurus front-matter
  2. Builds the Docusaurus site with the remark-kroki-a11y plugin
  3. Deploys to GitHub Pages

Single Source of Truth

The README.md and CONTRIBUTING.md files are maintained in the repository root for GitHub visibility. These files are automatically copied to the Docusaurus docs folder by start-docs.sh (with added front-matter for Docusaurus).

Important: Do NOT add Docusaurus-specific front-matter (the --- YAML block) to these root files, as they need to render correctly on GitHub. The start-docs.sh script adds the necessary front-matter when copying.

Meta: Eating Our Own Dog Food

This project has a delightful meta aspect: we build an accessibility plugin for "diagrams-as-code" in Docusaurus, and we use Docusaurus with those same diagrams to document the plugin itself.

Strategy Pattern class diagram example

The technical domain: The plugin operates in the landscape of Markdown, HTML generation, and diagram-as-code syntaxes (PlantUML, Mermaid). We use these same tools to document the plugin's architecture with C4 diagrams, class diagrams, and sequence diagrams.

The problem domain: We address accessibility (a11y) for visual diagrams - a challenge driven by both the continuous documentation movement in software engineering and broader societal/legal requirements like WCAG and the European Accessibility Act.

To see a more concrete example check the Docusaurus page with diagrams and documentation for this plugin itself. We also use that to test/validate our own plugin.

In short: A plugin that makes software diagrams accessible, and uses diagrams to explain how we do that (and these then test/validate if we are succeeding).

Acknowledgments

This plugin was originally conceived by Remco Veurink, lecturer at HAN University of Applied Sciences.

Related Work

The Mermaid project is also exploring accessibility for diagram-as-code. As noted in their accessibility discussion:

While I recognize that this is not going to be easy, I also believe that Mermaid is uniquely situated to solve this problem. The entire concept of Mermaid is that we can represent this visual content as plain structured text. Mermaid diagrams aren't just static images generated in Photoshop; they are rendered dynamically from structured data.

This insight applies equally to PlantUML and other diagram-as-code formats - the structured source text is inherently accessible, we just need to present it properly.

Contributing

Want to help? Or update and run this plugin itself? See CONTRIBUTING.md for local development setup and publishing tips.

For quality standards and acceptance criteria, see the Definition of Done.

License

MIT

Footnotes

  1. Mermaid has no Activity Diagram; use Flowchart instead. ↩

  2. PlantUML C4 support via the C4-PlantUML extension. ↩

About

A plugin that makes software diagrams accessible, and uses diagrams to explain how we do that (and test/validate if we are succeeding πŸ˜‰).

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors