@promptfarm/prompt-editor
v0.3.4
Published
A React component for building structured AI prompts using a Notion-like block editor powered by TipTap. Supports live compilation to `.prompt.md` format, variable interpolation, block toggling, and a clean light UI.
Readme
@promptfarm/prompt-editor
A React component for building structured AI prompts using a Notion-like block editor powered by TipTap. Supports live compilation to .prompt.md format, variable interpolation, block toggling, and a clean light UI.
Built-in features: slash command menu (/ to add blocks), drag-and-drop reordering, enable/disable toggles, structured inputs for example blocks, copy to clipboard, and a run button.
Install
npm install @promptfarm/prompt-editor
# peer deps
npm install react react-dom lucide-reactQuick start
import { useState } from "react";
import {
PromptEditor,
VariablesBar,
CompiledOutput,
useCompiledText,
} from "@promptfarm/prompt-editor";
import "@promptfarm/prompt-editor/styles.css";
import type { EditorSegment, Variable } from "@promptfarm/prompt-editor";
export function App() {
const [segments, setSegments] = useState<EditorSegment[]>([]);
const [variables, setVariables] = useState<Variable[]>([]);
const compiledText = useCompiledText(segments, variables);
return (
<div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", height: "100vh" }}>
<div style={{ display: "flex", flexDirection: "column" }}>
<VariablesBar
variables={variables}
onChange={setVariables}
className="border-b border-gray-200"
/>
<PromptEditor
onChange={(_text, _blocks, segs) => setSegments(segs)}
className="flex-1"
/>
</div>
<CompiledOutput
compiledPrompt={compiledText}
onRun={(prompt) => console.log("Run:", prompt)}
className="border-l border-gray-200"
/>
</div>
);
}Block types
| Block | Slash command | Description |
|---|---|---|
| Role | /role | Define the AI persona |
| Context | /context | Background info or framing |
| Task | /task | Main instruction |
| Example | /example | Few-shot input/output pair (structured: two fields) |
| Output Format | /output_format | Expected response structure |
| Constraint | /constraint | Rules or restrictions |
Components
<PromptEditor>
The main TipTap-based editor. Type / to open the block picker menu.
<PromptEditor
value="" // optional — initial content
onChange={(text, blocks, segments) => {}}
className="my-editor" // optional
/>| Callback arg | Type | Description |
|---|---|---|
| text | string | Plain text content of the editor |
| blocks | EditorBlock[] | All prompt blocks with kind, content, enabled state |
| segments | EditorSegment[] | Ordered segments (text + blocks) matching document order |
<CompiledOutput>
Renders the compiled prompt with colored section headings, a copy button, and an optional run button.
<CompiledOutput
compiledPrompt={compiledText} // the compiled prompt.md string
onRun={(prompt) => sendToModel(prompt)} // optional — adds a Run button
className="border-l border-gray-200" // optional
/><VariablesBar>
A bar for managing {{variable}} values. Variables are replaced in the compiled output.
<VariablesBar
variables={variables} // Variable[]
onChange={setVariables} // (variables: Variable[]) => void
onInsert={(name) => {}} // optional — called when a variable pill is clicked
className="border-b" // optional
/><CopyButton>
A standalone copy-to-clipboard button with a checkmark animation.
import { CopyButton } from "@promptfarm/prompt-editor";
<CopyButton text={compiledPrompt} />Hooks
useCompiledText(segments, variables?)
Compiles editor segments into a .prompt.md formatted string with variable interpolation. Merges consecutive blocks of the same kind and handles structured fields (e.g., example input/output).
import { useCompiledText } from "@promptfarm/prompt-editor";
const compiledText = useCompiledText(segments, variables);| Param | Type | Description |
|---|---|---|
| segments | EditorSegment[] | Ordered segments from PromptEditor's onChange |
| variables | Variable[] | Optional — variables to substitute {{name}} placeholders |
| returns | string | Compiled prompt in ## Heading format |
Types
EditorBlock
interface EditorBlock {
id: string;
kind: BlockKind;
content: string;
enabled: boolean;
fields?: Record<string, string>; // structured fields (e.g., example: input/output)
}EditorSegment
type EditorSegment =
| { type: "text"; content: string }
| { type: "block"; block: EditorBlock };Variable
type Variable = {
name: string;
value: string;
};BlockKind
type BlockKind = "role" | "context" | "task" | "example" | "output_format" | "constraint";Core utilities (from @promptfarm/editor-core)
These are re-exported from the prompt-editor package.
compile(blocks, variables?)
Compiles blocks into a prompt string with variable interpolation.
import { compile } from "@promptfarm/prompt-editor";
const { text, tokenCount, activeBlockCount } = compile(blocks, variables);compileToPromptMd(blocks)
Compiles blocks into .prompt.md format with YAML frontmatter.
import { compileToPromptMd } from "@promptfarm/prompt-editor";
const md = compileToPromptMd(blocks);
// ---
// name: You are a helpful assistant
// description:
// ---
//
// ## Role
// You are a helpful assistant
//
// ## Task
// Answer the user's questionparsePromptMd(md)
Parses a .prompt.md string back into blocks.
import { parsePromptMd } from "@promptfarm/prompt-editor";
const blocks = parsePromptMd(fileContent);createBlock(kind)
Factory that returns a fresh block with a unique ID.
import { createBlock } from "@promptfarm/prompt-editor";
const block = createBlock("context");Compiled output format
The compiled prompt uses markdown headings with block colors preserved in the UI:
## Role
You are a helpful assistant
## Context
The user is building a web app
## Task
Help them debug their CSS
## Example
Input: my div won't center
Output: Use flexbox: display: flex; justify-content: center; align-items: center;Theming
Import the stylesheet. The editor uses a light theme by default. Override styles on .pe-root:
.pe-root {
color-scheme: light;
font-family: "IBM Plex Sans", "Inter", ui-sans-serif, system-ui, sans-serif;
}Block colors are defined in BLOCK_COLORS and can be accessed for custom rendering:
import { BLOCK_COLORS, BLOCK_LABELS } from "@promptfarm/prompt-editor";
BLOCK_COLORS.role // "#7F77DD"
BLOCK_COLORS.context // "#1D9E75"
BLOCK_COLORS.task // "#378ADD"
BLOCK_COLORS.example // "#D4537E"
BLOCK_COLORS.output_format // "#EF9F27"
BLOCK_COLORS.constraint // "#E24B4A"License
This repository is licensed under PolyForm Noncommercial 1.0.0.
Commercial use is not permitted without a separate commercial agreement. See LICENSE.md.
