# Render components in an extension point

An extension point is a part of your plugin or Grafana UI where you can render content (links, functions or React components) from other plugins. Use them to extend your users' experience based on a context exposed by the extension point.

note

Read more about extensions under [key concepts](https://grafana.com/developers/plugin-tools/how-to-guides/ui-extensions/ui-extensions-concepts.md).<br />For reference documentation, including the APIs, see [UI extensions reference guide](https://grafana.com/developers/plugin-tools/reference/ui-extensions-reference.md).

## Best practices for rendering components[​](#best-practices-for-rendering-components "Direct link to Best practices for rendering components")

* **Make sure your UI controls the behavior**
  <br />
  Component extensions can render different layouts and can respond to various kind of user interactions. Make sure that your UI defines clear boundaries for rendering components defined by other plugins.
* **Share contextual information**
  <br />
  Think about what contextual information could be useful for other plugins and pass this as `props` to the components.

## Create an extension point to render components[​](#create-an-extension-point-to-render-components "Direct link to Create an extension point to render components")

1. Create the extension point component:

src/components/InstanceToolbar.tsx

```tsx
import { usePluginComponents } from '@grafana/runtime';

export const InstanceToolbar = () => {
  // The `extensionPointId` must be prefixed.
  // - Core Grafana -> prefix with "grafana/"
  // - Plugin       -> prefix with "{your-plugin-id}/"
  //
  // This is also what plugins use when they call `addComponent()`
  const extensionPointId = 'myorg-foo-app/toolbar/v1';
  const { components, isLoading } = usePluginComponents({ extensionPointId });

  if (isLoading) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      {/* Loop through the components added by plugins */}
      {components.map((Component) => (
        <Component key={Component.meta.id} />
      ))}
    </div>
  );
};

```

2. Declare the extension point in your `plugin.json`:

src/plugin.json

```json
{
  ...
  "extensions": {
    "extensionPoints": [
      {
        "id": "myorg-foo-app/toolbar/v1",
      }
    ]
  }
}

```

## Passing data to the components[​](#passing-data-to-the-components "Direct link to Passing data to the components")

1. Update the component to pass props to extensions:

src/components/InstanceToolbar.tsx

```tsx
import { usePluginComponents } from '@grafana/runtime';

// Types for the props (passed as a generic to the hook in the following code block)
type ComponentProps = {
  instanceId: string;
};

export const InstanceToolbar = ({ instanceId }) => {
  const extensionPointId = 'myorg-foo-app/toolbar/v1';
  const { components, isLoading } = usePluginComponents<ComponentProps>({ extensionPointId });

  if (isLoading) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      {/* Sharing contextual information using component props */}
      {components.map((Component) => (
        <Component key={Component.meta.id} instanceId={instanceId} />
      ))}
    </div>
  );
};

```

2. Make sure your `plugin.json` is up to date:

src/plugin.json

src/plugin.json

```json
{
  ...
  "extensions": {
    "extensionPoints": [
      {
        "id": "myorg-foo-app/toolbar/v1",
      }
    ]
  }
}

```

## Limit which plugins can register components in your extension point[​](#limit-which-plugins-can-register-components-in-your-extension-point "Direct link to Limit which plugins can register components in your extension point")

1. Update the component to filter plugins:

src/components/InstanceToolbar.tsx

```tsx
import { usePluginComponents } from '@grafana/runtime';

export const InstanceToolbar = () => {
  const extensionPointId = 'myorg-foo-app/toolbar/v1';
  const { components, isLoading } = usePluginComponents<ComponentProps>({ extensionPointId });

  // You can rely on the `component.pluginId` prop to filter based on the plugin
  // that has registered the extension.
  const allowedComponents = useMemo(() => {
    const allowedPluginIds = ['myorg-a-app', 'myorg-b-app'];
    return components.filter((Component) => allowedPluginIds.includes(Component.meta.pluginId));
  }, [components]);

  // ...
};

```

2. Make sure your `plugin.json` is up to date:

src/plugin.json

src/plugin.json

```json
{
  ...
  "extensions": {
    "extensionPoints": [
      {
        "id": "myorg-foo-app/toolbar/v1",
      }
    ]
  }
}

```
