In this guide, you'll configure your plugin to use [React](https://react.dev/). It assumes that you already have a plugin with a [[Views|custom view]] that you want to convert to use React.
While you don't need to use a separate framework to build a plugin, there are a few reasons why you'd want to use React:
- You have existing experience of React and want to use a familiar technology.
- You have existing React components that you want to reuse in your plugin.
- Your plugin requires complex state management or other features that can be cumbersome to implement with regular [[HTML elements]].
## Configure your plugin
1. Add React to your plugin dependencies:
```bash
npm install react react-dom
```
2. Add type definitions for React:
```bash
npm install --save-dev @types/react @types/react-dom
```
3. In `tsconfig.json`, enable JSX support on the `compilerOptions` object:
```ts
{
"compilerOptions": {
"jsx": "react-jsx"
}
}
```
## Create a React component
Create a new file called `ReactView.tsx` in the plugin root directory, with the following content:
```tsx title="ReactView.tsx"
export const ReactView = () => {
return <h4>Hello, React!</h4>;
};
```
## Mount the React component
To use the React component, it needs to be mounted on a [[HTML elements]]. The following example mounts the `ReactView` component on the `this.containerEl.children[1]` element:
```tsx
import { StrictMode } from 'react';
import { ItemView, WorkspaceLeaf } from 'obsidian';
import { Root, createRoot } from 'react-dom/client';
import { ReactView } from './ReactView';
const VIEW_TYPE_EXAMPLE = 'example-view';
class ExampleView extends ItemView {
root: Root | null = null;
constructor(leaf: WorkspaceLeaf) {
super(leaf);
}
getViewType() {
return VIEW_TYPE_EXAMPLE;
}
getDisplayText() {
return 'Example view';
}
async onOpen() {
this.root = createRoot(this.containerEl.children[1]);
this.root.render(
<StrictMode>
<ReactView />,
</StrictMode>,
);
}
async onClose() {
this.root?.unmount();
}
}
```
For more information on `createRoot` and `unmount()`, refer to the documentation on [ReactDOM](https://react.dev/reference/react-dom/client/createRoot#root-render).
You can mount your React component on any `HTMLElement`, for example [[Plugins/User interface/Status bar|status bar items]]. Just make sure to clean up properly by calling `this.root.unmount()` when you're done.
## Create an App context
If you want to access the [[Reference/TypeScript API/App|App]] object from one of your React components, you need to pass it as a dependency. As your plugin grows, even though you're only using the `App` object in a few places, you start passing it through the whole component tree.
Another alternative is to create a React context for the app to make it globally available to all components inside your React view.
1. Use `createContext()` to create a new app context.
```tsx title="context.ts"
import { createContext } from 'react';
import { App } from 'obsidian';
export const AppContext = createContext<App | undefined>(undefined);
```
2. Wrap the `ReactView` with a context provider and pass the app as the value.
```tsx title="view.tsx"
this.root = createRoot(this.containerEl.children[1]);
this.root.render(
<AppContext.Provider value={this.app}>
<ReactView />
</AppContext.Provider>
);
```
3. Create a custom hook to make it easier to use the context in your components.
```tsx title="hooks.ts"
import { useContext } from 'react';
import { AppContext } from './context';
export const useApp = (): App | undefined => {
return useContext(AppContext);
};
```
4. Use the hook in any React component within `ReactView` to access the app.
```tsx title="ReactView.tsx"
import { useApp } from './hooks';
export const ReactView = () => {
const { vault } = useApp();
return <h4>{vault.getName()}</h4>;
};
```
For more information, refer to the React documentation for [Passing Data Deeply with Context](https://react.dev/learn/passing-data-deeply-with-context) and [Reusing Logic with Custom Hooks](https://react.dev/learn/reusing-logic-with-custom-hooks).