Help us improve
Share bugs, ideas, or general feedback.
Expert in creating React components for Obsidian plugins with proper TypeScript types and integration
npx claudepluginhub jwplatta/agent-cubicle --plugin obsidian-plugin-builderHow this skill is triggered — by the user, by Claude, or both
Slash command
/obsidian-plugin-builder:react-component-expertThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
You are an expert in building React components for Obsidian plugins.
Builds advanced Obsidian plugin UI: custom ItemView sidebars, modals with forms, editor selection commands, status bar, context menus, Vault file API.
Creates p5.js generative art with seeded randomness, noise fields, and interactive parameter exploration. Use for algorithmic art, flow fields, or particle systems.
Share bugs, ideas, or general feedback.
You are an expert in building React components for Obsidian plugins.
import * as React from 'react';
import { useState, useEffect } from 'react';
interface MyComponentProps {
data: string;
onUpdate: (value: string) => void;
}
export const MyComponent: React.FC<MyComponentProps> = ({ data, onUpdate }) => {
const [value, setValue] = useState(data);
return (
<div className="my-component">
<input
value={value}
onChange={(e) => {
setValue(e.target.value);
onUpdate(e.target.value);
}}
/>
</div>
);
};
import { ItemView, WorkspaceLeaf } from 'obsidian';
import * as React from 'react';
import { createRoot, Root } from 'react-dom/client';
import { MyComponent } from './MyComponent';
export const VIEW_TYPE = 'my-view';
export class MyReactView extends ItemView {
root: Root | null = null;
constructor(leaf: WorkspaceLeaf) {
super(leaf);
}
getViewType() {
return VIEW_TYPE;
}
getDisplayText() {
return 'My View';
}
async onOpen() {
const container = this.containerEl.children[1];
container.empty();
container.addClass('my-view-container');
this.root = createRoot(container);
this.root.render(
<MyComponent
data="initial"
onUpdate={(value) => console.log(value)}
/>
);
}
async onClose() {
this.root?.unmount();
}
}
import { App, Modal } from 'obsidian';
import * as React from 'react';
import { createRoot, Root } from 'react-dom/client';
import { MyComponent } from './MyComponent';
export class MyReactModal extends Modal {
root: Root | null = null;
constructor(app: App) {
super(app);
}
onOpen() {
const { contentEl } = this;
this.root = createRoot(contentEl);
this.root.render(
<MyComponent
data="modal data"
onUpdate={(value) => {
console.log(value);
this.close();
}}
/>
);
}
onClose() {
this.root?.unmount();
}
}
{
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0"
}
}
Ensure esbuild.config.mjs handles JSX:
external: [
'obsidian',
'electron',
'@codemirror/*',
'react',
'react-dom'
],
When creating components: