npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-custom-syntax

v1.0.0

Published

A lightweight, customizable React syntax editor with rule-based highlighting, prettification, and plugin support

Readme

react-custom-syntax

⚠️ Warning: This library is in active development and is NOT ready for production use. This project is subject to breaking changes and may undergo significant modifications. Please review the CHANGELOG.md for the latest updates and breaking changes. Use at your own risk.

📖 Live Documentation & Interactive Playground: Explore the full interactive documentation with live examples at react-custom-syntax.trugraph.io or react-custom-syntax.vercel.app

A lightweight, customizable React syntax editor with rule-based highlighting, prettification, and plugin support. Define any custom language syntax using JSON configuration.

npm version License: MIT GitHub stars GitHub forks GitHub issues GitHub Release Date GitHub code size in bytes Release Code Quality Beta Code Quality

A lightweight, customizable React syntax editor with rule-based highlighting, prettification, and plugin support. Define any custom language syntax using JSON configuration.

Features

  • 🎨 Rule-Based Syntax Highlighting - Define highlighting rules via JSON configuration
  • 🔧 Fully Customizable - Control styles, colors, classNames, and behavior
  • 📦 Lightweight - Zero runtime dependencies (React as peer dependency)
  • 🔌 Plugin System - Extend functionality with custom plugins
  • 💅 Themeable - CSS variables for easy theming
  • 📝 TypeScript Support - Full type definitions included
  • Built-in Prettifier - Format queries with proper indentation
  • 🎯 OData Config Included - Ready-to-use OData syntax configuration

Installation

npm install react-custom-syntax
# or
yarn add react-custom-syntax
# or
pnpm add react-custom-syntax

Quick Start

import { useState } from 'react'
import { CustomSyntaxEditor, ConfigManager, odataConfig } from 'react-custom-syntax'

function App() {
  const [value, setValue] = useState('')
  const configManager = new ConfigManager(odataConfig)

  const handleChange = e => {
    setValue(e.target.value)
  }

  return (
    <CustomSyntaxEditor
      value={value}
      onChange={handleChange}
      configManager={configManager}
      headerLabel="OData Query Editor"
    />
  )
}

Note: Styles are automatically included via CSS modules. No separate import required. CSS variables are available for theming customization.

Custom Language Configuration

Define your own syntax by creating a JSON configuration:

{
  "version": "1.0.0",
  "description": "Custom SQL-like syntax",
  "highlightingRules": [
    {
      "name": "Keywords",
      "matchType": "keyword",
      "caseSensitive": false,
      "addWordBoundaries": true,
      "tokens": [
        {
          "keyword": "SELECT",
          "type": "SqlKeyword",
          "description": "Select statement"
        },
        {
          "keyword": "FROM",
          "type": "SqlKeyword",
          "description": "From clause"
        }
      ]
    },
    {
      "name": "Strings",
      "matchType": "regex",
      "pattern": "'([^']*)'",
      "replacement": "<span class='rcse-literal'>'$1'</span>",
      "type": "StringLiteral"
    }
  ],
  "types": [
    {
      "className": "SqlKeyword",
      "highlightColor": "#569cd6",
      "parentType": "Keyword",
      "fontWeight": "600"
    },
    {
      "className": "StringLiteral",
      "highlightColor": "#ce9178",
      "parentType": "Literal",
      "fontWeight": "normal"
    }
  ]
}

Then use it:

import customConfig from './customSyntax.json'

const configManager = new ConfigManager(customConfig)

;<CustomSyntaxEditor value={value} onChange={handleChange} configManager={configManager} />

API Reference

CustomSyntaxEditor Props

| Prop | Type | Default | Description | | ----------------------- | --------------------- | ----------------------- | ---------------------------- | | value | string | Required | Current editor value | | onChange | (event) => void | Required | Change handler | | configManager | ConfigManager | undefined | Custom configuration manager | | disabled | boolean | false | Disable the editor | | showHeader | boolean | true | Show/hide header | | headerLabel | string | 'Syntax Editor' | Header label text | | headerLinks | HeaderLink[] | [] | Documentation links | | showCopyButton | boolean | true | Show copy button | | showPrettifyButton | boolean | true | Show prettify button | | copyButtonLabel | string | 'Copy' | Copy button label | | prettifyButtonLabel | string | 'Prettify' | Prettify button label | | placeholder | string | 'Enter your query...' | Placeholder text | | className | string | undefined | Custom container class | | style | CSSProperties | undefined | Inline styles | | classNames | CustomClassNames | {} | Custom class names | | styles | CustomStyles | {} | Custom inline styles | | onCopy | (value) => void | undefined | Custom copy handler | | onPrettify | (value) => void | undefined | Custom prettify handler | | notificationHandler | NotificationHandler | undefined | Custom notifications | | disableStyleInjection | boolean | false | Disable CSS injection |

Core Classes

ConfigManager

import { ConfigManager } from 'react-custom-syntax'

const config = new ConfigManager(syntaxConfig)

// Get keywords by type
config.getOperatorKeywords()
config.getFunctionKeywords()
config.getCustomTokenKeywords()

// Token information
config.getTokenInfo('and')
config.hasKeyword('contains')

// Generate CSS
const css = config.generateCSS()

// Load from URL
const manager = await ConfigManager.fromURL('https://example.com/syntax.json')

SyntaxHighlighter

import { SyntaxHighlighter } from 'react-custom-syntax'

const highlighter = new SyntaxHighlighter(configManager)
const highlighted = highlighter.highlight('status eq true')

Prettifier

import { Prettifier } from 'react-custom-syntax'

const prettifier = new Prettifier(configManager)
const formatted = prettifier.prettify('status eq true and priority gt 5')

// Configure max line length
prettifier.setMaxLineLength(100)

IdentifierExtractor

import { IdentifierExtractor } from 'react-custom-syntax'

const extractor = new IdentifierExtractor(configManager)
const identifiers = extractor.extract('status eq true and priority gt 5')
// Returns: ['status', 'priority']

Plugins

Extend functionality with custom plugins using lifecycle hooks:

import type { Plugin } from 'react-custom-syntax'

// Example: Logging plugin
const loggingPlugin: Plugin = {
  name: 'logging',
  beforeHighlight: text => {
    console.log('Highlighting text:', text)
    return text
  },
  afterHighlight: (highlightedHtml, originalText) => {
    console.log('Highlighted to:', highlightedHtml)
    return highlightedHtml
  },
  beforePrettify: text => {
    console.log('Prettifying text:', text)
    return text
  },
  afterPrettify: (prettifiedText, originalText) => {
    console.log('Prettified to:', prettifiedText)
    return prettifiedText
  }
}

See the Plugins section for more details.

Styling and Theming

CSS Variables

Override these CSS variables to customize the theme:

:root {
  --rcse-bg-primary: #1e1e1e;
  --rcse-bg-secondary: #2d2d2d;
  --rcse-border-color: #404040;
  --rcse-text-primary: #d4d4d4;
  --rcse-text-secondary: #666;
  --rcse-accent-primary: #1976d2;
  --rcse-accent-hover: #264f78;
  --rcse-font-mono: 'Consolas', 'Monaco', 'Courier New', monospace;
}

Custom Class Names

<CustomSyntaxEditor
  value={value}
  onChange={handleChange}
  classNames={{
    container: 'my-container',
    header: 'my-header',
    editor: 'my-editor'
  }}
/>

Custom Inline Styles

<CustomSyntaxEditor
  value={value}
  onChange={handleChange}
  styles={{
    container: { borderRadius: '12px' },
    editor: { fontSize: '16px' }
  }}
/>

Advanced Usage

Custom Notification Handler

import { toast } from 'react-toastify'

const notificationHandler = {
  success: msg => toast.success(msg),
  warning: msg => toast.warning(msg),
  error: msg => toast.error(msg)
}

;<CustomSyntaxEditor value={value} onChange={handleChange} notificationHandler={notificationHandler} />

Custom Copy/Prettify Handlers

<CustomSyntaxEditor
  value={value}
  onChange={handleChange}
  onCopy={value => {
    navigator.clipboard.writeText(value)
    console.log('Copied:', value)
  }}
  onPrettify={prettified => {
    console.log('Prettified:', prettified)
  }}
/>

Header Links

<CustomSyntaxEditor
  value={value}
  onChange={handleChange}
  headerLinks={[
    {
      href: 'https://docs.example.com',
      label: 'Documentation',
      title: 'View documentation'
    }
  ]}
/>

Configuration Schema

Highlighting Rules

Two types of matching are supported:

1. Keyword Matching

{
  "name": "Operators",
  "matchType": "keyword",
  "caseSensitive": false,
  "addWordBoundaries": true,
  "tokens": [{ "keyword": "and", "type": "LogicalOperator", "description": "AND operator" }]
}

2. Regex Matching

{
  "name": "Strings",
  "matchType": "regex",
  "pattern": "'([^']*)'",
  "replacement": "<span class='rcse-literal'>'$1'</span>",
  "type": "StringLiteral"
}

Type Styles

{
  "className": "LogicalOperator",
  "highlightColor": "#569cd6",
  "parentType": "Operator",
  "fontWeight": "600"
}

Examples

Live Examples

Check out the examples directory for a showcase app with multiple examples:

# Build the main package
npm run build

# Navigate to examples
cd docs

# Install dependencies
npm install

# Run the showcase
npm run dev

The showcase includes:

OData Query Editor

import { useState } from 'react'
import { CustomSyntaxEditor, ConfigManager, odataConfig } from 'react-custom-syntax'

function ODataEditor() {
  const [query, setQuery] = useState("status eq 'Active' and priority gt 5")
  const configManager = new ConfigManager(odataConfig)

  return (
    <CustomSyntaxEditor
      value={query}
      onChange={e => setQuery(e.target.value)}
      configManager={configManager}
      headerLabel="OData Query Editor"
      headerLinks={[
        {
          href: 'https://azuresearch.github.io/odata-syntax-diagram',
          label: 'OData Syntax Reference'
        }
      ]}
    />
  )
}

Read-Only Display

<CustomSyntaxEditor value={savedQuery} onChange={() => {}} disabled={true} configManager={configManager} />

Minimal Editor (No Header)

<CustomSyntaxEditor value={value} onChange={handleChange} showHeader={false} configManager={configManager} />

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

Next.js Compatibility

This library uses client-side features (contentEditable, clipboard API). All components are marked with 'use client' directive and will work seamlessly in Next.js App Router.

// In your Next.js app router component
'use client'

import { CustomSyntaxEditor, ConfigManager, odataConfig } from 'react-custom-syntax'

export default function Page() {
  const configManager = new ConfigManager(odataConfig)
  // ... rest of your code
}

Development

Running Tests

npm run test          # Run tests once
npm run test:watch    # Run tests in watch mode
npm run test:coverage # Run tests with coverage report

Coverage reports are generated in:

  • Terminal: Text summary
  • coverage/index.html: Interactive HTML report (open in browser)
  • coverage/coverage-final.json: JSON data

License

MIT © Mohamed Elbaz

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.