Skip to content

Bannermedia-ltd/lexical-ghost-text

@scrivenmark/lexical-ghost-text

Inline ghost text (autocomplete suggestions) plugin for Lexical.

CI npm License: MIT

Renders translucent suggestion text at the cursor position inside a Lexical editor. Tab accepts, Escape dismisses.

Installation

# pnpm
pnpm add @scrivenmark/lexical-ghost-text

# npm
npm install @scrivenmark/lexical-ghost-text

# yarn
yarn add @scrivenmark/lexical-ghost-text

Quick start

import { useRef } from 'react'
import { LexicalComposer } from '@lexical/react/LexicalComposer'
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
import { ContentEditable } from '@lexical/react/LexicalContentEditable'
import {
  GhostTextNode,
  GhostTextPlugin,
  GhostTextHandle,
} from '@scrivenmark/lexical-ghost-text'
import '@scrivenmark/lexical-ghost-text/styles.css'

const initialConfig = {
  namespace: 'MyEditor',
  nodes: [GhostTextNode],
  onError: (err: Error) => { throw err },
}

export function Editor() {
  const ghostRef = useRef<GhostTextHandle>(null)

  function handleKeyUp() {
    // Supply a suggestion however you like
    ghostRef.current?.showSuggestion('world')
  }

  return (
    <LexicalComposer initialConfig={initialConfig}>
      <RichTextPlugin
        contentEditable={<ContentEditable onKeyUp={handleKeyUp} />}
        placeholder={<div>Start typing…</div>}
        ErrorBoundary={LexicalErrorBoundary}
      />
      <GhostTextPlugin
        onReady={(handle) => { ghostRef.current = handle }}
      />
    </LexicalComposer>
  )
}

API reference

GhostTextNode

Extends DecoratorNode. Inline, non-selectable. Renders with aria-hidden="true" so screen readers ignore the suggestion.

Apply custom styles via config.theme.ghostText (defaults to the class lexical-ghost-text).

$createGhostTextNode(suggestion: string)

Factory function. Creates a GhostTextNode with the given text.

$isGhostTextNode(node: unknown): node is GhostTextNode

Type guard.

SerializedGhostTextNode

Serialisation type for GhostTextNode.

GhostTextPlugin

React component. Must be placed inside a LexicalComposer.

Prop Type Description
onReady (handle: GhostTextHandle) => void Optional. Called once the plugin is mounted, providing the imperative handle.

GhostTextHandle

Imperative handle returned via onReady.

Method Signature Description
showSuggestion (text: string) => void Insert or replace the ghost text at the cursor.
dismissSuggestion () => void Remove the ghost text node if present.
hasSuggestion () => boolean Returns true if a ghost text node is currently active.

GhostTextPluginProps

interface GhostTextPluginProps {
  onReady?: (handle: GhostTextHandle) => void
}

Styling

Import the default stylesheet:

import '@scrivenmark/lexical-ghost-text/styles.css'

Or target the CSS class yourself (set via theme.ghostText in your editor config, defaults to lexical-ghost-text):

.lexical-ghost-text {
  color: #9ca3af;
  pointer-events: none;
  user-select: none;
}

Keyboard shortcuts

Key Action
Tab Accept suggestion — replaces ghost text with real text
Escape Dismiss suggestion
Any other key Dismiss suggestion

Peer dependencies

Package Version
lexical ^0.40.0
@lexical/react ^0.40.0
react ^18.0.0 || ^19.0.0

Contributing

See CONTRIBUTING.md.

Licence

MIT © Lettergraph

About

Lexical plugin for inline ghost text suggestions with Tab to accept and Esc to dismiss

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors