> ## Documentation Index
> Fetch the complete documentation index at: https://docs.charmos.io/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Render Rich UI

The Charm Store **Universal Renderer** maps structured agent output to React components — bar/line/pie charts, data grids, metric cards — without you writing frontend code.

For full payload schemas, see the [UI Protocol Reference](/platform/ui-protocol).

## Built-in render types (no store changes)

Return a JSON object with `_charm_render_type` set to one of:

| Type          | Use case                |
| ------------- | ----------------------- |
| `bar_chart`   | Categorical comparisons |
| `line_chart`  | Trends over time        |
| `pie_chart`   | Part-to-whole           |
| `data_grid`   | Tabular results         |
| `metric_card` | KPI-style metrics       |

These work for any published agent — **no store deploy required**.

## Custom Python agents

```python theme={"theme":{"light":"min-light","dark":"min-dark"}}
def agent(inputs):
    return {
        "_charm_render_type": "bar_chart",
        "title": "Quarterly Sales",
        "data": [
            {"name": "Q1", "value": 15000},
            {"name": "Q2", "value": 22000},
        ],
    }
```

With the built-in **`custom`** adapter, return the dict directly from your entry point. With a third-party adapter, return `{"status": "success", "output": {...}}` or ensure your adapter forwards structured output.

## Framework adapters (LangChain, CrewAI, OpenClaw)

Configure the model to emit JSON matching the schema. Example for OpenClaw:

```yaml theme={"theme":{"light":"min-light","dark":"min-dark"}}
runtime:
  adapter:
    type: openclaw
  config:
    system_prompt: |
      Return your final answer as JSON only:
      {
        "_charm_render_type": "metric_card",
        "title": "Analysis Results",
        "metrics": [
          {"label": "Confidence", "value": "98.5", "unit": "%"}
        ]
      }
```

Adapters parse JSON final messages and forward structure to the Store.

## Metric card example

```python theme={"theme":{"light":"min-light","dark":"min-dark"}}
return {
    "_charm_render_type": "metric_card",
    "title": "Performance",
    "metrics": [
        {"label": "Active Users", "value": 1204, "change": 12, "unit": "users"},
        {"label": "Error Rate", "value": "0.3", "unit": "%"},
    ],
}
```

## Markdown and HTML fallback

Return a plain string for standard Markdown rendering. HTML and SVG snippets are sanitized (scripts stripped):

```python theme={"theme":{"light":"min-light","dark":"min-dark"}}
def agent(inputs):
    return "### Status\n\nAll systems operational."
```

## Streaming text + rich final

Use `CharmEmitter` for intermediate markdown, then return structured JSON as the final result:

```python theme={"theme":{"light":"min-light","dark":"min-dark"}}
from charm.core.io import CharmEmitter

def agent(inputs):
    CharmEmitter.emit_delta("Analyzing dataset...\n")
    return {
        "_charm_render_type": "metric_card",
        "title": "Results",
        "metrics": [{"label": "Score", "value": 98, "unit": "%"}],
    }
```

## Sharing Custom Output Renderers with the Community

You can now build and share your own custom UI components (like a specialized stock chart, a unique data grid, or a 3D molecule viewer) without waiting for a store deployment! Charm supports dynamic ESM module loading for community output renderers.

To share a custom renderer:

1. **Build a React Component**: Write a React component that takes a `payload` prop and export it as your default export.
2. **Publish to NPM**: Package your component and publish it to NPM. Ensure your package is ESM compatible.
3. **Register in the Community Plugin**: Submit a Pull Request to the [charm-community-plugin](https://github.com/CharmAIOS/charm-community-plugin) repository. Add your renderer's details (including the `id` which corresponds to your `_charm_render_type`, and the `npm_package` name) into `renderers/registry.json`.

Once your PR is merged, the Charm Store will dynamically fetch your component from `esm.sh` directly in the browser whenever an agent emits your `_charm_render_type`!

You can also browse all community renderers on the **Plugins** page in the Charm Store.

## Related

* [UI Protocol Reference](/platform/ui-protocol)
* [Extensibility Overview](/guides/extensibility)
* [Input Forms (UI Schema)](/guides/interface)
