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

@sugar-high/react

v2.4.1

Published

Lightweight React code blocks and editors powered by Sugar High

Readme

@sugar-high/react

Lightweight React code blocks and editors powered by Sugar High.

Install

npm install @sugar-high/react react

Editor

import { Editor } from '@sugar-high/react'

<Editor
  lang="typescript"
  title="app.tsx"
  value="const App = () => <main>Hello</main>"
  onChange={console.log}
/>

Press Tab or Shift+Tab to indent or outdent the caret or selected lines. Customize the indentation string and underlying textarea attributes with indent and textareaProps:

<Editor
  indent="\t"
  textareaProps={{ 'aria-label': 'Source code', autoCapitalize: 'off' }}
  value={source}
  onChange={setSource}
/>

FileTree

Compose file navigation with Editor or Code. The parent owns the files and selected path; the tree owns folder expansion and keyboard focus.

import { useState } from 'react'
import { Editor, FileTree } from '@sugar-high/react'

export function FilesExample() {
  const [files, setFiles] = useState<Record<string, string>>({
    'src/index.ts': 'export const greeting = "Hello"',
    'src/styles.css': 'body { margin: 0; }',
  })
  const [activeFile, setActiveFile] = useState('src/index.ts')

  return (
    <div style={{ display: 'grid', gridTemplateColumns: '180px minmax(0, 1fr)' }}>
      <FileTree paths={Object.keys(files)} activeFile={activeFile} onActiveFileChange={setActiveFile} />
      <Editor title={activeFile} value={files[activeFile]}
        onChange={code => setFiles(current => ({ ...current, [activeFile]: code }))} />
    </div>
  )
}

Replace Editor with <Code title={activeFile}>{files[activeFile]}</Code> for read-only viewing. Pass the same theme to the tree and document for matching colors. Layout is ordinary CSS.

paths, activeFile (string | null), and onActiveFileChange(path) are required. Paths are relative, slash-separated file names; folders are inferred and initially expanded. Duplicates are removed. Empty paths, leading/trailing slashes, empty segments, and . / .. segments are ignored. Callbacks preserve the supplied file path. Folders sort before files. If files are removed, the parent should update its selection; the tree does not select another file automatically.

Arrow keys navigate and expand/collapse folders; Home/End move to the first/last visible item. Enter or Space selects a file or toggles a folder. Typing a name moves focus to a matching item. FileTree accepts standard div attributes, an accessible label (default “Files”), and theme. Style it through data-sh-file-tree and the existing --sh-* theme variables. Document cursor, scroll, and undo history are not managed by the tree.

Code

import { Code } from '@sugar-high/react'

<Code lang="python" title="main.py" lineNumbers cx={{ keyword: 'font-bold' }}>
  {'def hello():\n    return "world"'}
</Code>

For excerpts from larger files, set the first displayed line number. Long lines wrap by default; disable wrapping to use horizontal scrolling instead. Both options also work with Editor. At the same font and width, Code and Editor use the same wrapping rules. Empty lines retain a full line height. fontSize applies to source text and filename headers in both components.

Set editor typography once on the root; the textarea and highlighted code inherit it together:

<Editor value={code} onChange={setCode} style={{ fontSize: 14, lineHeight: 1.6 }} />

You can also set these styles through className, or use the existing fontSize and fontFamily props. The default editor line height is 1.5.

The browser layout suite runs with pnpm --filter @sugar-high/react test:browser after building the package. It uses Node's test runner and an installed agent-browser CLI, without a site server. It checks typography, blank lines, wrapping, horizontal overflow, and highlighted character positions against a plain-text mirror of the textarea at multiple widths. CI installs a pinned CLI and runs the suite in a separate job on pushes to main, including merged PRs. PR checks skip this job; locally the suite skips if the CLI is absent.

<Code lineNumbers startingLineNumber={40} wrapLongLines={false}>
  {source}
</Code>

Experimental WebGPU highlighting

Import the opt-in client components from @sugar-high/react/gpu for large code blocks or editors. They use gpu-lexer asynchronously and do not load the GPU model from the default React entry.

npm install @sugar-high/react react gpu-lexer
'use client'

import { Code, Editor } from '@sugar-high/react/gpu'

<Code lineNumbers>{largeSource}</Code>
<Editor value={source} onChange={setSource} />

The components render synchronized plain text while the GPU initializes. Their nested code view sets data-sh-gpu to pending, ready, or unavailable; when WebGPU is unavailable, the plain text remains readable and editable. GPU highlighting is language-agnostic, so lang and extension are accepted only for compatibility and do not affect inference. All other Code and Editor layout, theme, line-number, and display-hook props continue to work.

lang takes a canonical Sugar High language name. When omitted, title or the legacy extension prop is resolved through Sugar High's language aliases.

Select languages and render on the server

Use @sugar-high/react/core when you only need a few languages or want a server-compatible static code block. Import each language configuration explicitly and pass it through lang:

import { Code } from '@sugar-high/react/core'
import * as python from 'sugar-high/lang/python'

<Code lang={python} title="main.py" lineNumbers>
  {'def hello():\n    return "world"'}
</Code>

The core React entry does not include the complete language registry or a client directive. The default entry remains the convenient choice when string language names and title-based detection are more important than selecting the smallest bundle.

Headless highlighting

Highlight keeps parsing and generated token properties while giving you complete control over the markup. It is server-compatible and accepts the same selective language imports, cx, mark, and markLine options as core Code.

import { Highlight } from '@sugar-high/react/core'
import * as typescript from 'sugar-high/lang/typescript'

<Highlight
  code={source}
  lang={typescript}
  markLine={(line) => {
    if (line.annotations.includes('focus')) line.properties['data-focus'] = true
  }}
  render={({ lines }) => (
    <pre>
      {lines.map((line, index) => (
        <div key={index} {...line.properties}>
          {line.tokens.map((token, tokenIndex) => (
            <span key={tokenIndex} {...token.properties}>
              {token.value}
            </span>
          ))}
        </div>
      ))}
    </pre>
  )}
/>

The result is not limited to code-block markup. For example, render each generated line as a table row for a diff or virtualized viewer:

<Highlight
  code={source}
  lang={typescript}
  render={({ lines }) => (
    <table>
      <tbody>
        {lines.map((line, index) => (
          <tr key={index}>
            <th>{index + 1}</th>
            <td>{line.tokens.map((token) => token.value).join('')}</td>
          </tr>
        ))}
      </tbody>
    </table>
  )}
/>

Use the data-sh-* attributes and --sh-* variables for new styles. The package temporarily preserves Codice's existing data-codice-* attributes so existing structural selectors can migrate incrementally.

Themes

Pass a JavaScript theme to Code or Editor. Paired themes follow the inherited CSS color-scheme, so system and application theme changes do not require a React rerender:

import { Editor } from '@sugar-high/react'
import { taffy } from '@sugar-high/react/themes'

<Editor theme={taffy} value={source} onChange={setSource} />

Enable automatic light and dark selection at the application root. Force a scheme by setting color-scheme to only light or dark on any ancestor:

:root {
  color-scheme: light dark;
}

:root[data-theme='light'] {
  color-scheme: light;
}

:root[data-theme='dark'] {
  color-scheme: dark;
}

Available themes are taffy, vercel, vscode, oneDarkPro, monokai, minimal, gruvbox, tokyoNight, nordLight, and softMinimal. The last two are light-only palettes; the others provide light and dark colors. vercel is adapted from the official Geist Code Block palette.

A single palette stays the same in light and dark color schemes. Custom themes use the same token names as Sugar High. background and foreground are required; tokens that are not set inherit foreground:

import type { Theme } from '@sugar-high/react'

const ocean = {
  background: '#0f172a',
  foreground: '#e2e8f0',
  keyword: '#f472b6',
  string: '#86efac',
  comment: '#64748b',
  property: '#7dd3fc',
} satisfies Theme

<Code theme={ocean}>{source}</Code>

Use { light, dark } only when the theme should adapt to the inherited color scheme. Optional component colors are caret, title, control, lineNumber, and lineHighlight.

Low-level styling

Set Sugar High variables on the component itself for a self-contained theme:

const style = {
  backgroundColor: '#f6f8fa',
  '--sh-editor-background-color': 'transparent',
  '--sh-caret-color': '#24292f',
  '--sh-title-color': '#57606a',
  '--sh-control-color': '#afb8c1',
  '--sh-line-number-color': '#8c959f',
  '--sh-line-highlight-color': '#fff8c5',
  '--sh-keyword': '#cf222e',
  '--sh-string': '#0a3069',
} as React.CSSProperties

<Editor style={style} value={source} onChange={setSource} />

The --sh-* variables control both the component frame and syntax tokens; see the theme guide.

| Variable | Applies to | Default | Purpose | | --- | --- | --- | --- | | --sh-editor-text-color | Editor | transparent | Textarea text color; normally transparent over highlighted code. | | --sh-editor-background-color | Editor | transparent | Textarea background color. | | --sh-caret-color | Both | CanvasText | Editor caret and editable title caret. | | --sh-font-family | Both | Editor: Consolas, Monaco, monospace; Code: inherited | Code, textarea, and title font family. | | --sh-font-size | Both | inherit | Code and textarea font size. | | --sh-padding | Both | 1rem | Shared content and header spacing. | | --sh-line-number-width | Both | 2.5rem, expanding for 4+ digits | Line-number gutter width. Prefer lineNumbersWidth for an explicit override. | | --sh-control-color | Both | unset | Header control-dot color. | | --sh-title-color | Both | unset | Header filename color. | | --sh-line-number-color | Both | unset | Line-number color. | | --sh-line-highlight-color | Both | unset | Background for lines selected by highlightLines. |

The editor is a textarea layered over highlighted code. Keep --sh-editor-text-color and --sh-editor-background-color transparent unless deliberately changing that overlay; set the root's ordinary color and backgroundColor for the visible surface.

New styles should select component structure through the data-sh-* attributes. Component roots retain data-codice, data-codice-code, or data-codice-editor compatibility attributes during the Codice migration. Both components also accept standard div attributes.