Skip to content

grnet/rspress-plugin-terminology

@grnet/rspress-plugin-terminology

A plugin for Rspress that enables terminology management with hover tooltips and auto-generated glossaries.

This plugin is a port of @grnet/docusaurus-terminology for the Rspress static site generator.

Features

  • Term Definitions - Define terms in markdown files with frontmatter
  • Hover Tooltips - Display term definitions when hovering over links
  • Auto-Generated Glossary - Automatically create a glossary page with all terms
  • Customizable Components - Use built-in components or provide your own
  • Fast & Efficient - Pre-loads data during build, minimal runtime overhead
  • 🛡️ XSS Protection - Built-in security using DOMPurify sanitization

Installation

npm install @grnet/rspress-plugin-terminology --save
# or
yarn add @grnet/rspress-plugin-terminology
# or
pnpm add @grnet/rspress-plugin-terminology

Quick Start

Try the Example First!

The easiest way to see the plugin in action is to run the included example:

cd rspress-plugin-terminology

# Build the plugin
npm run build

# Install example dependencies
cd example
npm install

# Start the dev server
npm run dev

Then open http://localhost:3000 and:

  • Hover over linked terms to see tooltips
  • Visit the Glossary page
  • Explore the source code in docs/terms/

Using in Your Project

1. Configure the Plugin

Add the plugin to your rspress.config.ts:

import { defineConfig } from '@rspress/core';
import { terminologyPlugin } from '@grnet/rspress-plugin-terminology';

export default defineConfig({
  // ... other config
  plugins: [
    terminologyPlugin({
      termsDir: './docs/terms',           // Directory containing term definitions
      docsDir: './docs/',                  // Root documentation directory
      glossaryFilepath: './docs/glossary.md'  // Path to glossary page
    })
  ]
});

2. Create Term Definitions

Create markdown files in your docs/terms/ directory:

---
id: api-key
title: API Key
hoverText: A unique identifier used to authenticate a user or application.
---

An API key is a secret token that identifies the calling application or user. API keys are used to track and control how the API is being used, prevent malicious use, and calculate usage fees.

3. Create Glossary Page

Create docs/glossary.md:

---
title: Glossary
---

# Glossary

Welcome to the glossary. All terms from the documentation are listed below.

The plugin will automatically inject the <Glossary /> component into this file.

4. Use Terms in Your Documentation

Reference terms using standard markdown link syntax:

To use the API, you need an [API Key](./terms/api-key).

This will automatically be transformed into an interactive link with a hover tooltip.

Configuration

Options

Option Type Required Description
termsDir string Yes Directory containing term definition files (e.g., './docs/terms')
docsDir string Yes Root documentation directory (e.g., './docs/')
glossaryFilepath string Yes Path to glossary markdown file (e.g., './docs/glossary.md')
basePath string No Base path for the site (e.g., '/my-site'). Useful when hosting in a subdirectory.
termPreviewComponentPath string No Custom path to Term preview component
glossaryComponentPath string No Custom path to Glossary view component
debug boolean | object No Enable debug logging. See Debug Configuration below.

Example with Custom Components

terminologyPlugin({
  termsDir: './docs/terms',
  docsDir: './docs/',
  glossaryFilepath: './docs/glossary.md',
  termPreviewComponentPath: './components/CustomTerm.tsx',
  glossaryComponentPath: './components/CustomGlossary.tsx'
})

Example with Base Path

If your site is hosted in a subdirectory (e.g., https://example.com/docs/), use basePath:

terminologyPlugin({
  termsDir: './docs/terms',
  docsDir: './docs/',
  glossaryFilepath: './docs/glossary.md',
  basePath: '/docs'  // Links will be /docs/terms/term instead of /terms/term
})

Debug Configuration

The plugin includes a built-in debug logging utility to help troubleshoot issues.

Enable All Debug Logs

terminologyPlugin({
  termsDir: './docs/terms',
  docsDir: './docs/',
  glossaryFilepath: './docs/glossary.md',
  debug: true  // Enable all debug logs
})

Advanced Debug Configuration

terminologyPlugin({
  termsDir: './docs/terms',
  docsDir: './docs/',
  glossaryFilepath: './docs/glossary.md',
  debug: {
    enabled: true,
    timestamps: true,  // Include timestamps in logs
    namespaces: [      // Only log specific namespaces
      'build:*',       // All build operations
      'plugin:load'    // Plugin loading
    ]
  }
})

Using Environment Variables

You can also control debug logging via environment variable:

# Enable all debug logs
RSPRESS_TERMINOLOGY_DEBUG=1 npm run build

# Enable specific namespaces
RSPRESS_TERMINOLOGY_DEBUG=build:* npm run build

# Enable multiple namespaces (comma-separated)
RSPRESS_TERMINOLOGY_DEBUG=plugin:load,build:index npm run build

Available Namespaces

  • plugin - Main plugin lifecycle events
    • plugin:load - Loading glossary JSON
    • plugin:build - Build phase events
    • plugin:page - Page data extension
    • plugin:inject - HTML injection events
  • build - Build-time operations
    • build:index - Term indexing operations
    • build:glossary - Glossary JSON generation
    • build:inject - Component injection
    • build:copy - File copying operations

For more examples and detailed usage, see DEBUG_EXAMPLES.md.

Term Definition Format

Each term file should include:

---
id: unique-term-id        # Required: Unique identifier
title: Term Title          # Required: Display title
hoverText: Short definition shown on hover  # Optional: Hover text
---

Full term explanation and details here...

Frontmatter Fields

Field Type Required Description
id string Yes Unique identifier for the term
title string Yes Display title of the term
hoverText string No Short description shown on hover (supports markdown)

Custom Components

Custom Term Component

Create a custom term preview component:

// components/CustomTerm.tsx
import React from 'react';
import type { TermMetadata } from '@grnet/rspress-plugin-terminology';

interface CustomTermProps {
  pathName: string;
  children?: React.ReactNode;
}

export default function CustomTerm({ pathName, children }: CustomTermProps) {
  const [term, setTerm] = React.useState<TermMetadata | null>(null);

  React.useEffect(() => {
    fetch(`${pathName}.json`)
      .then(res => res.json())
      .then(setTerm);
  }, [pathName]);

  return (
    <span className="custom-term">
      <a href={pathName}>{children || term?.title}</a>
      {/* Custom tooltip implementation */}
    </span>
  );
}

Custom Glossary Component

// components/CustomGlossary.tsx
import React from 'react';
import type { TermMetadata } from '@grnet/rspress-plugin-terminology';

export default function CustomGlossary() {
  const [terms, setTerms] = React.useState<Record<string, TermMetadata>>({});

  React.useEffect(() => {
    fetch('/docs/glossary.json')
      .then(res => res.json())
      .then(setTerms);
  }, []);

  return (
    <div className="custom-glossary">
      <h1>Glossary</h1>
      {Object.entries(terms).map(([path, term]) => (
        <div key={path}>
          <a href={path}>{term.title}</a>
        </div>
      ))}
    </div>
  );
}

Styling

The plugin includes default styles. To customize, override these CSS classes:

Term Link Classes

  • .term-link - Base term link style
  • .term-link:hover - Hover state
  • .term-link-loading - Loading state
  • .term-link-error - Error state

Tooltip Classes

  • .rspress-plugin-terminology-tooltip - Tooltip container
  • .term-tooltip-content - Tooltip content wrapper
  • .term-title - Term title in tooltip
  • .term-hover-text - Hover text content

Glossary Classes

  • .glossary-container - Glossary wrapper
  • .glossary-item - Individual glossary entry
  • .glossary-term - Term title
  • .glossary-definition - Term definition

Custom Styles

Add custom styles in your Rspress theme:

/* src/styles/custom.css */
.term-link {
  text-decoration-style: dotted;
  color: #3b82f6;
}

.rspress-plugin-terminology-tooltip {
  max-width: 400px;
  padding: 16px;
}

How It Works

The plugin works in two phases:

Build Time: Scans your termsDir for markdown files, extracts frontmatter (id, title, hoverText), and generates JSON files for each term plus a master glossary.json. A remark plugin transforms markdown links into interactive <Term> components.

Runtime: Term components display tooltips on hover by fetching pre-generated JSON data. The Glossary component renders all terms in a sorted list. All HTML content is sanitized with DOMPurify to prevent XSS attacks.

Migration from Docusaurus

If you're migrating from @grnet/docusaurus-terminology:

Configuration Changes

Docusaurus:

module.exports = {
  plugins: [
    ['@grnet/docusaurus-terminology', {
      termsDir: './docs/terms',
      docsDir: './docs/',
      glossaryFilepath: './docs/glossary.md'
    }]
  ]
};

Rspress:

import { terminologyPlugin } from '@grnet/rspress-plugin-terminology';

export default defineConfig({
  plugins: [
    terminologyPlugin({
      termsDir: './docs/terms',
      docsDir: './docs/',
      glossaryFilepath: './docs/glossary.md'
    })
  ]
});

Component Changes

  • @docusaurus/BrowserOnly → No longer needed (client-side fetching handled internally)
  • @docusaurus/useBaseUrlusePageData() from rspress/runtime
  • @docusaurus/Link → Standard <a> tags (Rspress handles routing)

Development

Building

npm run build

Watch Mode

npm run dev

Testing

The project includes comprehensive security tests to verify XSS prevention:

# Run tests
npm test

# Run tests in watch mode
npm run test:watch

# Run tests with coverage
npm run test:coverage

See SECURITY.md for detailed security information.

Testing Locally

# Link your local version
npm link

# In your rspress project
npm link @grnet/rspress-plugin-terminology

Troubleshooting

Common issues and solutions:

  • Terms not showing: Verify term files have required frontmatter (id, title) and check browser console for errors
  • Tooltips not appearing: Ensure links use correct relative paths and check browser console
  • Glossary empty: Verify glossary.json is generated during build

For detailed help, see GitHub Discussions or open an issue.

License

BSD-2-Clause

Credits

Ported from @grnet/docusaurus-terminology

Original implementation for Docusaurus by GRNET Developers.

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.


Note: This is the Rspress version of the terminology plugin. For Docusaurus, see @grnet/docusaurus-terminology.

About

No description, website, or topics provided.

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages