
Security News
Free Certified Patch for Critical Rails Active Storage Vulnerability
Socket has released a free Certified Patch for a critical Rails Active Storage vulnerability, giving developers time to upgrade to a secure Rails version.
@handlewithcare/react-codemirror
Advanced tools
A simple library for safely integrating React and CodeMirror.
npm:
npm install @handlewithcare/react-codemirror
yarn:
yarn add @handlewithcare/react-codemirror
This library provides an API similar to that of
@handlewithcare/react-prosemirror
for integrating React with CodeMirror. The surface area is considerably smaller,
because CodeMirror has no notion of NodeViews. A future version of this library
may support React-based widgets and tooltips.
To get started, render the CodeMirror and CodeMirrorEditor components:
import { EditorState, type Transaction } from "@codemirror/state";
import { CodeMirror, CodeMirrorEditor } from "@handlewithcare/react-codemirror";
import { basicSetup } from "codemirror";
import React, { StrictMode, useCallback, useState } from "react";
const editorState = EditorState.create({ doc: "", basicSetup });
function CodeEditor() {
const [state, setState] = useState(editorState);
const dispatchTransactions = useCallback((trs: readonly Transaction[]) => {
setState(trs[trs.length - 1]!.state);
}, []);
return (
<CodeMirror
state={state}
dispatchTransactions={dispatchTransactions}
extensions={basicSetup}
>
<CodeMirrorEditor />
</CodeMirror>
);
}
The CodeMirrorEditor is where the actual CodeMirror editor will be
instantiated. It can be nested anywhere as a descendant of the CodeMirror
component.
The useCompartment hook can be used to configure dynamic CodeMirror
extensions. Here’s an example, using a simple language picker:
// LanguagePicker.tsx
import { htmlLanguage, html } from "@codemirror/lang-html";
import { language, type Language } from "@codemirror/language";
import { javascript, javascriptLanguage } from "@codemirror/lang-javascript";
interface Props {
value: Language;
onChange: (lang: Language) => void;
}
function LanguagePicker({ value, onChange }: Props) {
return (
<Select value={language} onChange={onChange}>
<Option value={htmlLanguage}>HTML</Option>
<Option value={javascriptLanguage}>JavaScript</Option>
</Select>
);
}
// CodeEditor.tsx
import { javascript } from "@codemirror/lang-javascript";
import { language } from "@codemirror/language";
import { EditorState, type Transaction } from "@codemirror/state";
import { CodeMirror, CodeMirrorEditor } from "@handlewithcare/react-codemirror";
import { basicSetup } from "codemirror";
import React, { StrictMode, useCallback, useState } from "react";
import { LanguagePicker } from "./LanguagePicker.tsx";
function CodeEditor() {
const [languageExt, reconfigureLanguage] = useCompartment(javascript());
const extensions = [basicSetup, languageExt];
const [state, setState] = useState(() =>
EditorState.create({ doc: "", extensions }),
);
const dispatchTransactions = useCallback((trs: readonly Transaction[]) => {
setState(trs[trs.length - 1]!.state);
}, []);
return (
<CodeMirror
state={state}
dispatchTransactions={dispatchTransactions}
extensions={extensions}
>
<LanguagePicker
value={state.facet(language)}
onChange={(lang) => reconfigureLanguage(lang)}
/>
<CodeMirrorEditor />
</CodeMirror>
);
}
The useEditorEventCallback hook is a more general purpose hook that allows
components that are descendants of the CodeMirror component to dispatch a
transaction or otherwise interact with the CodeMirror EditorView in an event
callback:
// AutocompleteButton.tsx
import { useEditorEventCallback } from "@handlewithcare/react-codemirror";
export function AutocompleteButton() {
const onClick = useEditorEventCallback(async (view) => {
const result = await fetchMagicAutoComplete(view.state.doc.toString());
view.dispatch({
changes: {
from: 0,
to: view.state.doc.size,
insert: result,
},
});
});
return <button onClick={onClick}>Autocomplete</button>;
}
// CodeEditor.tsx
import { EditorState, type Transaction } from "@codemirror/state";
import { CodeMirror, CodeMirrorEditor } from "@handlewithcare/react-codemirror";
import { basicSetup } from "codemirror";
import React, { StrictMode, useCallback, useState } from "react";
import { AutocompleteButton } from "./AutocompleteButton.tsx";
const editorState = EditorState.create({ doc: "", basicSetup });
function CodeEditor() {
const [state, setState] = useState(editorState);
const dispatchTransactions = useCallback((trs: readonly Transaction[]) => {
setState(trs[trs.length - 1]!.state);
}, []);
return (
<CodeMirror
state={state}
dispatchTransactions={dispatchTransactions}
extensions={basicSetup}
>
<AutocompleteButton />
<CodeMirrorEditor />
</CodeMirror>
);
}
CodeMirrorfunction CodeMirror(
props: Omit<EditorViewConfig, "parent"> & {
defaultState?: EditorState;
children: ReactNode;
},
): JSX.Element;
Provides the CodeMirror context.
Example usage:
import { EditorState, type Transaction } from "@codemirror/state";
import { CodeMirror, CodeMirrorEditor } from "@handlewithcare/react-codemirror";
import { basicSetup } from "codemirror";
const editorState = EditorState.create({ doc: "", basicSetup });
function CodeEditor() {
return (
<CodeMirror
defaultState={editorState}
dispatchTransactions={dispatchTransactions}
>
<CodeMirrorEditor />
</CodeMirror>
);
}
CodeMirrorEditorfunction CodeMirrorEditor(): JSX.Element;
Renders the actual editable CodeMirror editor.
This must be a descendant of the CodeMirror component. It may be wrapped
in other components, and other children may be passed before or after.
Example usage:
import { EditorState, type Transaction } from "@codemirror/state";
import { CodeMirror, CodeMirrorEditor } from "@handlewithcare/react-codemirror";
import { basicSetup } from "codemirror";
const editorState = EditorState.create({ doc: "", basicSetup });
function CodeEditor() {
return (
<CodeMirror
defaultState={editorState}
dispatchTransactions={dispatchTransactions}
>
<ToolBar />
<SomeWrapper>
<CodeMirrorEditor />
</SomeWrapper>
<Footnotes />
</CodeMirror>
);
}
useEditorStatefunction useEditorState(): EditorState;
Provides access to the current EditorState value.
useCompartmentfunction useCompartment(
initialExtension: Extension,
): readonly [Extension, (extension: Extension) => void];
Returns a compartment of the provided extension, and a method to reconfigure it.
Example usage:
import { javascript } from "@codemirror/lang-javascript";
import { language } from "@codemirror/language";
import { EditorState, type Transaction } from "@codemirror/state";
import { CodeMirror, CodeMirrorEditor } from "@handlewithcare/react-codemirror";
import { basicSetup } from "codemirror";
import React, { StrictMode, useCallback, useState } from "react";
import { LanguagePicker } from "./LanguagePicker.tsx";
function CodeEditor() {
const [languageExt, reconfigureLanguage] = useCompartment(javascript());
const extensions = [basicSetup, languageExt];
const [state, setState] = useState(() =>
EditorState.create({ doc: "", extensions }),
);
const dispatchTransactions = useCallback((trs: readonly Transaction[]) => {
setState(trs[trs.length - 1]!.state);
}, []);
return (
<CodeMirror
state={state}
dispatchTransactions={dispatchTransactions}
extensions={extensions}
>
<LanguagePicker
value={state.facet(language)}
onChange={(lang) => reconfigureLanguage(lang)}
/>
<CodeMirrorEditor />
</CodeMirror>
);
}
useEditorEventCallbackfunction useEditorEventcallback<T extends unknown[]>(
callback: (view: EditorView, ...args: T) => void,
): void;
Returns a stable function reference to be used as an event handler callback.
The callback will be called with the EditorView instance as its first argument.
useEditorEffectfunction useEditorEffect(
effect: (view: EditorView) => void | (() => void),
dependencies?: React.DependencyList,
): void;
Registers a layout effect to run after the EditorView has been updated with the latest EditorState.
Effects can take an EditorView instance as an argument. This hook should be used to execute layout effects that depend on the EditorView, such as for positioning DOM nodes based on CodeMirror positions.
Layout effects registered with this hook still fire synchronously after all DOM mutations, but they do so after the EditorView has been updated, even when the EditorView lives in an ancestor component.
Reach out to Handle with Care! We're a product development collective with years of experience bringing excellent ideas to life. We love React and ProseMirror, and we're always looking for new folks to work with!
FAQs
Unknown package
The npm package @handlewithcare/react-codemirror receives a total of 180 weekly downloads. As such, @handlewithcare/react-codemirror popularity was classified as not popular.
We found that @handlewithcare/react-codemirror demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.

Security News
Socket has released a free Certified Patch for a critical Rails Active Storage vulnerability, giving developers time to upgrade to a secure Rails version.

Security News
/Threat Research
A malicious Ruby gem runs a credential-stealing worm during installation, poisons AI coding tools, and can wipe files when a stolen GitHub token is revoked.

Security News
GitHub is tightening GitHub Actions security with new restrictions on privileged pull request workflows. Here's what changes and how maintainers are affected.