# Technical Documentation: evidence-dev/evidence

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/evidence-dev/evidence)

### Overview (`README.md`)

<div id="top" align="center">

<picture>
  <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/evidence-dev/media-kit/main/svg/wordmark-white.svg">
  <img alt="Evidence Logo" src="https://raw.githubusercontent.com/evidence-dev/media-kit/main/svg/wordmark-black.svg">
</picture>

Evidence is an agent-ready tool for creating reports using your data

### [Docs](https://docs.evidence.studio) | [Slack](https://slack.evidence.dev)


[](https://slack.evidence.dev)

</div>

# How It Works

Evidence is an open-source, code-based alternative to drag-and-drop business intelligence tools.

- Create reports in code using SQL and markdown
- Develop using Evidence's Agent, or on your local machine with Claude Code / Cursor etc
- Self-host or publish on Evidence Studio

# Install

### macOS / Linux

```bash
curl -fsSL https://evidence.studio/install.sh | sh
evidence help
```

### Windows

```powershell
irm https://evidence.studio/install.ps1 | iex
evidence help
```

# Create a Project

```bash
evidence init my-project
cd my-project
evidence dev
```

# Publish

Publish your project on [Evidence Studio](https://evidence.studio) for hosted reports, or self-host the generated static site on your own infrastructure. See the [publishing docs](https://docs.evidence.studio/publishing) for options.

# Join the Evidence Community

Join our [Slack channel](https://slack.evidence.dev) to get involved in the community's discussion, share what you're working on, or ask for help.

# Contributing

Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md) for how pull requests are reviewed and merged.

# License

Evidence is licensed under the MIT license. See [LICENSE](LICENSE) for details.

---

### Overview (`cli/README.md`)

# EVD

Evidence Studio local development CLI.

## Quick Start

```bash
# Install dependencies (from monorepo root)
pnpm install

# Run a CLI command from source — instant, no build (defaults to cli/test-environment)
pnpm evd query "select 1"
pnpm evd help

# Run the dev server from source against the test playground
pnpm evd dev

# Build the CLI binary (requires Bun installed globally)
pnpm cli:build

# Run the binary
./cli/dist/evidence
./cli/dist/evidence --help
./cli/dist/evidence dev --port 8080
```

## Architecture

```
/* Detailed source-code truncated for AI context efficiency. */
```

## Project Structure

```
.
├── adapter/
│   └── index.js          # Custom SvelteKit adapter
│                         # - Discovers & embeds static assets
│                         # - Generates manifest
│                         # - Compiles binary with Bun
│
├── cli/
│   ├── index.ts          # CLI entry point
│   ├── args.ts           # Argument parsing, help, banner
│   └── server.ts         # Bun HTTP server + SvelteKit integration
│
├── src/
│   ├── routes/           # SvelteKit routes (the actual app)
│   ├── lib/              # Shared components
│   └── app.html          # HTML template
│
├── static/               # Static assets (favicon, etc.)
├── dist/                 # Build output (gitignored)
│   └── evd               # The compiled binary
│
├── svelte.config.js      # SvelteKit config (uses ./adapter)
├── vite.config.ts        # Vite config
└── package.json
```

## How It Works

### 1. Asset Embedding

The magic that makes a single binary possible. During build:

```javascript
// adapter/index.js generates imports like:
import favicon_SVG_a1b2 from '../client/favicon.svg' with { type: 'file' };

export const assetMap = new Map([
	['/favicon.svg', favicon_SVG_a1b2]
	// ... all static files
]);
```

Bun's `{ type: "file" }` import attribute embeds the file contents into the binary.

### 2. The Adapter

`adapter/index.js` is a custom SvelteKit adapter that:

1. **Writes SvelteKit output** - client assets, prerendered HTML, server code
2. **Generates asset imports** - creates `assets.generated.ts` with embedded file references
3. **Generates manifest** - SvelteKit's routing manifest
4. **Compiles** - runs `bun build --compile` to create the binary

### 3. The CLI

`cli/` contains the runtime code that gets compiled:

- `args.ts` - Parses `--port`, `--help`, `--version`, etc.
- `server.ts` - Starts Bun.serve(), handles static assets & SSR
- `index.ts` - Wires it together, handles commands

### 4. Request Flow

```
Request → Bun.serve()
            │
            ├─→ Static asset? → Serve from embedded assetMap
            │
            ├─→ Prerendered route? → Serve embedded HTML
            │
            └─→ Otherwise → SvelteKit SSR
```

## Development

### Prerequisites

- [Bun](https://bun.sh) v1.2.18+ (required for running CLI source and for binary compilation)
- [pnpm](https://pnpm.io) (for package management)

### Day-to-day workflow

| What you're working on              | Run              | Build needed? |
| ----------------------------------- | ---------------- | ------------- |
| `evidence dev` flow / Svelte routes | `pnpm evd dev`   | no            |
| Other CLI commands                  | `pnpm evd <cmd>` | no            |
| Final binary smoke test             | `pnpm cli:build` | yes           |

Both scripts default to the `cli/test-environment` playground regardless of where you invoke them from. Pass `--project <path>` to override the target directory.

### Quick Install: Add `evidence` to Your PATH

After building the CLI binary, you can add it to your PATH for convenient global access:

```bash
# Symlink the binary to a directory in your PATH (requires sudo)
sudo ln -sf "$(pwd)/cli/dist/evidence" /usr/local/bin/evidence

# Verify it works
which evidence
evidence --version
```

**Benefits of this approach:**

- Always reflects the latest `dist/evidence` after rebuilds (no re-install needed)
- Works everywhere (scripts, subshells, GUI tools)
- Easy to revert (see below)

**Undo the symlink:**

```bash
# Remove the symlink
sudo rm /usr/local/bin/evidence

# If you want to restore the previous binary (backup created during install)
sudo mv /usr/local/bin/evidence.old /usr/local/bin/evidence
```

**Note:** If you built the CLI elsewhere, replace the path accordingly. You can also prepend a user bin directory to your PATH instead of using `/usr/local/bin` if you prefer not to use `sudo`.

#### Examples — all run from the monorepo root

```bash
pnpm evd help
pnpm evd query "select 1"                  # against cli/test-environment (NDJSON)
pnpm evd --project ./some/dir validate     # override to an arbitrary project
pnpm evd dev --port 5173                   # extra flags forward to the dev server
```

### Output formats

Data commands are **machine-readable by default; the human view is opt-in** via
`--verbose`. Output is identical whether or not stdout is a terminal (there is
no TTY detection). All formatting is centralized in `cli/output.ts`
(`printResult` / `renderResult` / `fail`) — commands never call `JSON.stringify`
or render tables directly.

Defaults (no flags):

- Result sets (`query`, `describe`, `schema`) → **NDJSON**, one JSON object per line.
- Name lists (`tables`) → **plain `schema.table`, one per line**.
- Structured/list results (`connectors`, `models`, `lineage`, `docs`) → **compact JSON**.
- No ANSI color and no box-drawing characters, ever, by default.

Shared flags on every data command:

| Flag                | Effect                                                                      |
| ------------------- | --------------------------------------------------------------------------- |
| `--verbose`         | Human view: pretty aligned table + full/extra columns                       |
| `--format <fmt>`    | `json`, `ndjson`, `csv`, `table` (`table` = pretty). Wins over `--verbose`. |
| `--columns <a,b,c>` | Select and order columns                                                    |
| `--limit <n>`, `-l` | Limit rows (`query` defaults to 1000; a stderr note flags truncation)       |
| `--all`             | Remove the row limit                                                        |
| `--no-color`        | Disable color (the `NO_COLOR` env var is also honored)                      |

Errors go to stderr; under `--format json`/`ndjson` they are emitted as
`{"error":<msg>,"code":<str>}`. Status/progress chatter also goes to stderr.

> **Breaking changes** (vs. the previous human-first defaults):
>
> - Default output is now NDJSON/plain/compact-JSON instead of pretty tables.
>   Use `--verbose` for the old human view.
> - `-v` now means `--verbose`. Use `--version` (or the `version` subcommand)
>   for the version.
> - `--columns` now takes a value (column selection) instead of being a boolean
>   "columns-only" toggle — that role is now `describe`'s default.
> - `--format` is long-form only; `-o`/`--output <path>` keeps its "write to
>   file" meaning. `--json` still works as an alias for `--format json`.
> - `query` no longer pretty-prints by default and caps output at 1000 rows
>   unless `--all` is passed.

`evd dev` detects that it's running from source (via `process.execPath`) and routes through `vite dev` automatically — same auth + Studio health check as the binary, then spawns `vite dev`. Browser auto-open defaults to off in source mode (pass `--open` to opt back in); the binary still auto-opens by default.

#### What works under `evd` (no build)

The commands that are pure TypeScript and don't need the SvelteKit bundle: `help`, `version`, `login`, `logout`, `whoami`, `orgs`, `switch`, `token`, `query`, `tables`, `describe`, `schema`, `connectors`, `models`, `lineage`, `upgrade`.

#### What still needs `cli:build` (or the dev server)

`validate` and `docs` go through SvelteKit's HTTP layer, which uses `import.meta.glob` — a vite-only construct. Two options:

- Run `pnpm cli:build` once, then `./cli/dist/evidence validate` reflects the latest source. (You only need to rebuild when SvelteKit-side code changes.)
- Or run `pnpm evd dev` and hit the same endpoints directly: `curl http://localhost:3000/api/validate`.

### Other commands

```bash
pnpm cli:build       # Build production binary
pnpm cli:check       # Type check
pnpm cli:lint        # Lint & format check
pnpm --filter @evidence/cli format
```

### Dev vs Production

| Aspect    | `pnpm evd dev`            | `./dist/evidence`  |
| --------- | ------------------------- | ------------------ |
| Server    | Vite dev server (spawned) | Bun.serve()        |
| Assets    | Served from disk          | Embedded in binary |
| HMR       | Yes                       | No                 |
| Auto-open | No (pass `--open`)        | Yes                |
| SSR       | Yes                       | Yes                |
| Size      | N/A                       | ~50MB single file  |

### Adding CLI Commands

Edit `cli/args.ts` to add new commands:

```typescript
// In parseArgs():
if (firstArg === 'mycommand') command = 'mycommand';

// In cli/index.ts:
case 'mycommand':
  // do something
  break;
```

Data-producing commands should route their results through `printResult` (from
`cli/output.ts`) using the shared `args.output` options, rather than calling
`JSON.stringify` or rendering tables themselves — this keeps the machine-first
defaults, `--format`, `--columns`, `--limit`, and color handling consistent
across every command.

### Modifying the Adapter

The adapter in `adapter/index.js` controls the build process. Key functions:

- `discoverAssets()` - Finds all files to embed
- `generateAssetImports()` - Creates the import statements
- `adapt()` - Main build orchestration

## Docker Image

The CLI is published as a Docker image, `evidencedev/serve` ([Docker Hub](https://hub.docker.com/r/evidencedev/serve)), so that self-hosting a project is a two-line `Dockerfile`:

```docker
FROM evidencedev/serve:latest
COPY --chown=evidence:evidence . /project
```

That's the whole point of the image — a user self-hosting a project should never have to figure out how to install the CLI inside a container. `cli/Dockerfile` handles fetching the right binary for the architecture, CA certificates (without them, TLS to the warehouse fails at runtime), a non-root `evidence` user, `/project` as the working directory, honouring a platform-provided `$PORT`, and starting `evidence serve --host 0.0.0.0`. The user's layer is just "copy my project in".

### It ships on a version bump

The image does not build the CLI. Its first stage downloads an already-published binary from Vercel Blob:

```
https://.../cli/v${EVIDENCE_VERSION}/evidence-${target}
```

So a new image only appears when a new CLI version is released. In `.github/workflows/cli-release.yml`, the `docker` job has `needs: release` — it cannot run until the release job has uploaded binaries for that version. There is no way to rebuild the image against unreleased CLI code: bump `VERSION` in `cli/cli/args.ts`, add the `cli-release` label to the PR, and merge.

Also bump the `ARG EVIDENCE_VERSION` default in `cli/Dockerfile` to match. CI overrides it, but anyone running `docker build -f cli/Dockerfile .` by hand gets whatever the default says.

### Tags and platforms

- `evidencedev/serve:<version>` on every release.
- `evidencedev/serve:latest` only for stable versions — a version containing `-` (`0.9.2-alpha.1`) never moves `latest`.
- Built for `linux/amd64` and `linux/arm64` via QEMU + Buildx. Pushed with the `DOCKERHUB_USERNAME` / `DOCKERHUB_TOKEN` secrets.

The `docker` job lives in the release workflow rather than its own file because the `cli-v*` tag is pushed with `GITHUB_TOKEN`, which cannot trigger another workflow.

## Telemetry

The CLI reports anonymous usage — to opt out run `evidence telemetry disable`, or set `EVIDENCE_TELEMETRY_DISABLED=1` or `DO_NOT_TRACK=1`. The full payload is documented at https://docs.evidence.studio/cli#telemetry.

Events go to `POST /api/cli/event` in studio (`studio/src/routes/api/cli/event/`), which allow-lists fields and forwards to PostHog. Three rules keep the "unique users" number honest: `serve` runs and the daily `serve_heartbeat` never create a PostHog person (count deployments by `project_id` instead), a machine id that cannot be persisted is sent as `null` rather than a fresh UUID per run, and the first run inside an agent sandbox or container is flagged `sandbox` and recorded personless. Authenticated CLI usage of Studio is captured server-side as `cli_studio_request` in `authenticateCliRequest`, keyed to the user's email and `organization` group, so it is not subject to client opt-out.

## License

MIT

---

### Overview (`docs/README.md`)

# Evidence Docs

## Autogenerated Components and Data Sources Docs

The following directories are autogenerated by scripts in the `scripts/docs`:

- `components` - All user components
- `data-sources` - All data sources

Do not edit these files manually! Instead run the docs generation scripts:

```
npm run docs:generate-components
npm run docs:generate-connectors
```

## Development

Install the [Mintlify CLI](https://www.npmjs.com/package/mint) to preview the documentation changes locally. To install, use the following command

```
npm i mint
```

Run the following command at the root of your documentation (where docs.json is)

```
mint dev
```

---

### Overview (`cli/test-environment/README.md`)

# CLI dev playground

This directory is the local Evidence project the CLI is exercised against during development. Drop a `connection.yaml` here (gitignored) pointing at your dev warehouse and the scripts below will pick it up.

## Setup

Create `cli/test-environment/connection.yaml`. Snowflake + dbt source files for this directory will be added in follow-up work — for now a minimal config is enough to exercise CLI commands.

## Run from the monorepo root

```bash
# A CLI command, against this directory (the default)
pnpm evd help
pnpm evd query --sql "select 1"

# Dev server, against this directory (vite dev under the hood, no binary build)
pnpm evd dev
```

`validate` and `docs` go through the SvelteKit HTTP layer (which uses vite-only constructs), so they need either a binary build (`pnpm cli:build`) or a running dev server. See the main `cli/README.md` for the full breakdown.

These scripts work from anywhere inside the monorepo — they don't `cd` into this directory, they pass `--project cli/test-environment` to the CLI so `process.cwd()` semantics still resolve correctly. To target a different project, append `--project ./other/path` to either script.

## Behind the scenes

- `--project <path>` chdirs the CLI process and sets `EVIDENCE_PROJECT_CWD` so the SvelteKit dev server (which runs with `cwd` = the cli package) can find your project files via `getProjectCwd()`.
- `evd dev` detects "running from source" via `process.execPath` and routes through `vite dev` instead of the compiled Bun server. Browser auto-open is off by default in source mode; pass `--open` to opt in.

---

### Overview (`docs/components/README.md`)

# Component Docs

## Autogenerated Components Docs

These docs are autogenerated by the `scripts/generate-components-docs.ts` script. Do not edit these files manually!

To regenerate the docs, run the following command:

```
npm run docs:generate-components
```

---

### Overview (`docs/data-sources/README.md`)

# Data Source Docs

## Autogenerated Data Source Docs

These docs are autogenerated by the `scripts/generate-connector-options.ts` script. Do not edit these files manually!

To regenerate the docs, run the following command:

```
npm run docs:generate-connectors
```

---

### Overview (`core/src/user-components/UserComponentModel/README.md`)

# UserComponentModel

`UserComponentModel` is the **foundation** for all of our user-facing data components (tables, dimensions, measures, pivots, etc).  
Think of it like the **blueprint** for every component: it defines the rules for how components talk to each other, what data they hold, and how they can be serialized/deserialized during SSR.

## Why is it abstract?

An **abstract class** is like a "template" that you can't use directly.  
You don't create a `UserComponentModel` on its own—you only create _subclasses_ like `TableModel` or `DimensionModel` that **fill in the blanks**.

This lets us:

- Define **shared rules** once (e.g. parent/child validation, attribute reactivity, serialization).
- Ensure every subclass plays by the same rules, while still giving them the freedom to customize.

Analogy:

- Abstract class = "You must have wheels, but you can decide if you're a car, a bike, or a skateboard."

## Attributes

Every UserComponentModel accepts a `MaybeGetter` for the component's attributes in its constructor argument. `MaybeGetter` is used to allow the attributes to be either a plain value (`Record<string, unknown>`) or a function that returns a value (a _getter_: `() => Record<string, unknown>`). Accepting a function is necessary for [reactivity when passing state around](https://svelte.dev/docs/svelte/$state#Passing-state-into-functions). Reactivity isn't always necessary (like on the server during SSR)
so its a *Maybe*Getter.

In the constructor, the attributes use something called `useStable`. This prevents reactivity churn when the user is typing in the editor. When the user types, a new Markdoc RenderableTree is generated with every keystroke (after a debounce). This means that every model gets a brand new attributes object each time, which would cause all of the queries to re-run. To prevent this, `useStable` only returns a new value if the state has _actually changed_ by doing a recursive comparison of values all the way down objects and arrays.

## Parents and Children

2. **Parent**

   - The "container" this model lives inside.
   - Example: A `DimensionModel` can only exist _inside_ a `TableModel`.

3. **Children**
   - Models that live _inside_ this one.
   - Example: A `TableModel` can contain multiple `DimensionModel` and `MeasureModel` children.

This creates a **tree structure** with our models that mimics the RenderableTree from markdoc. It enables parents and children to depend on and interact with each other to run queries.

### Why we check parent/child at runtime

Even though TypeScript checks parent/child relationships at compile time, we also validate them at runtime (`isValidParent` and `isValidChild`). This is necessary because the user's input is completely dynamic and they could build components with invalid parent/child relationships, which would result in us creating models with invalid parent/child relationships. By checking the types of parents/children, we make sure we _fail fast_ with a clear error rather than something failing obscurely down the line.

```ts
const dimension = new DimensionModel(...);
table.addChild(dimension); // ✅ Works

const measure = new MeasureModel(...);
dimension.addChild(measure); // ❌ Throws runtime error
```

## Serialization and SSR

Serialization and Deserialization is the process of converting a complex object into a JSON representation and then back again. This process is necessary because only JSON can be sent from the server to the client, not classes, functions, or other complex entities.

If a component needs to be serializable, it should specify its serialized type via the `Serialized` generic, implement the `toSerialized` function to return its serialized data, and perform necessary deserialization using the `serialized` data in the model constructor.

_Note: We don't have to serialize all the way down to JSON! SvelteKit uses [devalue](https://github.com/rich-harris/devalue) under the hood which supports some more complex types like `Date` and `Map`._

## Generics

### What even are generics?

Generics are a way of writing code that is flexible but still type-safe.

Think of them as placeholders for types. Instead of hard-coding "this must always be a string" or "this must always be a number," we say "this can work with any type, but once you pick the type, it stays consistent."

For example, imagine we need a function that ensures something is always an array. We can pass it an argument that may or may not be an array, and it will ensure that what is returned is an array. This kind of function doesn't care if we're dealing with an array of strings, numbers, or anything else. We can use generics to make the types behave nicely with any kind of input.

```ts
function makeArray<T>(input: T | T[]): T[] {
	return Array.isArray(input) ? input : [input];
}

const example1 = makeArray(1); // -> number[]
const example2 = makeArray(['a', 'b', 'c']); // -> string[]
const example3 = makeArray(new SomeClass()); // -> SomeClass[]
```

UserComponentModel's generic types work fundamentally the same. They ensure consistency between the types of attributes, parents, children, and the serialized version of a model.

### Why do they look weird/extra complex for UserComponentModel?

You'll notice the type definition uses a **big object of options** rather than simple type parameters:

```ts
type TableModelGenerics = WithDefaults<{
	Attributes: TableAttributes;
	Serialized: SerializedTableModel;
	ValidChildren: [typeof DimensionModel, typeof MeasureModel, typeof PivotModel];
}>;
```

Why?

1. **Clarity** - Instead of positional generics (`<A, S, P, C>`), we structure them in an object where each type has an explicit name from its key. This is more readable when there are a lot of generic types.
2. **Flexibility** - You don't always need to set all options. Using the `WithDefaults` helper, you can override just the parts you need, and leave the rest at defaults.

## State in models

For reactivity, use `$state` and `$derived` (or `$derived.by`) for models' member variables.

Use `$state` for data that is changed during reactivity (e.g. `page`, `search`, `order` in `TableModel`)

Use `$derived` (or `$derived.by`) for state that is computed (derived) from other state like `$state` declarations, the model's attributes, etc (e.g. `queryConfig` in `TableModel`)

_Note: Use `$derived` or `derived.by` for computed state, NOT getters (`get myField() { }`). Getters will be re-executed whenever they are read resulting in performance issues._

---

### Overview (`core/src/user-components/common/README.md`)

# Common Utilities

This directory contains shared utility functions used across user components.

## Date System Architecture

### The Problem We Solved

When building a data visualization platform, dates are everywhere but behave differently depending on context. Users want to:

- Filter data by date ranges ("Show me last 30 days")
- Compare time periods ("How does this month compare to last month?")
- Group data by time periods ("Monthly sales trends")

The challenge: **date logic was scattered across components with inconsistent behavior**. Some components parsed "Last 30 days" differently, comparison tooltips showed placeholder dates, and we had duplicate parsing logic everywhere.

### Our Solution: Three Clear Use Cases

We identified that all date operations fall into three distinct patterns, each requiring different technical approaches:

#### 1. Explicit Date Filtering ("Show me sales from last month")

**The Use Case**: User wants to see data from a specific time period. They select "Last 30 days" from a dropdown, and we filter the entire dataset.

**Why This Exists**: Most basic date filtering - users want to slice data by time ranges. Common in dashboards where you want to focus on recent data.

**How It Works**: We convert "Last 30 days" into SQL like `WHERE date >= '2024-01-01' AND date <= '2024-01-31'`

**For Comparisons**: We shift the date boundaries - if current period is "last month", comparison period becomes "two months ago"

#### 2. Time-Series Analysis ("Monthly sales trends with comparisons")

**The Use Case**: User wants to see data grouped by time periods (daily, monthly, yearly) and compare each period to its predecessor. A table showing "Monthly Revenue" where each row is a month, and they want to see how each month compares to the previous month.

**Why This Exists**: Time-series analysis is core to business intelligence. Users don't just want to see monthly totals - they want to see "Is this month better than last month?" for every month.

**How It Works**: Instead of filtering dates, we group by time periods using `date_grain="month"`. For comparisons, we shift the date expressions themselves: `toStartOfMonth(date - INTERVAL 1 MONTH)`.

**The Tricky Part**: Each row represents a different time period, so the comparison logic needs to be applied per-row, not per-query.

#### 3. Dashboard-Wide Date Controls ("Apply this date range to everything")

**The Use Case**: User sets a date range at the dashboard level and wants it applied to all components. Common in executive dashboards where you want to see "Q3 performance" across all metrics.

**Why This Exists**: Consistency - users want to change one date filter and have it affect multiple charts/tables simultaneously.

**How It Works**: Similar to explicit filtering but propagated across multiple components. The date range logic is reused but applied at a higher level.

### Key Technical Decisions

#### MIN/MAX Aggregates for GROUPING SETS

**Problem**: Comparison tooltips showed "Jan 1/70" (ClickHouse null date placeholders) for total rows.

**Solution**: Wrap date expressions in MIN/MAX aggregates:

```sql
-- Before
formatDateTime(toStartOfMonth(date), '%b %e/%y')

-- After
formatDateTime(MIN(toStartOfMonth(date)), '%b %e/%y')
```

**Why**: GROUPING SETS automatically calculates correct date ranges for both individual rows and totals without manual conditional logic.

#### Centralized Date Parsing

**Problem**: Duplicate parsing logic across multiple files.

**Solution**: Single `parseDateRange()` function in `date-options.ts` handles all patterns:

- "Last X days/months/years"
- "MTD/WTD/YTD"
- Case insensitive matching
- Singular/plural forms

#### Structured Return Values

**Problem**: Functions returned SQL strings that were then parsed with regex.

**Solution**: Return structured objects:

```typescript
{ whereClause: string; startDate: string } | undefined
```

### Functions Overview

#### `processDateRange(date_range)`

- Converts date range objects to SQL WHERE clauses
- Returns both SQL and parsed start date
- Handles all supported date range patterns
- Uses date column from the DateRangeObject

#### `calculateComparisonDateRange(dateRange, offset)`

- Calculates comparison date ranges
- Handles both range-based and dimension-based shifting
- Uses centralized parsing logic

#### `parseDateRange(dateRange)`

- Central parsing for all date range strings
- Returns structured `ParsedDateRange` object
- Includes ClickHouse-specific fields

### Common Patterns

#### Date Range Patterns

- `"Last 30 days"` → 30 days ago to today
- `"Last month"` → Previous calendar month
- `"MTD"` → Month to date
- `"YTD"` → Year to date

#### Comparison Calculations

- **Range-based**: Shift boundaries by offset periods
- **Dimension-based**: Shift expressions by adding/subtracting intervals

### When to Use What

**Use Normal Range when:**

- Adding explicit date filters to components (`date_range="Last 30 days"`)
- User selects a date range from a dropdown
- You want to filter the entire dataset

**Use Dynamic Range when:**

- Component has `date_grain` and you want period-over-period comparisons
- Data is already grouped by time periods
- Each row represents a different time period

**Use Table Range when:**

- Applying dashboard-wide date filters
- Multiple components need the same date range

### Common Gotchas

1. **"Jan 1/70" in tooltips** → Use MIN/MAX aggregates around date expressions
2. **Comparison dates off by one** → Check if you need the +1 day adjustment in `processDateRange`
3. **Case sensitivity** → All parsing is case-insensitive, but double-check your strings
4. **MTD/YTD not working** → Ensure you're using the `startDateFunction` from `parseDateRange`

### Migration Notes

- Eliminated `generateDateSql` wrapper function
- Consolidated `calculatedateDimensionComparisonDateRange` into main function
- Removed string parsing in favor of structured returns
- No backwards compatibility maintained (as requested)

## Other Utilities

- `comparisons.ts` - Comparison query generation
- `sql-options.ts` - SQL expression utilities
- `format-options.ts` - Value formatting helpers

---

### Index (`docs/index.mdx`)

---
title: What is Evidence?
description: 'Evidence is a powerful framework for building and publishing data products using SQL, markdown, and AI.'
keywords:
  - business intelligence
  - BI tool
  - business intelligence and analytics (ABI)
  - data products
  - dashboards
  - reporting platform
  - analytics platform
  - data visualization
  - business intelligence tools
  - SQL reports
---

Evidence is a business intelligence and analytics (ABI) platform for building data products with SQL, markdown, and AI. Use it as a BI tool to write SQL reports, build dashboards, and publish an analytics platform your team can explore. It's a reporting platform for data visualization — one of the business intelligence tools your whole organization can use. Evidence comes in two parts: an open-source framework you can run yourself, and a hosted platform built on top of it.

## Evidence Core

**Evidence Core** is an MIT-licensed framework for building data apps from SQL and Markdown. You write reports in [Markdown](/core-concepts/markdown) with embedded [SQL](/core-concepts/markdown#sql) and [components](/core-concepts/components), query your own warehouse through [direct connectors](/direct-connectors/snowflake), and preview locally with the [CLI](/cli). It builds to a static site you can [self-host](/self-host) anywhere — Vercel, Netlify, Docker, or your own infrastructure. No account required.

## Evidence Studio

**Evidence Studio** is the hosted platform built on Evidence Core. Alongside everything in Core, it adds:

- A collaborative [editor](/editing) and [publishing](/publishing) with preview deployments
- The [Evidence Agent](/features/evidence-agent) for building reports with AI
- [Access rules](/features/access-rules) and [page-level access control](/features/page-level-access-control) for controlling who sees what
- [Scheduled reports](/features/scheduled-reports) and [embedded analytics](/features/embedded)

Studio-only pages in these docs are marked with a badge.

## Getting Started

Create your first report in minutes.

<CardGroup cols={2}>
	<Card title="Sign Up" icon="user" href="https://login.evidence.studio/sign-up">
		Create an Evidence Studio account and start building in your browser.
	</Card>
	<Card title="Download the CLI" icon="terminal" href="/cli">
		Build locally with Evidence Core.
	</Card>
</CardGroup>

## Learn More

Build reports to share with your team.

<CardGroup cols={2}>
	<Card title="Add Components" icon="chart-line" href="/core-concepts/components">
		Add charts, tables and interactive components to your reports
	</Card>
	<Card title="Write SQL" icon="database" href="/core-concepts/markdown">
		Write SQL queries to power your reports
	</Card>
	<Card title="Share Reports" icon="share" href="/publishing">
		Publish your reports online to share with your team
	</Card>
	<Card title="Write Reports with AI" icon="sparkles" href="/editing">
		Build interactive reports with the help of the Evidence AI Agent
	</Card>
</CardGroup>

---

### Quickstart (`docs/quickstart.mdx`)

---
title: 'Quickstart'
description: 'Start building reports in under 5 minutes'
keywords:
  - getting started
  - build a dashboard
  - business intelligence example
  - business report example
  - data analytics tutorial
---

<CardGroup cols={2}>
	<Card title="Evidence Studio" icon="user" href="https://login.evidence.studio/sign-up">
		Get started on our managed platform
	</Card>
	<Card title="Evidence Core" icon="terminal" href="/cli">
		Get started with open source
	</Card>
</CardGroup>


## Create an Account

This quickstart is the getting started guide for Evidence — a hands-on data analytics tutorial that walks you through building a business report example from scratch, taking you from an empty report to a published page in under 5 minutes. By the end, you'll build a dashboard and have a working business intelligence example you can share with your team.

<Steps>
	<Step title="Sign Up">
		Register at [Evidence Studio](https://login.evidence.studio/sign-up) and create a new account.
		You can SSO with Google, Github or Microsoft, or sign up with an email and password.
	</Step>
	<Step title="Edit Your First Report">
		You'll start on an empty report. Type markdown in the editor on the left hand side, and you'll
		get a preview of the report on the right hand side.
	</Step>
	<Step title="Publish your Report">
		When you are happy with your changes, click the "Share" button in the top right corner, and then
		choose the "Publish" button. After a few seconds, you'll see a link to your report.
	</Step>
</Steps>

---

### Cli Index (`docs/cli/index.mdx`)

---
title: 'CLI'
description: 'Develop Evidence Studio projects locally or with the agent of your choice.'
---

The Evidence CLI lets you run and develop Evidence projects locally from the command line.

It includes a development server for previewing your reports locally as you work, commands for running queries, viewing metadata, and validating your code. 

If you are going to use the CLI for development, you should set up the [GitHub Integration](../features/version-control#github-integration).

## Install

<Tabs>
  <Tab title="macOS / Linux">
    ```bash
    curl -fsSL https://evidence.studio/install.sh | sh
    ```

    Installs to `/usr/local/bin` (falls back to `~/.local/bin` if not writable).
  </Tab>
  <Tab title="Windows">
    ```powershell
    irm https://evidence.studio/install.ps1 | iex
    ```

    Installs to `%LOCALAPPDATA%\Evidence\bin` and adds it to your user PATH. Restart your terminal after install.
  </Tab>
</Tabs>

Both `evidence` and `evd` commands are available after install.

### Supported Platforms

- macOS arm64 (Apple Silicon)
- macOS x64 (Intel)
- Linux x64
- Linux arm64
- Windows x64

### Verify Installation

```bash
evidence version
```

## Getting Started

1. **Create a project** in [Evidence Studio](https://evidence.studio) and connect it to a GitHub repo.
2. **Clone the repo** to your local machine.
3. **Log in** to your Evidence account via the CLI:
   ```bash
   evidence login
   ```
4. **Start developing** from inside your cloned project directory:
   ```bash
   evidence dev
   ```
5. Open a pull request on the repo. Evidence Studio will reply with a preview link. Merging the PR releases your changes.

## Upgrade

```bash
evidence upgrade
```

The CLI checks for updates on startup. If a newer version is available, you'll see a warning. If your version is below the minimum supported version, the CLI will require an upgrade before running.

## Telemetry

The CLI reports anonymous usage so we can tell how many people use Evidence, which commands matter, and which versions are still in the wild. Nothing about your data, queries, file paths, or repository is ever sent.

### Opting out

Any one of these turns telemetry off:

```bash
evidence telemetry disable      # persists in ~/.evd/telemetry.json
export EVIDENCE_TELEMETRY_DISABLED=1
export DO_NOT_TRACK=1           # the cross-tool convention
```

`evidence telemetry status` shows the current state and why. Telemetry is also skipped automatically on CI (`CI`, `GITHUB_ACTIONS`, `GITLAB_CI`, `CIRCLECI`, `BUILDKITE`, `TF_BUILD`, `JENKINS_URL`).

### What is sent

One `cli_command` event per invocation, one `cli_installed` event from the install script, and — for `evidence serve` only — a `serve_heartbeat` once every 24 hours so long-running deployments stay counted, plus a `serve_preflight_failed` event (with a `reason` such as `no_connection_yaml`) when `serve` refuses to start, so we can spot broken self-host deployments.

| Field         | Example              | Purpose                                                                                                         |
| ------------- | -------------------- | --------------------------------------------------------------------------------------------------------------- |
| `machineId`   | random UUID          | Stored in `~/.evd/machine-id` on first run (or in your temp dir if home isn't writable); counts developer machines without knowing who you are |
| `id_source`   | `home` / `tmp`       | Where the machine id was stored                                                                                 |
| `command`     | `dev`                | Which command ran                                                                                               |
| `version`     | `0.9.3`              | CLI version                                                                                                     |
| `os`, `arch`  | `darwin`, `arm64`    | Platform mix                                                                                                    |
| `connector`   | `direct` / `managed` | Whether the project has a `connection.yaml` or uses the managed warehouse                                       |
| `logged_in`   | `false`              | Whether a Studio login exists on this machine                                                                   |
| `project_id`  | random UUID          | `telemetry.id` from `evidence.config.yaml`; counts deployments of a project rather than restarts of a container |
| `agent`       | `cursor`             | Set when a coding agent (Cursor, Claude Code, Codex, Gemini) is driving the CLI                                 |
| `tty`         | `true`               | Whether a person is at an interactive terminal                                                                  |
| `runtime`     | `docker` / `bare`    | Whether the CLI is running in a container                                                                       |
| `first_run`   | `true`               | Whether this is the first run on this machine                                                                   |
| `sandbox`     | `false`              | First run inside an agent or container; these never count as users                                              |
| `instance_id` | random UUID          | Per-process id, used only to count restarts of a deployment                                                     |

Requests carry your IP like any HTTP request; it is used for country-level geolocation only.

### Project id

`evidence init` writes a random `telemetry.id` into `evidence.config.yaml`. It identifies the project, not you or your machine, and is what lets us count a self-hosted deployment once rather than once per container restart. Delete the key to opt a project out of that count.

### When you are logged in

Commands that talk to Evidence Studio (`launch`, `link`, `publish`, `models`, and others) are authenticated API calls, and Studio records that your account and organization used the CLI, the same way it records use of the web app. Anonymous local usage is never linked to an account.

---

### Mcp Overview (`docs/mcp/overview.mdx`)

---
title: 'Overview'
description: 'Connect AI clients to Evidence with the Model Context Protocol.'
---

## What is MCP?

The [Model Context Protocol](https://modelcontextprotocol.io) is an open standard that enables AI applications to connect to external data sources and tools. Evidence provides two MCP servers.

<CardGroup cols={2}>
  <Card title="Studio MCP" icon="database" href="/mcp/studio">
    Connect an AI client to your live Evidence workspace — search reports and query your data. Requires authentication.
  </Card>
  <Card title="Docs MCP" icon="book-open" href="/mcp/docs">
    A developer tool that searches the Evidence documentation. No authentication required.
  </Card>
</CardGroup>

## Which one do I want?

- **Querying your own data and reports?** Use the **[Studio MCP](/mcp/studio)** — it connects to your live workspace with your permissions.
- **Developing reports?** Use the **[Docs MCP](/mcp/docs)** — it searches the docs and component reference.

---

### Self Host Index (`docs/self-host/index.mdx`)

---
title: 'Self Host'
description: 'Host your Evidence project on platforms including Vercel, Render, Fly.io, and Railway.'
---

Evidence projects can be self-hosted with the official [Docker image](https://hub.docker.com/r/evidencedev/serve).

The image runs [`evidence serve`](/cli/commands#evidence-serve), which is similar to `evidence dev` but hardened as a production server.

Self-hosted projects _must_ use a direct connector (configured in [`connection.yaml`](/cli/connections)).

Docker containers can run on many platforms, major cloud providers or your own machine. See the below guides for some tested options:

- [Vercel](/self-host/vercel)
- [Render](/self-host/render)
- [Fly.io](/self-host/fly)
- [Railway](/self-host/railway)

## Should you self host?

Self hosting is appropriate if:

1. Your organization requires data does not leave your infrastructure
2. You have a hobby project and do not want to pay for a managed service

However, you should be aware that there are tradeoffs associated with self hosting Evidence projects:

- [Several platform features](#self-host-vs-evidence-studio) (e.g. User Auth, Access Controls, Evidence Agents) are not built in
- There are no platform fees, but you will incur costs from infrastructure and maintenance
- You need to handle security, monitoring, and scaling on your own

## Generic Docker Deployment

Details may differ, but these steps are required for all Docker deployments.

1. Add a `Dockerfile`:

   ```docker filename="Dockerfile"
   FROM evidencedev/serve:latest
   COPY --chown=evidence:evidence . /project
   ```

2. Move secrets out of `connection.yaml`, replacing them with `${VAR}` environment references
3. Commit `connection.yaml` (it is gitignored by default)
4. Add environment variables

   | Env Var                   | Purpose                                        | Required? |
   | ------------------------- | ---------------------------------------------- | --------- |
   | `EVIDENCE_BASIC_USER`     | HTTP Basic Auth username                       | Yes\*     |
   | `EVIDENCE_BASIC_PASSWORD` | HTTP Basic Auth password                       | Yes\*     |
   | `${VAR}` references       | All variables referenced in `connection.yaml`  | Yes       |
   | `EVIDENCE_AUTH_DISABLED`  | Skip auth entirely on trusted private networks | -         |
   | `PORT`                    | Port the server listens on (default: 3000)     | -         |
   | `EVIDENCE_TELEMETRY_DISABLED` | Turn off the anonymous startup event and daily heartbeat ([details](/cli#telemetry)) | -         |

   \* Unless auth disabled

5. Start the server

## Self Host vs. Evidence Studio

Self-hosting allows you to render your SQL + markdown into interactive reports — but the Evidence Studio platform has many additional features:

| Feature                                                | Self Host       | Evidence Studio                          |
| ------------------------------------------------------ | --------------- | ---------------------------------------- |
| Rendering reports                                      | ✓               | ✓                                        |
| [Direct connectors](/cli/connections)                  | ✓               | ✓                                        |
| [Evidence Warehouse](/evidence-warehouse)   | —               | ✓                                        |
| [SQL models](/core-concepts/models)                    | —               | ✓                                        |
| Auth                                                   | HTTP Basic Auth | SSO with viewer, developer & admin roles |
| [Access controls](/features/page-level-access-control) | —               | ✓                                        |
| [Row-level security](/features/row-level-security)           | —               | ✓                                        |
| Developer Agent                                        | —               | ✓                                        |
| Viewer Agent                                           | —               | ✓                                        |
| Web editor & real-time collaboration                   | —               | ✓                                        |
| [Embedded analytics](/features/embedded-analytics)       | —               | ✓                                        |
| [Studio MCP server](/mcp/studio)                       | —               | ✓                                        |

## Authentication

Self-hosted sites are protected by HTTP Basic Auth. The browser caches credentials in memory until the browser is exited (there is no logout button).

To force all viewers to re-authenticate, change `EVIDENCE_BASIC_PASSWORD` and redeploy.

For deployments only reachable over a trusted private network (VPN, Tailscale, internal VPC), set `EVIDENCE_AUTH_DISABLED=true` to skip authentication entirely.

To authenticate users against your organization's identity provider, deploy `evidence serve` behind an authenticating reverse proxy — see [Authentication & SSO](/self-host/authentication).

---

### Changelog (`docs/changelog.mdx`)

---
title: 'Changelog'
description: 'Track the latest updates and improvements to Evidence'
rss: true
---


{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

<Update label="October 15, 2026" description="" tags={["New Feature"]}>

### ✨ AI chat in embedded reports

Embedded reports can now show the Evidence AI chat, so your users can ask questions about a report without leaving your application. Embedding customers opt in per session with the `enableAIChat` parameter on the embed API.

</Update>

<Update label="October 15, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Organization switching for viewers

Fixed an issue that blocked viewers from switching organizations in the published app.

</Update>

<Update label="October 14, 2026" description="" tags={["Improvement"]}>

### 🚀 Big values fit two to a line on phones

On phones, big values now sit two to a line instead of stacking one per line.

</Update>

<Update label="October 14, 2026" description="" tags={["Improvement"]}>

### 🚀 Render html blocks without a card

On pages with card mode enabled, `{% html card=false %}` renders the block directly on the page background instead of inside a card.

</Update>

<Update label="October 14, 2026" description="" tags={["New Feature"]}>

### ✨ Preview pages at mobile width in the editor

A new toggle on the editor's preview pane narrows the preview to phone width, so you can check how a page reads on mobile without resizing your browser.

- Mobile-specific behavior shows in the preview too: `details` honors `open_mobile`, and modals open as they would on a phone, inside the preview.
- `dimension_grid` now wraps based on its own width rather than the browser's, so it lays out correctly in narrow columns as well as on phones.

</Update>

<Update label="October 14, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Stacked areas no longer have holes

Fixed gaps in stacked area charts on date axes when a series has no data for some dates.

</Update>

<Update label="October 13, 2026" description="" tags={["New Feature"]}>

### ✨ Hide or show content in print without grouping it

New `{% hidden_in_print %}` and `{% only_in_print %}` blocks control what appears in printed pages and PDFs, without the blank gaps `print_group` can leave.

</Update>

<Update label="October 9, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Reopening an invitation link takes you to your organization

Reopening an invitation you've already accepted while signed in now takes you into that organization instead of showing an error.

</Update>

<Update label="October 8, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Improved PDF exports

Fixed charts that could be missing from PDF exports.

</Update>

<Update label="October 7, 2026" description="" tags={["New Feature"]}>

### ✨ Commentary per input selection

Commentary can now be kept separately for each selected value of one or more inputs, alongside the reporting period.

[View Documentation](https://docs.evidence.studio/components/commentary)

</Update>

<Update label="October 7, 2026" description="" tags={["New Feature"]}>

### ✨ Page download options

Hide download options from a published page's menu with the `downloads` page setting.

</Update>

<Update label="October 7, 2026" description="" tags={["New Feature"]}>

### ✨ Period selector component

Added a period selector input, which can also place a page's reporting period anywhere on the page.

[View Documentation](https://docs.evidence.studio/components/period_selector)

</Update>

<Update label="October 7, 2026" description="" tags={["New Feature"]}>

### ✨ Print-only content

Show content only in printed pages and PDFs with `{% print_group print_only=true %}`.

</Update>

<Update label="October 7, 2026" description="" tags={["Improvement"]}>

### 🚀 Improved row layout

Rows can now spread their contents across the full width, for example a heading on the left and a button on the right.

[View Documentation](https://docs.evidence.studio/components/row)

</Update>

<Update label="October 6, 2026" description="" tags={["New Feature"]}>

### ✨ Generate Excel Report

A new **Generate Excel Report** option exports the page as an Excel workbook with a snapshot of the report on the first sheet and a data sheet per component; **Download Data** now also appears in the CLI.

- **Download Data** is unchanged and still exports data only; pick **Generate Excel Report** when you want the report snapshot included.
- Hide it with `downloads: { excel: false }` in page frontmatter. It is also hidden when `image` or `data` downloads are turned off.
- The local CLI viewer now has **Download Data** and **Generate Excel Report** in its page menu.

</Update>

<Update label="October 6, 2026" description="" tags={["Improvement"]}>

### 🚀 Improved info tooltips

Info tooltips now support text across multiple lines.

</Update>

<Update label="October 1, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Improved date axis labels

Improved the layout of date labels on chart axes.

</Update>

<Update label="September 29, 2026" description="" tags={["New Feature"]}>

### ✨ Attach files to reports

Drop or paste a file into the editor to upload it and insert a `file` card showing its icon, name, type, and date.

</Update>

<Update label="September 29, 2026" description="" tags={["Improvement"]}>

### 🚀 Set down_is_good for a whole page

Add `down_is_good: true` to a page's frontmatter to treat decreases as good for every delta on that page.

- Applies to `big_value`, `delta`, and table delta columns. A component's own `down_is_good` still overrides it.
- `down_is_good=true` on a `benchmark_comparison` or `target_comparison` option is now respected when a component uses that `comparison_selector`.

</Update>

<Update label="September 26, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Tables inside repeat blocks now read page inputs

A `table` inside a `{% repeat %}` block now resolves page inputs referenced in its `where`, `having`, `order`, and `qualify` attributes instead of running with the value missing.

- Previously the table only looked at the repeat's own scope, so `{{my_input}}` in these attributes interpolated as empty and the query failed with a syntax error.
- Titles and other text attributes on the same table also resolve page inputs correctly now.

</Update>

<Update label="September 24, 2026" description="" tags={["Bug Fix"]}>

### 🐛 CLI runs direct-connector projects without reaching Evidence Studio

`evidence dev` no longer refuses to start when evidence.studio is unreachable for projects with a `connection.yaml`, `evidence upgrade` now works on Windows, and the home page honours `page_width` and `cards` like every other page.

- Projects with a `connection.yaml` skip the Studio reachability check entirely; projects on the Evidence Warehouse get a warning (with the failure reason and a proxy hint) instead of a hard exit.
- `evidence dev` prints which mode it is in — direct connector or managed warehouse — so it is clear whether a login is needed.
- `evidence upgrade` supports Windows x64 and Linux arm64, keeps `evd.exe` in sync on Windows, and points to the installer when the update check fails.
- `evidence serve` is listed in `evidence help`.
- `pages/home.md` now respects `page_width`, `cards`, `table_of_contents` and frontmatter `theme`, matching subpages.

</Update>

<Update label="September 24, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Viewer log out fix

Fixed logging out from a published report showing a "Page not found" error and leaving you signed in.

</Update>

<Update label="September 23, 2026" description="" tags={["Improvement"]}>

### 🚀 Details start state on mobile

The `details` component has a new `open_mobile` attribute to choose whether it starts open or collapsed on mobile screens, independently of `open`

[View Documentation](https://docs.evidence.studio/components/details)

</Update>

<Update label="September 23, 2026" description="" tags={["New Feature"]}>

### ✨ Validation summary in the editor

A new indicator in the editor toolbar shows how many validation errors are on the open file. Click it to see every error with its line number, and click an error to jump to it in the editor.

- Covers component errors, inline SQL query errors, and config file (yaml) validation.
- Each entry is labeled with the component, query, or config key it belongs to.
- Clicking an error scrolls the editor to the line and highlights it.

</Update>

<Update label="September 22, 2026" description="" tags={["Bug Fix"]}>

### 🐛 CLI keeps input selections in the URL

Input components in `evidence dev` and self-hosted CLI pages now write their selections to the URL and restore them from it, so filtered views can be refreshed, bookmarked and shared like in Studio.

</Update>

<Update label="September 22, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Commentary save fix

Fixed an issue where some commentary saves did not persist.

[View Documentation](https://docs.evidence.studio/components/commentary)

</Update>

<Update label="September 22, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Filter defaults no longer appear in URL

A `table_filter` with `initial_values` no longer writes its default into the page URL, so other pages keep showing their own data instead of inheriting that default and filtering against the wrong values.

</Update>

<Update label="September 21, 2026" description="" tags={["New Feature"]}>

### ✨ Commentary supports workflow periods

Commentary components can now keep separate notes for each reporting period with `scope="period"`.

- Period-scoped commentary follows the page's `workflow.period` picker, including in PDF renders.
- Commentary without `scope` remains page-wide.

[View Documentation](https://docs.evidence.studio/components/commentary)

</Update>

<Update label="September 21, 2026" description="" tags={["New Feature"]}>

### ✨ Waterfall chart

The `waterfall_chart` component is now available - useful for growth decomposition, revenue bridges, and reconciliations

[View Documentation](https://docs.evidence.studio/components/waterfall_chart)

</Update>

<Update label="September 17, 2026" description="" tags={["New Feature"]}>

### ✨ Search team members

Filter your team settings page by name or email with a new search field.

</Update>

<Update label="September 16, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Slack channel picker finds every channel the bot is in

Fix the scheduled report Slack channel dropdown missing channels the Evidence bot had joined in large workspaces with many channels.

</Update>

<Update label="September 15, 2026" description="" tags={["Improvement"]}>

### 🚀 Improved content selection in PDF download menu

Simpler click behaviour to select and deselect content in nested sections.

</Update>

<Update label="September 15, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Table cells only merge within their parent group

Fix table dimension cells merging across rows whose parent dimension values differ, such as after sorting by a measure.

</Update>

<Update label="September 7, 2026" description="" tags={["Improvement"]}>

### 🚀 Resume GitHub Enterprise connections

GitHub Enterprise Cloud connections can now resume after another organization owner installs the app, with clearer errors and controls for unfinished attempts.

- Finish connecting from GitHub integration settings when the installation callback is missed.
- Allow up to seven days for installation after app registration.
- Resume or cancel an unfinished connection instead of creating another app on each retry.
- See an error message and request ID when a connection needs support.

</Update>

<Update label="September 2, 2026" description="" tags={["New Feature"]}>

### ✨ Reporting periods

Turn a page into a periodic report with a `workflow.period` block in frontmatter.

- Adds a period picker at the top right of the page, listing complete calendar periods (day, week, month, quarter or year)
- The selected period is available as the `period` variable — `{{ period.label }}` in markdown, `{{ period.between }}` in SQL
- Only finished periods are offered, so a published report doesn't change while its period is still running
- The selection is kept in the URL, so a link points at a specific period

[View Documentation](https://docs.evidence.studio/features/page-settings#workflow-period)

</Update>

<Update label="August 28, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Dropdown options on Cube

Fix data-driven dropdowns returning no options when connected to a Cube warehouse.

</Update>

<Update label="August 24, 2026" description="" tags={["New Feature"]}>

### ✨ Scheduled report using email or Slack

Scheduled report using email or Slack

[View Documentation](https://docs.evidence.studio/features/scheduled-reports)

</Update>

<Update label="August 20, 2026" description="" tags={["New Feature"]}>

### ✨ More control over color scales

Color scales in tables and map layers now support diverging midpoints and custom value-to-color breakpoints, and behave consistently across both.

- Set `midpoint` to anchor a diverging scale at a value such as 0, and `min`/`max` to fix the scale bounds.
- Use `color_stops` to pin specific colors to specific values.
- Diverging scales stay correct even when every value falls on one side of the midpoint.

</Update>

<Update label="August 19, 2026" description="" tags={["Improvement"]}>

### 🚀 Improved error display

Components now display syntax and query errors more prominently in the editor.

</Update>

<Update label="August 19, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Reliable map layer filter updates

Area, point, and heatmap layers now reliably update when filters change their data.

</Update>

<Update label="August 18, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Table filter values on Snowflake

Fix the table filter returning no selectable values on Snowflake and other uppercase-folding warehouses.

</Update>

<Update label="August 16, 2026" description="" tags={["New Feature"]}>

### ✨ Folder-Level Access Rules

Add folder-level access rules to `access.yaml` — grant or restrict every page in a directory subtree with a single entry.

</Update>

<Update label="August 14, 2026" description="" tags={["New Feature"]}>

### ✨ Scheduled Reports

Email reports to your users on a regular schedule, or send one-off reports on demand.

[View Documentation](https://docs.evidence.studio/features/scheduled-reports)

</Update>

<Update label="August 14, 2026" description="" tags={["New Feature"]}>

### ✨ Access Viewer AI inside Slack

Connect a Slack workspace in Integration settings and message the Evidence bot to get answers from your data without leaving Slack.

- An admin adds the app from Settings → Integrations → Slack, then each person connects their own account — the bot only reads what you can already see.
- Direct message the bot, or @mention it in a channel.
- Answers can display charts, save insights to your library, and link back into Evidence.
- Admins can turn the bot off for the whole organization, and choose whether each person's first answer in a channel is shown to them before the channel sees it.

</Update>

<Update label="August 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Partial filter initial values now apply on parent pages

Fixed an issue where filter initial values defined in partials could be empty when rendered on parent pages.

</Update>

<Update label="August 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Filters load in partial page previews

Filters in partials now load when using View another page in the editor.

</Update>

<Update label="August 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Link buttons support relative page URLs

Link buttons now navigate correctly with portable relative URLs across edit, preview, and published reports.

</Update>

<Update label="August 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Table filters close safely without selections

Table filters now remain visible when a numeric or date picker is closed without a selection.

</Update>

<Update label="August 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Sorting a table by a column it does not show

Sorting a table by a column that is not one of its dimensions or measures no longer splits the rows into extra groups, and no longer fails on Postgres, Fabric and Cube.

</Update>

<Update label="August 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 ClickHouse conditional aggregates

Fix `sumIf` and its `-If` siblings breaking date-filtered measures and comparison targets on ClickHouse, and no longer warn that they are missing an aggregation.

</Update>

<Update label="August 12, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Snowflake table conditional colors

Fix conditional colors on table dimensions in Snowflake for literal colors and SQL expressions.

</Update>

<Update label="August 12, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Sorting a table by a grouped date column

Sorting a table by a date column that has a `date_grain` now sorts by the grouped date instead of failing with a grouping error.

- `order="my_date desc"` alongside `{% dimension value="my_date" date_grain="day" /%}` sorted by the raw column, which the warehouse never grouped. ClickHouse rejected the query and the table rendered empty.
- A hidden sort column on a table with subtotals is now aggregated, so it no longer breaks the subtotal and total rows.

</Update>

<Update label="August 7, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Creating files and folders is disabled on protected branches

The sidebar's create page, partial, SQL, component, folder, and agent-file actions are now disabled when the current branch is protected on GitHub, matching the existing branch-protection guard on Commit.

</Update>

<Update label="August 5, 2026" description="" tags={["New Feature"]}>

### ✨ Bring your own model API key

Enterprise organizations can now point both AI agents at their own OpenAI, Anthropic, AWS Bedrock, or Google Vertex account from Settings → AI Agent.

- Both the editor agent and the viewer agent use your provider and model, so your provider bills you for inference directly and Evidence AI credits are neither consumed nor charged.
- Credentials are stored in the WorkOS Vault and never sent back to the browser. Saving verifies the credential against your provider first, so a wrong key or model ID is rejected rather than stored.
- There is no fallback to Evidence's models: if your credential stops working, chat reports a clear error instead of quietly switching back and billing you for credits.

</Update>

<Update label="July 31, 2026" description="" tags={["Improvement"]}>

### 🚀 Big value titles are clickable when linked

Setting `link` on a big value now turns the title into a styled link instead of the number, matching typical score card conventions.

</Update>

<Update label="July 31, 2026" description="" tags={["New Feature"]}>

### ✨ Metrics

Evidence now has a metrics layer. Define metrics in `metrics/*.yaml` and reference them in charts and tables. Ask the agent to build one for you to get started.

</Update>

<Update label="July 30, 2026" description="" tags={["New Feature"]}>

### ✨ MCP Visualize Tool

The Evidence Studio Claude Connector and ChatGPT Plugin can now generate charts inline in the chat with the new `visualize` tool.

</Update>

<Update label="July 30, 2026" description="" tags={["New Feature"]}>

### ✨ Reports page for run history and schedules

A new top-level Reports page (next to Models) for viewing report run history and managing schedules.

- **History tab**: View all report runs with status, trigger type (manual/schedule/API), author, timing, and recipient count
- **Schedules tab**: View and manage recurring report schedules with pause/resume and delete actions
- **Admin-only actions**: Pause/resume schedules, delete schedules, re-run past reports, download PDFs
- **Developer access**: Developers (members) can view the page; admins can take all actions
- **Entitlement gate**: Available on Team, Pro, and Enterprise plans

[View Documentation](https://docs.evidence.studio/features/scheduled-reports)

</Update>

<Update label="July 29, 2026" description="" tags={["New Feature"]}>

### ✨ GitHub Enterprise Cloud support

Enterprise organizations can now connect Evidence Studio and the Evidence CLI to GitHub Enterprise Cloud accounts hosted on dedicated `*.ghe.com` domains.

- Create and install a private, organization-owned GitHub App through Organization Settings.
- Select accessible enterprise repositories in Project Settings and use Studio branches, pull requests, checks, and publishing as usual.
- Run `evidence launch` or `evidence link` from HTTPS and SSH GHE.com remotes.

</Update>

<Update label="July 28, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Feature request dialogs remain accessible with long descriptions

Feature request dialogs now constrain long descriptions to a scrollable area so their controls remain accessible.

</Update>

<Update label="July 27, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Table links now work in fullscreen reports

Table links now navigate to their destination while viewing a report in fullscreen presentation mode.

</Update>

<Update label="July 27, 2026" description="" tags={["New Feature"]}>

### ✨ MotherDuck direct connector

Connect Evidence directly to a MotherDuck database to build reports on live data without syncing it first.

[View Documentation](https://docs.evidence.studio/direct-connectors/motherduck)

</Update>

<Update label="July 26, 2026" description="" tags={["New Feature"]}>

### ✨ Custom Maps

Use the `custom_map` component to build fully customized maps with Mapbox GL or MapLibre GL.

- Write map code directly in the component body — pull page data with `evidence.query`, read and write page filters, and react to variables and theme changes.
- No key needed by default: keyless MapLibre out of the box, or Mapbox using Evidence's shared token under the hood.
- Import map-ecosystem plugins (mapbox-gl-draw, deck.gl, turf, and more) straight from a CDN.

</Update>

<Update label="July 25, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Custom HTML and ECharts blocks work in the CLI

`{% html %}` and `{% custom_echart %}` blocks now render when running a project locally with the Evidence CLI.

- Both blocks previously rendered blank in `evidence dev` — the sandbox runtime they load was only built by the hosted app, so the CLI served nothing for it
- Requires CLI v0.7.4 or later
- If a sandbox runtime is ever missing, the block now reports an explicit error instead of staying blank

</Update>

<Update label="July 24, 2026" description="" tags={["Improvement"]}>

### 🚀 AI chat now consumes far fewer credits

We've significantly reduced how many credits AI chat consumes, so your balance goes much further.

</Update>

<Update label="July 24, 2026" description="" tags={["New Feature"]}>

### ✨ Cube Connector

Connect Evidence directly to your Cube semantic layer through its Postgres-wire SQL API.

- Query your cubes and views live from Evidence — metrics stay defined in Cube.
- Configure it in **Connectors → Warehouse → Cube** (host, port, user, password, SSL), or via `connection.yaml` (`type: cube`) in the CLI.
- The SQL editor validates expressions against Cube's documented function subset, so unsupported functions are flagged before you run a query.

</Update>

<Update label="July 24, 2026" description="" tags={["New Feature"]}>

### ✨ PDF "Use page colors" option

Preserve the exact colors from your page when generating PDFs.

- New "Use page colors" checkbox in the PDF settings modal (Cmd+P)
- When enabled, PDFs retain the theme's actual background colors (including dark mode or custom theme backgrounds)
- When disabled (default), PDFs use white backgrounds optimized for printing
- Preview updates to show how the PDF will look with the selected option

</Update>

<Update label="July 23, 2026" description="" tags={["New Feature"]}>

### ✨ Postgres Direct Connector

Connect Evidence directly to Postgres — including Amazon RDS/Aurora, Supabase, Neon, and Timescale — and query it live.

- Add Postgres under Settings → Warehouse: enter host, port, database, user, password, and SSL mode, test the connection, and save.
- Works with any Postgres-wire source: generic Postgres, Amazon RDS / Aurora, Supabase, Neon, and Timescale.
- Full SSL/TLS support with `disable` / `require` / `verify-ca` / `verify-full` modes, plus an optional CA bundle and mutual-TLS client certificate.
- The schema browser lists tables, views, and materialized views.
- Also available from the CLI via `connection.yaml` (`type: postgres`) or `evidence init --warehouse postgres`, with certificates referenced by file path.

</Update>

<Update label="July 22, 2026" description="" tags={["New Feature"]}>

### ✨ Search across your reports with Cmd+K

Press Cmd/Ctrl+K to instantly search across every report you have access to.

</Update>

<Update label="July 22, 2026" description="" tags={["New Feature"]}>

### ✨ Viewer AI & Insights

Report viewers can now ask questions of your data in a chat assistant and save the answers as insights to revisit later.

</Update>

<Update label="July 21, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed editor inserting characters at the wrong position on older reports

Typing in the editor now appears where you clicked on reports created before mid-2026.

</Update>

<Update label="July 20, 2026" description="" tags={["New Feature"]}>

### ✨ Evidence Studio MCP Server

Search your reports and query your data from your favorite AI client. Connect Claude, ChatGPT, and other MCP clients to your live Evidence workspace — every request runs as the signed-in user, so access policies and page controls are respected.

[View Documentation](https://docs.evidence.studio/mcp/studio)

</Update>

<Update label="July 17, 2026" description="" tags={["Bug Fix"]}>

### 🐛 CLI dev server no longer crashes when a subfolder has an index.md

Nested `index.md` / `home.md` / `README.md` files are no longer treated as the home page in the sidebar, so `evidence dev` renders normally instead of crashing with a duplicate-key error when a project has a root home page plus an `index.md` in a subfolder.

</Update>

<Update label="July 16, 2026" description="" tags={["New Feature"]}>

### ✨ Point Map Clustering

You can now include up to 100,000 points in a point layer by using `cluster=true`. Nearby points are grouped into aggregated bubbles that split apart as you zoom in, so large datasets stay fast and readable.

</Update>

<Update label="July 12, 2026" description="" tags={["New Feature"]}>

### ✨ 50 New Data Connectors

Connect 50 more data sources to Evidence, including Zendesk, Intercom, Mixpanel, Amplitude, Square, QuickBooks, Recurly, Pipedrive, Gong, LinkedIn Ads, and more. Set them up in a few clicks from the Connectors page.

</Update>

<Update label="July 12, 2026" description="" tags={["New Feature"]}>

### ✨ 50 More Data Connectors

Another 50 data sources are now available, including Jira, Airtable, Asana, Notion, Slack, Klaviyo, Mailchimp, Braze, SendGrid, TikTok Ads, Amazon Ads, Google Search Console, ServiceNow, and Okta. Set them up in a few clicks from the Connectors page.

</Update>

<Update label="July 12, 2026" description="" tags={["New Feature"]}>

### ✨ Lemlist Connector

Connect your Lemlist data to Evidence. Sync campaigns, leads, and activities from your email outreach.

[View Documentation](https://docs.evidence.studio/data-sources/lemlist)

</Update>

<Update label="July 12, 2026" description="" tags={["Improvement"]}>

### 🚀 Improved chart x-axis and tooltip labels

Better handling of dates and numbers on chart x-axes and tooltips.

</Update>

<Update label="July 10, 2026" description="" tags={["New Feature"]}>

### ✨ Table Access Restrictions

Restrict tables to a chosen set of users

Restrict specific tables to a chosen set of users from the Access Rules settings page. Unrestricted tables stay open to everyone in the organization, and restricted tables show a lock badge in the editor's schema list.

[View Documentation](https://docs.evidence.studio/features/row-level-security)

</Update>

<Update label="July 8, 2026" description="" tags={["New Feature"]}>

### ✨ Image component accepts data queries

Add `data` and `column` props to the image component to load the image URL from a query and respond to filter changes — e.g. show the top-selling product's photo, a client logo driven by a dropdown, or a dark-mode variant via `dark_column`.

</Update>

<Update label="July 8, 2026" description="" tags={["New Feature"]}>

### ✨ Radar, Treemap, and Chord charts

Three new charts now available: radar_chart, treemap, and chord_chart

</Update>

<Update label="July 8, 2026" description="" tags={["New Feature"]}>

### ✨ Mix single and multi select columns in table filters

Add `single_select` and `multi_select` to `table_filter` to set the selection mode per column — e.g. restrict a client column to one value at a time while keeping region and product filters multi-select.

</Update>

<Update label="July 8, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Y-axis titles stay legible above chart data

Chart contents no longer overlap the y-axis title — bars, areas, and lines that reach the top of the axis now render beneath the title instead of covering it. Gridlines are cut off cleanly behind the title rather than showing through the text, the title is vertically aligned with the top axis tick label, and a subtle text outline keeps it readable when data passes directly beneath it. Applies to both left and right (`y2`) axis titles.

</Update>

<Update label="July 7, 2026" description="" tags={["Bug Fix"]}>

### 🐛 range_calendar "all time" no longer breaks raw SQL

Referencing `{{ date_filter.between }}` in a `where` or SQL template while "all time" was selected previously produced an empty string, which broke the query (`where date ` → syntax error). `.between` now emits `IS NOT NULL` for "all time", so `where="date {{ date_filter.between }}"` matches all rows and just works.

The new `all_time_range` attribute controls what "all time" means for a specific `range_calendar`:

- `all_time_range="none"` restores the previous empty-string behavior — pair it with `[[ ]]` conditional blocks or a `| fallback` when the whole clause should drop (e.g. to keep NULL-date rows, which `IS NOT NULL` otherwise excludes).
- Set it to a bounded range — a preset key (`"last 12 months"`), a `custom_ranges` label, or a range expression (`"from 2022-12-01"`) — and "all time" resolves to that range everywhere (`.between`, `.start`, `.end`, and the `date_range` value). If you were faking this with a `| fallback` in your `where` clause, set `all_time_range` to that range and delete the fallback.

`.start` / `.end` stay empty for unbounded "all time" (so date spines and axes fail loudly rather than silently wrong), and `.filter` / a `filters=[...]` reference stay a true no-op that keeps NULL rows.

</Update>

<Update label="July 2, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix for AI chat losing conversation context

Fixed an issue where the AI chat could respond to an earlier message in long conversations instead of the one you just sent.

</Update>

<Update label="July 2, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Sparkline hover values now use theme foreground

Sparkline hover values and the vertical tracking line follow the theme's foreground and muted-foreground tokens, restoring contrast in light mode (most visible on big_value sparklines).

</Update>

<Update label="July 1, 2026" description="" tags={["New Feature"]}>

### ✨ AI Agent Multi-File Edits

The AI dev assistant can now edit multiple files in a single turn — as well as create, rename, and move files.

</Update>

<Update label="July 1, 2026" description="" tags={["New Feature"]}>

### ✨ Extra tooltip rows on chart series

Add `tooltip_fields` to any `bar_chart` / `line_chart` / `area_chart` / `scatter_chart` / `bubble_chart` — or to `bar`, `line`, `area`, `scatter`, `bubble` inside a `combo_chart` — to surface additional aggregated values on hover, with optional labels, format codes, and `color_by_sign` / `down_is_good` for delta-style coloring.

</Update>

<Update label="June 29, 2026" description="" tags={["New Feature"]}>

### ✨ Link charts together

Add `connect_group` to charts to sync their tooltips, axis-pointer, and zoom across any charts sharing the same id — e.g. stack a price chart above a volume chart, align KPIs that share a time axis, or coordinate small multiples.

</Update>

<Update label="June 27, 2026" description="" tags={["New Feature"]}>

### ✨ Customize built-in charts with ECharts options

Override any ECharts option on built-in charts via `echarts_options` (chart-wide) or `echarts_series_options` (looped across every series).

</Update>

<Update label="June 26, 2026" description="" tags={["New Feature"]}>

### ✨ Attach images to editor AI chat

Click the image button in the editor chat composer to attach screenshots or other images for the AI agent to see alongside your message.

</Update>

<Update label="June 26, 2026" description="" tags={["New Feature"]}>

### ✨ Custom components

Build your own Markdoc tags from `components/*.md` files — each component declares its attributes in frontmatter and gets autocomplete, slash-command, and AI-tool support just like a built-in.

</Update>

<Update label="June 26, 2026" description="" tags={["New Feature"]}>

### ✨ Pin color scale values in tables

Anchor a measure's color scale to specific data values with `color_stops`.

</Update>

<Update label="June 25, 2026" description="" tags={["New Feature"]}>

### ✨ Custom HTML in reports

Embed your own HTML and JavaScript anywhere in a report with the new `{% html %}` block. Build custom visualizations that integrate with Evidence's filters, queries, and theme — using any library, like D3 or deck.gl.

</Update>

<Update label="June 24, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Hide unneeded subtotal rows in tables

Tables now hide duplicative subtotal rows that only summarize a single item, while keeping the grand total.

</Update>

<Update label="June 24, 2026" description="" tags={["New Feature"]}>

### ✨ Expanded theme options

Themes now include fonts, colors, corner roundness, spacing density, and chart defaults, applied consistently across the whole report. Override the theme for a single page when you need to.

</Update>

<Update label="June 23, 2026" description="" tags={["New Feature"]}>

### ✨ Custom date ranges

Add `custom_ranges` to `{% range_calendar %}` to generate named presets — e.g. fiscal years, seasons, and retail calendars.

</Update>

<Update label="June 18, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Smoother schema panel refresh

The refresh button no longer pushes content down or hides the schema list while reloading, and long table or column names truncate instead of forcing horizontal scroll.

</Update>

<Update label="June 17, 2026" description="" tags={["New Feature"]}>

### ✨ Show size dimension in bubble and scatter chart tooltips

Bubble and scatter chart tooltips now display the size dimension value, with a new `size_fmt` attribute for formatting.

</Update>

<Update label="June 17, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Faster, more reliable editor preview on heavy pages

Fixed an issue where the editor could lock up on pages with many charts and tables.

</Update>

<Update label="June 17, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix heatmap collapsing at wider screen widths

Fixed heatmap charts collapsing into a small box at certain screen widths.

</Update>

<Update label="June 17, 2026" description="" tags={["New Feature"]}>

### ✨ Impersonate

Create and manage access tokens for programmatic API access from the new Access Tokens settings page. Admins and developers can impersonate team members to see exactly what they see (disabled by default).

</Update>

<Update label="June 16, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix dropdown search failing on BigQuery

Fixed an issue with searching a dropdown or table filter for BigQuery direct connections.

</Update>

<Update label="June 16, 2026" description="" tags={["New Feature"]}>

### ✨ Failed Publishes No Longer Affect Viewers

If a publish fails, your project keeps serving the last successful version — viewers never see broken content.

</Update>

<Update label="June 16, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix spurious markdown validation errors on PRs

Fixed the PR markdown-validation check reporting false-positive `undefined-translation-key` and `undefined-frontmatter-variable` errors on pages using translations and on partials that receive variables from the pages including them.

</Update>

<Update label="June 16, 2026" description="" tags={["New Feature"]}>

### ✨ Publish History & Rollback

View your project's publish history and roll back to any previous version.

</Update>

<Update label="June 14, 2026" description="" tags={["New Feature"]}>

### ✨ ClickHouse direct connector

Connect Evidence directly to your own ClickHouse instance to build reports on live data without syncing it first.

[View Documentation](https://docs.evidence.studio/direct-connectors/clickhouse)

</Update>

<Update label="June 12, 2026" description="" tags={["New Feature"]}>

### ✨ Make the selected option in `button_group` and `input_tabs` more noticeable

The selected button in `button_group` and the active tab in `input_tabs` now stand out more clearly.

</Update>

<Update label="June 10, 2026" description="" tags={["New Feature"]}>

### ✨ New share menu and additive page access

The redesigned share menu lets you grant page-level access on top of project access, so you can share a single dashboard with a stakeholder who shouldn't see anything else.

</Update>

<Update label="June 10, 2026" description="" tags={["New Feature"]}>

### ✨ Vibe code any visualization with the custom_echart component

Need a chart Evidence doesn't have out of the box — a waterfall, a bridge, a radar, something bespoke? The new `custom_echart` component lets you build any visualization you can imagine. Describe what you want to the assistant and it writes the chart for you, wired up to your data, filters, and theme automatically.

</Update>

<Update label="June 10, 2026" description="" tags={["New Feature"]}>

### ✨ Pre-select the top N options in a multi-select dropdown

Multi-select dropdowns now accept a `default_top_n` attribute that pre-selects the first N options on load. Combine it with `order` to control which N are selected by default — which viewers can then change.

</Update>

<Update label="June 7, 2026" description="" tags={["New Feature"]}>

### ✨ New Publish Menu in Editor

View pending changes and open pull requests directly from Studio.

</Update>

<Update label="June 6, 2026" description="" tags={["New Feature"]}>

### ✨ See what each user, group, and customer can access

Admins and developers can now see every project and page a user, group, or customer can access, plus how that access was granted.

</Update>

<Update label="June 4, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Share menu now lets you grant page access to any team member

The Page tab of the share menu now lists every internal team member, so you can grant page access directly without first adding them to the parent project.

</Update>

<Update label="June 4, 2026" description="" tags={["Improvement"]}>

### 🚀 Add users to groups when inviting, and see group memberships in the team table

Admins can now pick groups when inviting or manually creating users, and the Team settings page shows each member's group memberships in its own column.

</Update>

<Update label="June 1, 2026" description="" tags={["Improvement"]}>

### 🚀 HubSpot Connector

Updated the HubSpot connector with more reliable syncs and broader table coverage.

[View Documentation](https://docs.evidence.studio/data-sources/hubspot)

</Update>

<Update label="June 1, 2026" description="" tags={["New Feature"]}>

### ✨ Microsoft Fabric direct connector

Connect Evidence directly to a Microsoft Fabric Warehouse or Lakehouse SQL endpoint to build reports on live data without syncing it first.

[View Documentation](https://docs.evidence.studio/direct-connectors/fabric)

</Update>

<Update label="June 1, 2026" description="" tags={["Bug Fix"]}>

### 🐛 PDF exports preserve dropdown filter values

PDF exports of pages with a `select_first=true` dropdown no longer revert the filter to its auto-selected default when the URL specifies a different value.

</Update>

<Update label="May 29, 2026" description="" tags={["New Feature"]}>

### ✨ Map area layer min, max, and midpoint

Map `area_layer` and `point_layer` now accept `min`, `max`, and `midpoint` props so you can pin a diverging color scale at zero (or any other value).

</Update>

<Update label="May 29, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed bar chart tooltip not displaying point_title

Fixed an issue where the `point_title` attribute on bar, line, and area charts was ignored in the tooltip.

</Update>

<Update label="May 25, 2026" description="" tags={["New Feature"]}>

### ✨ File change indicators in editor sidebar

Files with uncommitted changes now show colored status badges (M/A/D) in the editor sidebar file tree, so you can see which files have been modified without switching to the Version Control tab.

</Update>

<Update label="May 22, 2026" description="" tags={["New Feature"]}>

### ✨ Copy link to pages

Copy a shareable link to the current page from the page menu, with option to include the current filters.

</Update>

<Update label="May 22, 2026" description="" tags={["New Feature"]}>

### ✨ Download report as PNG

Save a full page as a PNG image from the page menu.

</Update>

<Update label="May 20, 2026" description="" tags={["Improvement"]}>

### 🚀 Dedicated Groups settings page

Groups now have their own page under Settings → Groups, separate from team members, with a detail view for managing each group's members and access.

</Update>

<Update label="May 20, 2026" description="" tags={["New Feature"]}>

### ✨ Snowflake and BigQuery direct connectors

Link Evidence to Snowflake or BigQuery directly to build reports without syncing data.

[View Documentation](https://docs.evidence.studio/direct-connectors/snowflake)

</Update>

<Update label="May 19, 2026" description="" tags={["Improvement"]}>

### 🚀 Improved discoverability of date input components in AI chat

Added search keywords to `range_calendar`, `date_grain_selector`, and `comparison_selector` so the AI assistant can find them when users ask for "date range filter", "date picker", "date input", etc.

</Update>

<Update label="May 19, 2026" description="" tags={["Improvement"]}>

### 🚀 Long chart label rotation

Charts now rotate long x-axis labels automatically so category names are easier to read without hovering.

</Update>

<Update label="May 15, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Map area layer filter updates

Fixed a bug where area charts did not respond to filter changes.

</Update>

<Update label="May 15, 2026" description="" tags={["Improvement"]}>

### 🚀 Data download title filenames

Data downloads now use titles in file names.

</Update>

<Update label="May 15, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Horizontal bar chart axis bound validation

The `horizontal_bar_chart` now reports a validation error when `x_axis_options.min` is greater than or equal to `x_axis_options.max`.

</Update>

<Update label="May 8, 2026" description="" tags={["New Feature"]}>

### ✨ Evidence CLI now available on Windows

The Evidence CLI now ships a Windows x64 binary, installable via PowerShell: `irm https://gaamozau3jchzs3r.public.blob.vercel-storage.com/cli/install.ps1 | iex`.

[View Documentation](https://docs.evidence.studio/cli)

</Update>

<Update label="May 8, 2026" description="" tags={["Improvement"]}>

### 🚀 Default tab selection

Add `default=true` to a `{% tab %}` to pre-select it on page load instead of always defaulting to the first tab.

</Update>

<Update label="May 7, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Data labels render on area and line charts

Fixed `data_labels` not appearing on `area_chart`, `line_chart`, and `combo_chart` line/area series.

</Update>

<Update label="May 4, 2026" description="" tags={["New Feature"]}>

### ✨ Add today and yesterday range calendar presets

Range calendars can now opt into Today and Yesterday preset ranges.

</Update>

<Update label="May 1, 2026" description="" tags={["Improvement"]}>

### 🚀 Faster Page Create and Rename

Creating, renaming, and reorganizing pages and folders in the editor sidebar is noticeably faster.

</Update>

<Update label="May 1, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Mobile sidebars close after navigation

Fixed mobile sidebars staying open after selecting a navigation link.

</Update>

<Update label="April 30, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Improved SQL file support in GitHub integration

Improved how SQL files sync between Studio and GitHub.

</Update>

<Update label="April 29, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Branch-aware link autocomplete and validation

Editor link autocomplete and validation now include pages that exist only on the current branch, and AI chat no longer flags them as broken.

</Update>

<Update label="April 28, 2026" description="" tags={["Bug Fix"]}>

### 🐛 AI chat current date awareness

Fixed AI chat date context so the agent knows today's date when answering in editor and viewer chats.

</Update>

<Update label="April 27, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Locally-authored pages now appear in Studio

Fixed an issue where files created locally and synced to GitHub were not appearing in Studio.

</Update>

<Update label="April 26, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Stable heading logo sizing

Fixed an issue where logos inside headings could briefly render at the wrong size on page load.

</Update>

<Update label="April 26, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix unquoted variables in partial attributes

Fixed an issue where unquoted variable references in component attributes failed when rendered from partials.

</Update>

<Update label="April 23, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix x_sort="data" imposing an x-axis sort

Fixed an issue where setting `x_sort="data"` on bar and line charts still sorted by the x-axis instead of preserving the source query's row order.

</Update>

<Update label="April 22, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Embedded page centering without TOC

Fixed an issue where embedded pages could stay shifted to the left after the table of contents was turned off.

</Update>

<Update label="April 20, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Stable logo sizing on load

Fixed an issue where logos in headings could briefly render at the wrong size while the page was loading.

</Update>

<Update label="April 20, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Improved models table readability

Fixed an issue where the models table was not sorted by name by default and long descriptions were hard to scan.

</Update>

<Update label="April 20, 2026" description="" tags={["New Feature"]}>

### ✨ Select content for PDF exports

Choose which sections and components to include when exporting a PDF.

</Update>

<Update label="April 20, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Source failure modal fix

Fixed an issue where opening a failed source status could show a blank blocking modal instead of the failure details.

</Update>

<Update label="April 19, 2026" description="" tags={["Improvement"]}>

### 🚀 Longer AI chat sessions

Increased the maximum AI chat response time so longer agentic conversations no longer time out.

</Update>

<Update label="April 17, 2026" description="" tags={["Improvement"]}>

### 🚀 Collapsible projects in published and preview sidebars

Projects in the sidebar can now be collapsed and expanded by clicking the project name, with state persisted across sessions.

</Update>

<Update label="April 17, 2026" description="" tags={["Improvement"]}>

### 🚀 Table Actions

Download and Fullscreen buttons now available in Table footers.

</Update>

<Update label="April 16, 2026" description="" tags={["Improvement"]}>

### 🚀 Claude Opus 4.7

The Evidence agent now uses Claude Opus 4.7 by default.

</Update>

<Update label="April 15, 2026" description="" tags={["New Feature"]}>

### ✨ Connector renaming

You can now rename connectors directly from the connectors page or the connector detail page by clicking the pencil icon next to the name.

</Update>

<Update label="April 15, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Dropdown search now handles nullable values safely

Fixed an issue where searching in a dropdown could fail when the value or label column contained empty values.

</Update>

<Update label="April 14, 2026" description="" tags={["New Feature"]}>

### ✨ Data lineage

See where your connectors and tables are used across projects, pages, models, and queries. Available in the connectors page, connector detail pages, models page, AI chat, and the CLI.



</Update>

<Update label="April 14, 2026" description="" tags={["Improvement"]}>

### 🚀 Resizable SQL console schema panel

The SQL console schema panel can now be resized by dragging its edge so long table names are easier to inspect.

</Update>

<Update label="April 13, 2026" description="" tags={["New Feature"]}>

### ✨ Connector and model health status

Connectors page now shows health status and sync schedule for all connector types. New `connectors` and `models` CLI commands let you check health statuses from the command line.

</Update>

<Update label="April 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed theme settings loading state while editing colors

Fixed an issue where editing theme color values could cause a broken loading state in settings.

</Update>

<Update label="April 12, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed inline SQL editor query references

Fixed an issue where inline SQL editor queries could fail when referencing other inline queries.

</Update>

<Update label="April 10, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed unexpectedly large branch diffs

Fixed an issue where small edits in Git-connected branches could appear as much larger diffs than expected.

</Update>

<Update label="April 9, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed stacked combo charts on time-based axes

Fixed an issue where stacked combo charts on time-based axes could render blank or incorrect series data.

</Update>

<Update label="April 9, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed filter bar not floating on scroll in published pages

Fixed an issue where the filter bar would not stay pinned to the top of the page when scrolling in published mode.

</Update>

<Update label="April 9, 2026" description="" tags={["New Feature"]}>

### ✨ Usage Analytics

Track how your team uses Evidence with built in analytics tables for sessions, users and page views.

</Update>

<Update label="April 8, 2026" description="" tags={["Bug Fix"]}>

### 🐛 AI theme updates apply instantly

Fixed an issue where theme changes made by the AI assistant only appeared after a page refresh.

</Update>

<Update label="April 8, 2026" description="" tags={["New Feature"]}>

### ✨ Audio Component

Embed an audio player in your reports with `{% audio url="..." /%}`. Supports mp3, wav, ogg, and other formats, with options for looping, autoplay, and preload behavior.

</Update>

<Update label="April 8, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Calendar heatmap dark mode colors

Fixed an issue where calendar heatmaps could show white empty-day cells in dark mode instead of blending with the page or card background.

</Update>

<Update label="April 8, 2026" description="" tags={["New Feature"]}>

### ✨ Conditional colors for dimensions and rows

Apply conditional background colors to entire rows or individual dimension cells using SQL expressions.



</Update>

<Update label="April 8, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed table SQL error overlay spacing

Fixed an issue where table SQL errors could overlap content below the table.

</Update>

<Update label="April 8, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Expanded background color options for AI theme updates

Expanded the background color options the AI agent can change in theme updates.

</Update>

<Update label="April 8, 2026" description="" tags={["New Feature"]}>

### ✨ YouTube Analytics Connector

Connect your YouTube Analytics data to Evidence. Sync channel reports, content owner reports, and metadata tables.

[View Documentation](https://docs.evidence.studio/data-sources/youtube_analytics)

</Update>

<Update label="April 7, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed combo chart SQL with toggle-driven inline queries

Fixed an issue where combo charts could fail when inline queries used toggle values in SQL conditions.

</Update>

<Update label="April 6, 2026" description="" tags={["New Feature"]}>

### ✨ Multiplayer editor

Collaborate with your team in real-time with live cursors and presence indicators.

</Update>

<Update label="April 2, 2026" description="" tags={["New Feature"]}>

### ✨ Axis titles for heatmaps

Heatmaps now support `x_axis_title` and `y_axis_title` so you can label both axes directly on the chart.

</Update>

<Update label="April 2, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix for table column groups with link attribute

Fixed an issue where adding a `link` attribute to a table dimension would cause all column groups to disappear.

</Update>

<Update label="April 1, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed spacing in the back-to-partial label

Fixed an issue where the "Back to partial" label appeared without a space in preview mode.

</Update>

<Update label="April 1, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Horizontal bar chart axis min/max now apply exactly

Fixed an issue where `x_axis_options.min` and `x_axis_options.max` on horizontal bar charts could be ignored instead of enforcing the requested axis range.

</Update>

<Update label="April 1, 2026" description="" tags={["New Feature"]}>

### ✨ SAP HANA Connector

Connect your SAP HANA data to Evidence. Sync data from SAP ECC and SAP S/4HANA systems running on the HANA platform.

[View Documentation](https://docs.evidence.studio/data-sources/sap_hana_db)

</Update>

<Update label="April 1, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix slider lockup with invalid step values

Fixed an issue where sliders could freeze the page when configured with an invalid step value.

</Update>

<Update label="March 30, 2026" description="" tags={["New Feature"]}>

### ✨ Third-party analytics for published pages

You can now add your own Google Analytics (GA4) or PostHog tracking to published and embedded pages. Configure your analytics provider in Organization Settings under Third-Party Analytics. Available on Enterprise plans.

</Update>

<Update label="March 27, 2026" description="" tags={["Improvement"]}>

### 🚀 Collapsible folders in published and preview sidebars

Added click-to-expand and collapse behavior for sidebar folders in published and preview pages to make navigation easier in larger projects.

</Update>

<Update label="March 26, 2026" description="" tags={["New Feature"]}>

### ✨ Added This Month and Next Month date presets

Range calendars now support `this month` and `next month` presets so you can filter full calendar months including upcoming dates.

</Update>

<Update label="March 25, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Dropdown options now support numeric values for initial selection

Fixed an issue where dropdown initial values could fail to apply when option values were provided as numbers.

</Update>

<Update label="March 25, 2026" description="" tags={["Improvement"]}>

### 🚀 Loading indicator for map components

Map components now show a loading indicator while map data is being fetched so blank maps are less confusing during slow queries.

</Update>

<Update label="March 20, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix for occasional AI chat timeouts

Fixed an issue where the AI agent could appear to run out of time when working with large queries.

</Update>

<Update label="March 20, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix for table search

Fixed an issue where searching in tables could produce errors or fail to recover after clearing a search.

</Update>

<Update label="March 20, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix table sorting when subtotal rows are hidden

Fixed an issue where sorting by measure columns in tables could produce incorrect order when subtotal rows were hidden.

</Update>

<Update label="March 19, 2026" description="" tags={["Improvement"]}>

### 🚀 Add mmm-yy date format

Added a built-in `mmm-yy` format code so dates can be displayed as month and two-digit year, like `Jan-22`.

</Update>

<Update label="March 18, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix mobile sidebar close animation flicker

Fixed an issue where the sidebar would briefly flash back into view at the end of its close animation on mobile devices.

</Update>

<Update label="March 18, 2026" description="" tags={["Improvement"]}>

### 🚀 Resizable Sidebar

The sidebar can now be resized by dragging its edge.

</Update>

<Update label="March 17, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Comparison column formatting fix

Fixed an issue where prior period comparison columns in tables did not apply the same number format as the main value column.

</Update>

<Update label="March 16, 2026" description="" tags={["New Feature"]}>

### ✨ Evidence CLI

Develop Evidence Studio projects locally from the command line with `evidence dev`.

[View Documentation](https://docs.evidence.studio/cli)

</Update>

<Update label="March 16, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Improve filter value visibility in the editor sidebar

Fixed an issue where filter values in the editor sidebar could be hard to read by showing each value on its own line.

</Update>

<Update label="March 15, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Recent AI chats update instantly

Fixed an issue where new AI chats would not appear in Recent chats until the page was refreshed.

</Update>

<Update label="March 15, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Improved spacing for small tables

Fixed an issue where tables with only a few rows could show unnecessary empty space.

</Update>

<Update label="March 14, 2026" description="" tags={["Improvement"]}>

### 🚀 Clearer error when defining queries inside components

Added a validation error when inline queries are defined inside components like tabs, accordion, or details. Queries should be defined at the top level of the page.

</Update>

<Update label="March 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Accordion items now maintain their original order

Fixed an issue where accordion items could reorder themselves based on when they were last updated instead of their original document order.

</Update>

<Update label="March 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Support for branch names with slashes in GitHub integration

Fixed an issue where branches containing slashes (e.g., `feature/my-branch`) would break navigation across the editor, preview, published views, and PDF generation.

</Update>

<Update label="March 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Button group and dropdown initial value fix

Fixed an issue where button groups and dropdowns could not set an initial value when using a numeric value column.

</Update>

<Update label="March 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed organization logo display in dark mode on published pages

Fixed an issue where the organization logo in the sidebar could appear as a dark image on a dark background when viewing published pages in dark mode.

</Update>

<Update label="March 13, 2026" description="" tags={["Improvement"]}>

### 🚀 Option to hide axis title arrow

Added a `title_arrow` option to `x_axis_options` that lets you hide the arrow (→) on chart axis titles.

</Update>

<Update label="March 12, 2026" description="" tags={["Improvement"]}>

### 🚀 Demo data table references updated

Demo data tables have moved to the `demo` schema (e.g. `demo_daily_orders` → `demo.daily_orders`). You may need to update references in existing projects and models.

</Update>

<Update label="March 10, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed model save failing after validation

Fixed an issue where saving a model could fail if the SQL query contained leading or trailing whitespace.

</Update>

<Update label="March 10, 2026" description="" tags={["Bug Fix"]}>

### 🐛 PDF downloads from editor now use working version

Fixed an issue where downloading a PDF from the editor would always produce the committed version instead of the current working draft.

</Update>

<Update label="March 9, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Print group cards spacing fix

Fixed an issue where wrapping components in a print group with cards layout enabled would remove the spacing between cards.

</Update>

<Update label="March 6, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Google Analytics setup links to Evidence docs

Fixed an issue where the Google Analytics connector setup page linked only to the Fivetran docs instead of the Evidence docs page.

</Update>

<Update label="March 6, 2026" description="" tags={["Improvement"]}>

### 🚀 More reliable PDF generation

Improved PDF generation reliability, especially for pages with conditionals, partials, and many components.

</Update>

<Update label="March 6, 2026" description="" tags={["Bug Fix"]}>

### 🐛 PDF downloads from preview now use working version

Fixed an issue where downloading a PDF from the preview route would always produce the published version instead of the working draft.

</Update>

<Update label="March 6, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed chart rendering error on published pages with point_title

Fixed an issue where charts using the `point_title` attribute could fail to render on published pages.

</Update>

<Update label="March 6, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed scatter chart tooltip with point_title and series

Fixed an issue where the `point_title` attribute on scatter charts was ignored in the tooltip when a `series` attribute was also set.

</Update>

<Update label="March 6, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed scatter chart size attribute

Fixed an issue where the `size` attribute on scatter charts was ignored, causing all points to render at the same size.



</Update>

<Update label="March 5, 2026" description="" tags={["New Feature"]}>

### ✨ Date range support for map layers

Map layers (point_layer, area_layer, and heatmap_layer) now support the `date_range` attribute for filtering data by time period.

</Update>

<Update label="March 5, 2026" description="" tags={["New Feature"]}>

### ✨ PayPal Connector

Connect your PayPal data to Evidence. Sync transactions, invoices, payments, subscriptions, and billing plans.

[View Documentation](https://docs.evidence.studio/data-sources/paypal)

</Update>

<Update label="March 5, 2026" description="" tags={["Improvement"]}>

### 🚀 Connection string autofill for PostgreSQL connections

You can now paste a PostgreSQL connection string into any field when setting up a PostgreSQL connection, and all fields will be automatically filled in.



</Update>

<Update label="March 5, 2026" description="" tags={["New Feature"]}>

### ✨ RevenueCat Connector

Connect your RevenueCat subscription data to Evidence. Sync subscribers, transactions, entitlements, offerings, and products.

[View Documentation](https://docs.evidence.studio/data-sources/revenuecat)

</Update>

<Update label="March 5, 2026" description="" tags={["Improvement"]}>

### 🚀 Invite team members from the Share menu

Added a quick link to Team Settings from the Share menu so you can invite new team members while managing page or project access.

</Update>

<Update label="March 4, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix for dimension grid with inline queries

Fixed an issue where the dimension grid component could not use inline SQL queries as its data source.

</Update>

<Update label="March 3, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix legend color for lines with explicit color in combo charts

Fixed an issue where lines in combo charts with an explicit color option (e.g., `options={color="black"}`) would display the palette color in the legend instead of the specified color.

</Update>

<Update label="March 3, 2026" description="" tags={["Improvement"]}>

### 🚀 Improved component search with keyword aliases

Added search keywords to component schemas so components can be found by common alternative names (e.g., "scatter plot" for scatter chart, "donut" for pie chart, "KPI" for big value).

</Update>

<Update label="March 2, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix filters with multiple consecutive spaces in values

Fixed an issue where filter values containing multiple consecutive spaces would fail to match data correctly.

</Update>

<Update label="February 28, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix collapsible table arrows not showing with hide_row_totals

Fixed an issue where collapsible table arrows were not visible when measures had `hide_row_totals` enabled.

</Update>

<Update label="February 27, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix branch deletion when branch was already deleted on GitHub

Fixed an issue where deleting branches from the Evidence UI would fail with an error when the branch had already been deleted on GitHub (e.g., by GitHub's auto-delete on merge feature).

</Update>

<Update label="February 27, 2026" description="" tags={["New Feature"]}>

### ✨ Candlestick chart component

Added a new candlestick chart component for visualizing OHLC financial data with optional volume bars.



[View Documentation](https://docs.evidence.studio/components/candlestick)

</Update>

<Update label="February 27, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix for overlapping content in PDF exports

Fixed an issue that could cause overlapping content in PDF exports.

</Update>

<Update label="February 27, 2026" description="" tags={["New Feature"]}>

### ✨ Percentage labels for pie charts

Added `pct` and `pct_fmt` options for pie charts to display percentage values directly on slice labels.



[View Documentation](https://docs.evidence.studio/components/pie_chart#param-pct)

</Update>

<Update label="February 26, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix AI chat generating dropdowns and date range filters

Fixed an issue where AI chat could fail when generating dropdowns or date range filters.

</Update>

<Update label="February 26, 2026" description="" tags={["New Feature"]}>

### ✨ Salesforce Connector

Connect your Salesforce CRM data to Evidence. Sync accounts, contacts, opportunities, leads, and campaigns.

[View Documentation](https://docs.evidence.studio/data-sources/salesforce)

</Update>

<Update label="February 26, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix x_fmt not applying to chart tooltips

Fixed an issue where setting `x_fmt` on charts would format the axis labels but not the date value shown in the tooltip.

</Update>

<Update label="February 25, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Improved AI chat reliability

Fixed an issue where AI chat could error out during longer conversations.

</Update>

<Update label="February 25, 2026" description="" tags={["New Feature"]}>

### ✨ Date Range Support for Input Components

Input components (dropdown, button_group, input_tabs, slider, dimension_grid) now support the `date_range` attribute, allowing you to filter options by a specific time period or a range_calendar selection.

</Update>

<Update label="February 25, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix dropdown with manual options showing SQL error

Fixed an issue where dropdowns using manual child option tags (no `data` attribute) would show an "Unknown table function WHERE" error.

</Update>

<Update label="February 25, 2026" description="" tags={["New Feature"]}>

### ✨ Multiplayer editor now in beta

Multiplayer editor is now available in beta. Turn it on from Project Settings to collaborate with your team in real-time.

</Update>

<Update label="February 24, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Graceful redirect when page not found after branch switch or rename

Fixed an issue where switching branches or renaming a page could result in a 404 when the current page doesn't exist on the target branch or at the old URL.

</Update>

<Update label="February 23, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix dimension link navigation resulting in 404

Fixed an issue where clicking dimension links in tables would result in a 404 when navigating between pages, because the URL wasn't being resolved relative to the current project context.

</Update>

<Update label="February 19, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Automatic chart padding for data labels

Charts now automatically add top padding when data labels are positioned above bars or points, preventing labels from being cut off at the top of the chart.

</Update>

<Update label="February 19, 2026" description="" tags={["New Feature"]}>

### ✨ External GitHub branch support and PR preview links

Projects connected to GitHub now show all repository branches in the branch switcher, not just branches created through Evidence Studio. When a pull request is opened or reopened, Evidence automatically posts a preview link comment on the PR.

</Update>

<Update label="February 19, 2026" description="" tags={["Improvement"]}>

### 🚀 SQL Console Table Grouping

Tables in the SQL console sidebar are now organized by schema/connection in a collapsible tree structure for easier navigation.

</Update>

<Update label="February 19, 2026" description="" tags={["New Feature"]}>

### ✨ Customizable Total Label for Tables

Tables now support a `total_label` attribute that allows customizing the text displayed in total/subtotal rows and columns, useful when using non-sum aggregations like avg, min, max, or count.

</Update>

<Update label="February 18, 2026" description="" tags={["New Feature"]}>

### ✨ Editor Sidebar

Enhanced editor sidebar, with diff viewer, search, table schema, and page filters.

</Update>

<Update label="February 14, 2026" description="" tags={["Improvement"]}>

### 🚀 Pivot Table Performance

Significant performance improvements for pivoted tables and increased row/column limits.

</Update>

<Update label="February 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix dropdowns closing modals

Fixed an issue where clicking on dropdown menus inside a modal would cause the modal to close unexpectedly.

</Update>

<Update label="February 13, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Stable AI Edit Previews

Prevent AI edits from causing full refresh

</Update>

<Update label="February 12, 2026" description="" tags={["New Feature"]}>

### ✨ Gradient fill for area charts

Area charts now support a gradient fill option that fades from the series color at the top to transparent at the bottom. Enable it with `area_options={ gradient=true }`.



[View Documentation](https://docs.evidence.studio/components/area_chart#param-area_options)

</Update>

<Update label="February 12, 2026" description="" tags={["New Feature"]}>

### ✨ Clock Component

Display a live clock with running seconds and the current date using `{% clock /%}`. Supports 12h/24h format, monospace font variant, and left/right alignment.

</Update>

<Update label="February 12, 2026" description="" tags={["New Feature"]}>

### ✨ Branching

Work on multiple versions of your reports at the same time. Create and switch between branches, commit your work, and publish when you're ready.

</Update>

<Update label="February 12, 2026" description="" tags={["New Feature"]}>

### ✨ Heat Grid

Visualize metrics across categories with color-coded cells based on configurable thresholds. Cells are colored red, yellow, or green depending on where values fall relative to your thresholds, with an optional `lower_is_better` mode.

</Update>

<Update label="February 12, 2026" description="" tags={["Improvement"]}>

### 🚀 Model Engine and Primary Key Settings

The model edit page now includes configurable refresh schedules, table engine selection, and primary key configuration with helpful tooltips explaining each engine type, data locations, and nullable primary key handling.

[View Documentation](https://docs.evidence.studio/core-concepts/models)

</Update>

<Update label="February 12, 2026" description="" tags={["New Feature"]}>

### ✨ Progress Bars

Display progress toward goals with horizontal bars showing numerator/denominator ratios. Supports threshold-based coloring and custom color gradients.

</Update>

<Update label="February 9, 2026" description="" tags={["New Feature"]}>

### ✨ PDF Export Options

PDF export now supports custom orientation, margins, and card styling options.

</Update>

<Update label="February 6, 2026" description="" tags={["New Feature"]}>

### ✨ Datadog Connector

Connect your Datadog monitoring and analytics data to Evidence. Sync metrics, dashboards, monitors, hosts, and usage data from your Datadog account.

[View Documentation](https://docs.evidence.studio/data-sources/datadog)

</Update>

<Update label="February 6, 2026" description="" tags={["New Feature"]}>

### ✨ Custom Title for Table Filter

Customize the Table Filter button text using the new `title` attribute.

</Update>

<Update label="February 6, 2026" description="" tags={["New Feature"]}>

### ✨ Table Repeat Dimension Values

Tables and dimensions now support a `repeat_values` attribute that forces dimension values to display on every row instead of being collapsed.

</Update>

<Update label="February 5, 2026" description="" tags={["Improvement"]}>

### 🚀 Improved code editor font

The code editor now uses Geist Mono, a modern monospace font designed for better readability and aesthetics.

</Update>

<Update label="February 4, 2026" description="" tags={["New Feature"]}>

### ✨ Custom AI Instructions

Configure custom instructions for the AI assistant in Settings > AI Agent.

</Update>

<Update label="February 4, 2026" description="" tags={["New Feature"]}>

### ✨ RDS PostgreSQL Connector

Connect your RDS PostgreSQL database to Evidence and sync your data automatically.

[View Documentation](https://docs.evidence.studio/data-sources/rds-postgres)

</Update>

<Update label="February 3, 2026" description="" tags={["Improvement"]}>

### 🚀 PostgreSQL TLS Requirement Documentation

Added documentation note for PostgreSQL and Azure PostgreSQL connectors specifying that TLS/SSL must be enabled on the database for secure connections.

</Update>

<Update label="February 1, 2026" description="" tags={["New Feature"]}>

### ✨ Collapsible Tables

Tables with subtotals can now be collapsed. Click subtotal rows to expand or collapse their children.



[View Documentation](https://docs.evidence.studio/components/table)

</Update>

<Update label="February 1, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fixed row link chevron styling for total and subtotal rows

Fixed chevron column styling in tables with row links to match total/subtotal row backgrounds.



</Update>

<Update label="February 1, 2026" description="" tags={["New Feature"]}>

### ✨ Total and Subtotal Position

Control where totals and subtotals appear with `total_position` and `subtotal_position`. Set to "top" or "bottom".



[View Documentation](https://docs.evidence.studio/components/table)

</Update>

<Update label="January 29, 2026" description="" tags={["Improvement"]}>

### 🚀 Table Filter Initial Values and Required Selections

Table filters now support `initial_values` to set default filter values when the page loads, and `require_selection` to prevent specific filters from being cleared.

</Update>

<Update label="January 28, 2026" description="" tags={["Improvement"]}>

### 🚀 Automatic Unit Formatting for Numbers

BigValue, Value, and Table components now auto-format large numbers with compact units (e.g., $1.2M instead of $1,234,567)

</Update>

<Update label="January 23, 2026" description="" tags={["New Feature"]}>

### ✨ Text Size Option for Big Value

The `big_value` component now supports a `text_size` attribute with predefined options (`sm`, `base`, `lg`, `xl`, `2xl`, `3xl`, `4xl`, `5xl`) for reliable text sizing.

</Update>

<Update label="January 23, 2026" description="" tags={["Improvement"]}>

### 🚀 Clear Table Sorting with Third Click

Click a column header a third time to clear sorting and return to the original order.

[View Documentation](https://docs.evidence.studio/components/table)

</Update>

<Update label="January 22, 2026" description="" tags={["New Feature"]}>

### ✨ Azure SQL Database Connector

Sync data from Azure SQL Database directly into Evidence.

[View Documentation](https://docs.evidence.studio/data-sources/azure-sql)

</Update>

<Update label="January 22, 2026" description="" tags={["New Feature"]}>

### ✨ Logo Attribute for Table Dimensions

Display company logos in table dimension columns. The new `logo` attribute accepts a column containing domains to look up logos, and `logo_options` lets you customize size, grayscale mode, and label visibility.



[View Documentation](https://docs.evidence.studio/components/dimension)

</Update>

<Update label="January 22, 2026" description="" tags={["New Feature"]}>

### ✨ PDF Export for Viewers

Viewers can now download published pages as PDFs using the page menu or the keyboard shortcut (Cmd/Ctrl+P).

</Update>

<Update label="January 22, 2026" description="" tags={["New Feature"]}>

### ✨ Twilio Connector

Connect your Twilio data to Evidence. Sync calls, messages, accounts, and usage records.

[View Documentation](https://docs.evidence.studio/data-sources/twilio)

</Update>

<Update label="January 21, 2026" description="" tags={["Improvement"]}>

### 🚀 BigQuery 1 Minute Incremental Syncs

BigQuery data connector now supports 1 minute incremental syncs for faster data freshness.

[View Documentation](https://docs.evidence.studio/data-sources/bigquery)

</Update>

<Update label="January 21, 2026" description="" tags={["New Feature"]}>

### ✨ Column Groups in Tables

Group related columns under shared headers using the new `column_group` attribute on measures and dimensions. Useful for organizing metrics by category, such as revenue metrics vs volume metrics.



</Update>

<Update label="January 21, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Dark Mode Empty Circle Markers Fix

Fixed emptyCircle markers in charts to properly use the background color in dark mode instead of white.

</Update>

<Update label="January 21, 2026" description="" tags={["New Feature"]}>

### ✨ Databricks Data Connector

Sync data from Databricks directly into Evidence.

[View Documentation](https://docs.evidence.studio/data-sources/databricks)

</Update>

<Update label="January 21, 2026" description="" tags={["New Feature"]}>

### ✨ Google Ads & Facebook Ads Connectors

Connect your Google Ads and Facebook Ads data to Evidence. Sync campaigns, ad groups, ads, and performance metrics to build marketing analytics dashboards.

[View Documentation](https://docs.evidence.studio/data-sources/google-ads)

</Update>

<Update label="January 21, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Horizontal Bar Chart Sorting Fix

Horizontal bar charts now default to sorting by value descending, showing the largest values at the top instead of the bottom.

</Update>

<Update label="January 21, 2026" description="" tags={["New Feature"]}>

### ✨ Logo Component

New logo component to display company logos using logo.dev. Supports light/dark theme switching, configurable sizes, and grayscale mode.

</Update>

<Update label="January 21, 2026" description="" tags={["New Feature"]}>

### ✨ MySQL Data Connector

Sync data from MySQL directly into Evidence.

[View Documentation](https://docs.evidence.studio/data-sources/mysql)

</Update>

<Update label="January 21, 2026" description="" tags={["New Feature"]}>

### ✨ PostHog Connector

Connect your PostHog product analytics data to Evidence. Sync events, persons, cohorts, feature flags, insights, and more from your PostHog account.

[View Documentation](https://docs.evidence.studio/data-sources/posthog)

</Update>

<Update label="January 21, 2026" description="" tags={["Improvement"]}>

### 🚀 Snowflake 1 Minute Incremental Syncs

Snowflake data connector now supports 1 minute incremental syncs for faster data freshness.

[View Documentation](https://docs.evidence.studio/data-sources/snowflake)

</Update>

<Update label="January 21, 2026" description="" tags={["New Feature"]}>

### ✨ SQL Server Data Connector

Sync data from SQL Server directly into Evidence.

[View Documentation](https://docs.evidence.studio/data-sources/sqlserver)

</Update>

<Update label="January 20, 2026" description="" tags={["New Feature"]}>

### ✨ Dimension Grid

New `dimension_grid` component for interactive multi-dimensional filtering.

</Update>

<Update label="January 20, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Fix for frozen columns row shading

Frozen columns in tables now display the correct alternating row shading when `row_shading=true` is enabled. Previously, frozen columns would not show the shading because they had a solid background that overrode the row-level shading.

</Update>

<Update label="January 20, 2026" description="" tags={["New Feature"]}>

### ✨ Series colors for pie charts

Map specific category values to specific colors in pie charts using the `series_colors` option in `chart_options`. This ensures consistent, meaningful coloring regardless of which categories are present in the data.

</Update>

<Update label="January 16, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Export Data Retains Filters

Table exports now correctly include filtered and sorted data, matching the visual display on screen.

</Update>

<Update label="January 16, 2026" description="" tags={["Bug Fix"]}>

### 🐛 PDF Export Now Retains Filters

When downloading a PDF, any selected filter values are now preserved in the exported PDF.

</Update>

<Update label="January 14, 2026" description="" tags={["Improvement","Breaking Change"]}>

### 🚀 Adjusted Developer Role Privileges

Previously, developers and admins could manage users, groups and customers. This is now restricted to Admins only.

</Update>

<Update label="January 13, 2026" description="" tags={["New Feature"]}>

### ✨ Motherduck Connector Schema Support

You can now use schema with the Motherduck connector

</Update>

<Update label="January 12, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Dropdown Component Now Supports 'where' Attribute

The `dropdown` component now supports the `where` attribute for filtering dropdown options with custom SQL WHERE conditions, bringing it to feature parity with other filter components like `button_group` and `input_tabs`.

</Update>

<Update label="January 12, 2026" description="" tags={["Bug Fix"]}>

### 🐛 Horizontal Bar Chart X-Axis Formatting

Fixed issue where the `x_fmt` parameter was not being applied to axis labels in horizontal bar charts. Formatting now works consistently for both axis labels and tooltips.

</Update>

<Update label="January 9, 2026" description="" tags={["New Feature"]}>

### ✨ Add your organization logo

Add your organization's logo in settings

</Update>

<Update label="January 9, 2026" description="" tags={["New Feature"]}>

### ✨ Github Data Connector

Sync data about your Github repos directly into Evidence.

</Update>

<Update label="January 7, 2026" description="" tags={["New Feature"]}>

### ✨ Deltalake (S3) Connector

Connect using your S3 with Delta Lake format your data remains at rest in your S3 bucket.

</Update>

<Update label="January 6, 2026" description="" tags={["New Feature"]}>

### ✨ Smooth Line Option

New `smooth` attribute inside line options lets you create a line with rounded corners



[View Documentation](https://docs.evidence.studio/components/line_chart#param-line-options)

</Update>

<Update label="December 30, 2025" description="" tags={["New Feature"]}>

### ✨ Chart `height` attribute

Control the height of your charts using the `height` attribute

[View Documentation](https://docs.evidence.studio/components/area_chart#param-height)

</Update>

<Update label="December 20, 2025" description="" tags={["New Feature"]}>

### ✨ Customer Groups

Create customers, and invite customer users to view reports that you choose.



[View Documentation](https://docs.evidence.studio/features/page-level-access-control#customers)

</Update>

<Update label="December 20, 2025" description="" tags={["New Feature"]}>

### ✨ Groups

Add team members to groups to simplify permissions on projects and pages

[View Documentation](https://docs.evidence.studio/features/page-level-access-control#groups)

</Update>

<Update label="December 19, 2025" description="" tags={["Improvement"]}>

### 🚀 Improved Excel Export

Excel exports now use component titles to create tab names, and exclude logic and filter components

</Update>

<Update label="December 15, 2025" description="" tags={["New Feature"]}>

### ✨ User Variables

Access the user's name, email and organization using variables in markdown.

[View Documentation](http://docs.evidence.studio/core-concepts/variables#built-in-variables)

</Update>

<Update label="December 11, 2025" description="" tags={["New Feature"]}>

### ✨ Themes

Set color themes at the organization, project, and page level - including background, chart, and card colors

Access theme settings in page settings, project settings, or org settings. You can override theme colors at each level (e.g., project can override org theme, page overrides project and org themes)



[View Documentation](https://docs.evidence.studio/core-concepts/themes)

</Update>

<Update label="December 9, 2025" description="" tags={["Improvement"]}>

### 🚀 Improved Translation Validation Errors

Incorrect structures for translation maps will provide useful errors

</Update>

<Update label="December 9, 2025" description="" tags={["Improvement"]}>

### 🚀 Translations Editor

Modify translations with a fully featured text editor

</Update>

<Update label="December 8, 2025" description="" tags={["Improvement"]}>

### 🚀 Improved bucket docs

Adds more information about using bucket connectors

[View Documentation](https://docs.evidence.studio/data-sources)

</Update>

<Update label="December 4, 2025" description="" tags={["New Feature"]}>

### ✨ Translation Management

Define variables with different translations for multi-language apps.



[View Documentation](https://docs.evidence.studio/core-concepts/translations)

</Update>

<Update label="November 30, 2025" description="" tags={["New Feature","Breaking Change"]}>

### ✨ Standalone Horizontal Bar Chart Component

New dedicated `horizontal_bar_chart` component makes it easier to create horizontal bar charts

We recommend migrating any existing horizontal bar charts to this new component

[View Documentation](https://docs.evidence.studio/components/horizontal_bar_chart)

</Update>

<Update label="November 29, 2025" description="" tags={["New Feature"]}>

### ✨ Display control for total and subtotals in table

Choose which totals or subtotals to display in your table

[View Documentation](https://docs.evidence.studio/components/table#param-show-subtotal-rows)

</Update>

<Update label="November 28, 2025" description="" tags={["New Feature"]}>

### ✨ Dark Mode Chart Colors

Configure colors for both light and dark mode in your project and org settings



</Update>

<Update label="November 28, 2025" description="" tags={["New Feature"]}>

### ✨ Input tabs full_width and align attributes

Input tabs now allows the same styling configuration as the Tabs component, including full width and right align

[View Documentation](https://docs.evidence.studio/components/input_tabs#param-full-width)

</Update>

<Update label="November 27, 2025" description="" tags={["New Feature"]}>

### ✨ Conditional Formatting

Apply conditional logic to choose colors for visualizations



</Update>

<Update label="November 26, 2025" description="" tags={["New Feature"]}>

### ✨ Series Color Mapping

Option to select specific colors for series in your charts



[View Documentation](https://docs.evidence.studio/components/bar_chart#bar-chart-with-series-colors)

</Update>

<Update label="November 25, 2025" description="" tags={["Improvement"]}>

### 🚀 Assign access to pending users

You can now grant project and page access to users who have not yet accepted invitations to join the Evidence organization.

</Update>

<Update label="November 24, 2025" description="" tags={["Improvement"]}>

### 🚀 Control order of series in combo chart

Combo chart now displays your series in the order you define them in your markdown

</Update>

<Update label="November 21, 2025" description="" tags={["New Feature"]}>

### ✨ Draft Diff Viewer

Review your changes using the diff viewer before you publish



</Update>

<Update label="November 21, 2025" description="" tags={["Improvement"]}>

### 🚀 Icons in Autocomplete

Find components more easily in component autocomplete menus using the mini-icons



</Update>

<Update label="November 18, 2025" description="" tags={["Improvement"]}>

### 🚀 Smoother chart loads on input changes

Improved chart loading behaviour and animation when changing inputs on your page



</Update>

<Update label="November 17, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fix for table pivoting issues

Fixed issue where tables were not pivoting in certain situations

</Update>

<Update label="November 17, 2025" description="" tags={["New Feature"]}>

### ✨ `fmt` property for input options

Use dynamic formats in viz components when creating an input to select a metric - e.g., show 'usd' for sales or 'pct1' for growth

[View Documentation](https://docs.evidence.studio/components/dropdown#fmt)

</Update>

<Update label="November 17, 2025" description="" tags={["New Feature"]}>

### ✨ Variable `label` property

You can now reference the `label` property of a variable - useful when adding labels to viz components based on input selection

[View Documentation](https://docs.evidence.studio/components/dropdown#label)

</Update>

<Update label="November 14, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fix for custom date range end dates

Fixes issue where custom end date defined in SQL was not taking effect

</Update>

<Update label="November 14, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fix for scale_column

Fixes issue where scale_column in the measure component was not properly assigning colors

</Update>

<Update label="November 14, 2025" description="" tags={["Improvement"]}>

### 🚀 Improved handling of date grains in charts

Automatically handles formatting and positioning of labels on x-axis for date grains including month of year and day of week

</Update>

<Update label="November 14, 2025" description="" tags={["New Feature"]}>

### ✨ Table of Contents

A generated table of contents from the headings in your report. Enable from page settings.



</Update>

<Update label="November 14, 2025" description="" tags={["New Feature"]}>

### ✨ Top padding option for charts

Top padding override option to allow more room for data labels - helps in cases where labels are cut off

</Update>

<Update label="November 14, 2025" description="" tags={["New Feature"]}>

### ✨ x_sort attribute

Choose a specific sort order for your x-axis, including specifying explicit strings

</Update>

<Update label="November 12, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Histogram support for inline queries

Fix for Histogram issue where it could not accept inline queries

</Update>

<Update label="November 11, 2025" description="" tags={["Improvement"]}>

### 🚀 Toggle `invert` attribute

Invert attribute added to make toggled state = `false` instead of `true`

</Update>

<Update label="November 8, 2025" description="" tags={["New Feature"]}>

### ✨ Slider Input

New slider input component to filter on numeric values



[View Documentation](https://docs.evidence.studio/components/slider)

</Update>

<Update label="November 7, 2025" description="" tags={["New Feature"]}>

### ✨ Query timing metadata

Queries in the SQL Console, and the pop out component inspector at the bottom of the editor now display how long the query took to run in the Evidence query engine

</Update>

<Update label="November 6, 2025" description="" tags={["New Feature"]}>

### ✨ Zoomable charts

Adds a new "zoom" chart option to enable zooming into the data



</Update>

<Update label="November 4, 2025" description="" tags={["New Feature"]}>

### ✨ Toggle input

New toggle input component which sets a boolean variable you can use in queries and components



[View Documentation](https://docs.evidence.studio/components/toggle)

</Update>

<Update label="November 2, 2025" description="" tags={["New Feature"]}>

### ✨ Button group and input tabs

New input components as visual alternatives to dropdowns: `button_group` and `input_tabs`

Note that this update also deprecates the `dropdown_option` component in favour of the more general `option` component. The `option` component can be used inside `dropdown`, `button_group`, or `input_tabs`



[View Documentation](https://docs.evidence.studio/components/button_group)

</Update>

<Update label="October 31, 2025" description="" tags={["Improvement"]}>

### 🚀 Info Links

Add links to info text popovers using <code>info_link</code> and <code>info_link_title</code> atttributes.

</Update>

<Update label="October 31, 2025" description="" tags={["Improvement"]}>

### 🚀 User Management Performance

Adding and removing users from reports is now faster

</Update>

<Update label="October 30, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fix for custom pivot formatting

Formatting for pivots now works as expected for custom date formats - e.g., `fmt="yyyy-mm"`

</Update>

<Update label="October 30, 2025" description="" tags={["New Feature"]}>

### ✨ Select all in dropdown

New button to select all options in a dropdown



</Update>

<Update label="October 26, 2025" description="" tags={["New Feature"]}>

### ✨ Text input component

Input component accepting free text input



[View Documentation](https://docs.evidence.studio/components/text_input)

</Update>

<Update label="October 25, 2025" description="" tags={["New Feature"]}>

### ✨ Feature Requests

Submit and track feature requests directly in your settings menu

From Settings > Feature Requests, you can create requests or bug reports, and set their priority. This integrates directly with the Evidence team's roadmap, with status changes synced into your view



</Update>

<Update label="October 24, 2025" description="" tags={["New Feature"]}>

### ✨ Stacked bar series in combo charts

Bar series in combo charts can now be stacked using the new <code>stack_id</code> attribute. Bars with the same <code>stack_id</code> will be stacked together, allowing for flexible combinations of stacked and grouped bars.

[View Documentation](https://docs.evidence.studio/components/bar)

</Update>

<Update label="October 23, 2025" description="" tags={["New Feature"]}>

### ✨ Max label length for x-axis labels

Truncate labels after a certain number of characters using the `max_label_length` attribute inside `x_axis_options`



</Update>

<Update label="October 21, 2025" description="" tags={["New Feature"]}>

### ✨ Rotate x-axis labels

Use the new `label_rotate` option in `x_axis_options` to rotate the labels on your x-axis



[View Documentation](https://docs.evidence.studio/components/line_chart#param-x-axis-options)

</Update>

<Update label="October 21, 2025" description="" tags={["Improvement"]}>

### 🚀 Sidebar Icons and Sorting

Add custom icons and adjust the sort order of projects and pages in the sidebar

</Update>

<Update label="October 20, 2025" description="" tags={["New Feature"]}>

### ✨ Jump to Code

In the editor preview, Cmd/Ctrl + click on a component to jump to the code for that component

You can jump to code by Cmd/Ctrl + clicking a component in the preview pane, or you can jump to the component preview by Cmd/Ctrl + clicking the code in your editor



</Update>

<Update label="October 17, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fixes for table pivoting

Fixed issue where columns were not properly pivoting in tables

</Update>

<Update label="October 16, 2025" description="" tags={["Improvement"]}>

### 🚀 Drag and drop image support

Drag, or paste images into the editor to add them to your page.

</Update>

<Update label="October 16, 2025" description="" tags={["New Feature"]}>

### ✨ Models (Beta)

Join sources together and materialize the results to improve performance

Models can be used to execute joins across sources, centralize type casting, and create clean tables to use when building reports. Models are run and materialized every 8 hours

[View Documentation](https://docs.evidence.studio/core-concepts/models)

</Update>

<Update label="October 16, 2025" description="" tags={["New Feature"]}>

### ✨ Set custom end date for date ranges

Use a dynamic end date for date ranges based on your data or a standard offset

By default, date ranges end as of today's date, but this setting allows you to choose a date based on a standard offset (e.g., 1 day ago) or by passing a sql query to calculate the date (e.g., `select max(date) from my_table`)

</Update>

<Update label="October 14, 2025" description="" tags={["New Feature"]}>

### ✨ Bar chart opacity setting

Customize the opacity of bars in bar chart and combo chart components

</Update>

<Update label="October 14, 2025" description="" tags={["Improvement"]}>

### 🚀 Project Sections

Organize projects into sections for easier navigation during development

Sections will not impact how projects are arranged in the app published to Viewer users

</Update>

<Update label="October 8, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Version control overflow

Fixes a bug where if you changed lots of files it overflowed the Version History panel

</Update>

<Update label="October 7, 2025" description="" tags={["New Feature"]}>

### ✨ Option to choose first day of week

In project settings, you can now choose whether weeks start on Sunday or Monday

</Update>

<Update label="October 6, 2025" description="" tags={["Improvement"]}>

### 🚀 Better SQL Autocomplete Suggestions

Improved SQL suggestions for columns, and tables after joins

</Update>

<Update label="October 6, 2025" description="" tags={["Improvement"]}>

### 🚀 Variable name shortcuts + use in markdown

Variables no longer require specifying a property - simply use the name, like `{{ my_var }}`

You can also use variables directly in markdown, including in headers and lists. You still have access to variable properties and can reference them like this: `{{ my_var.selected }}`



</Update>

<Update label="October 4, 2025" description="" tags={["Improvement"]}>

### 🚀 Performance improvement for table comparisons

Tables containing comparisons should now load much faster

</Update>

<Update label="October 3, 2025" description="" tags={["Improvement"]}>

### 🚀 More source sync info

View the number of rows in a source, and the amount of time it took for the source sync from the Sources page.

</Update>

<Update label="October 2, 2025" description="" tags={["New Feature"]}>

### ✨ Use variables inside components

You can now reference filter variables directly in component attributes

Supports the following attributes: title, subtitle, info, where, date_grain, date_range.range, comparison.compare_vs



</Update>

<Update label="October 1, 2025" description="" tags={["New Feature"]}>

### ✨ Icon support for dropdowns

Include an icon in your dropdown using the icon option



</Update>

<Update label="October 1, 2025" description="" tags={["New Feature"]}>

### ✨ Selector components for date grain and comparisons

Special components for selecting date grain and comparisons

</Update>

<Update label="September 30, 2025" description="" tags={["Improvement"]}>

### 🚀 Dynamic date ranges

Input arbitrary ranges into the date_range attribute in components, like "last 14 weeks" or "2023-01-14 to 2025-11-30"

</Update>

<Update label="September 30, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Filter scroll fix

Fixed a bug where selecting a filter caused the page to jump back to the top.

</Update>

<Update label="September 30, 2025" description="" tags={["New Feature"]}>

### ✨ Select preset ranges in range calendar

Choose which preset ranges you want your users to see when clicking the range calendar component

</Update>

<Update label="September 30, 2025" description="" tags={["Bug Fix"]}>

### 🐛 SQL comments in inline queries

You can now add comments to inline queries without breaking them

</Update>

<Update label="September 29, 2025" description="" tags={["New Feature"]}>

### ✨ Option to turn legend off in charts

You can now turn off chart legends with legend=false

</Update>

<Update label="September 25, 2025" description="" tags={["Improvement"]}>

### 🚀 Conditional component render instantly

When previewing or viewing published pages, the initial state of any if/else_if/else conditions will be pre-calculated before the page loads.

</Update>

<Update label="September 24, 2025" description="" tags={["Improvement"]}>

### 🚀 Better label spacing on x-axis

Improvement to the alignment and spacing of labels on the x-axis

</Update>

<Update label="September 24, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fix target comparison totals in table

Fixed an issue where target comparisons were hidden in total rows

</Update>

<Update label="September 22, 2025" description="" tags={["Bug Fix","Breaking Change"]}>

### 🐛 Improved date behaviour

Previously, database columns that returned Date type would return DateTime precision, which is confusing in the UI. Now dates will return no additional time component

Values that are Date type will no longer display time component in Tables, Values, and in various input components. Eg a Date previously formatted 2025-09-22T14:05:23Z would now be returned as 2025-09-22.

</Update>

<Update label="September 21, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fix Explore table resize and scroll

Fixes an issue where tables on the Explore page would resize and cut off content

</Update>

<Update label="September 19, 2025" description="" tags={["Improvement"]}>

### 🚀 Comparison Tooltip Improvements

Fixed issue with percentage calculations for negative values. Added support for custom formats.

</Update>

<Update label="September 18, 2025" description="" tags={["New Feature"]}>

### ✨ Make Feature Requests in AI Chat

Now you can ask the Evidence chat to submit a feature request to the Evidence team

</Update>

<Update label="September 16, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fixed unexpected date offsets

In certain timezones, dates were being transposed by a small number of seconds in Chrome and Safari. This could cause date formats to render incorrectly, for example showing the day before the expected date.

</Update>

<Update label="September 15, 2025" description="" tags={["Improvement"]}>

### 🚀 RLS Enhancements

Added variable support for IN/NOT IN operators, 'Apply All' rule option, new panel interface, and per-user variable editing capabilities.

</Update>

<Update label="September 10, 2025" description="" tags={["Improvement"]}>

### 🚀 Improved Inline SQL Editor

See available variables, inline queries, and a preview of compiled SQL when editing queries in the inline SQL editor



</Update>

<Update label="September 10, 2025" description="" tags={["Improvement"]}>

### 🚀 Improved international character support in SQL queries

You can now include Japanese, Chinese, emoji, and other non-Latin characters directly in SQL passed to components

</Update>

<Update label="September 10, 2025" description="" tags={["New Feature"]}>

### ✨ Page Loading (table)

Tables now load instantly on preview and published pages

This is the first change in a journey to fully enable Server-Side Rendering in Evidence pages. The table is the first component to support this behavior, which enables the following features:<br/>- Tables load instantly on preview and published pages (no more loading spinner when the page loads)<br/>- Chat can now debug SQL query errors in Table components<br/><br/>This change lays the groundwork for other components to opt into this new Server-Side Rendering system.

</Update>

<Update label="September 8, 2025" description="" tags={["New Feature"]}>

### ✨ Add optional dark_url prop to image component

Image components can now display different images in light and dark modes using the new <code>dark_url</code> prop.

</Update>

<Update label="September 8, 2025" description="" tags={["New Feature"]}>

### ✨ Themes

Define a custom color palette to apply to all charts in a project



</Update>

<Update label="September 3, 2025" description="" tags={["Improvement","Breaking Change"]}>

### 🚀 Improved Default Funnel Chart Styling

Funnel Charts are more intuitive to read, with a squared off style



[View Documentation](https://docs.evidence.studio/components/funnel_chart)

</Update>

<Update label="September 2, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fix Comparison Issues

Fixed bug for target comparisons which resulted in undefined error

</Update>

<Update label="August 28, 2025" description="" tags={["New Feature"]}>

### ✨ Inline SQL Editor

A new SQL editor for running and modifying inline queries on your page



</Update>

<Update label="August 26, 2025" description="" tags={["New Feature"]}>

### ✨ Icon Component

Add icons inline into markdown, with configuration for color and size



[View Documentation](https://docs.evidence.studio/components/icon)

</Update>

<Update label="August 22, 2025" description="" tags={["New Feature"]}>

### ✨ Row Level Security

Add rules to restrict which rows of are visible to users from sources

Add RLS rules to data source columns, and add user variables to determine which values in these columns allow access.

[View Documentation](https://docs.evidence.studio/features/row-level-security)

</Update>

<Update label="August 20, 2025" description="" tags={["Improvement"]}>

### 🚀 Custom Color Palettes

All charts now support custom color palettes via the "chart_options" attribute

Pass an array of hex codes to the color_palette option e.g. `color_palette=["#ff0000","#00ff00"]`



[View Documentation](https://docs.evidence.studio/components/pie_chart#with-custom-colors)

</Update>

<Update label="August 20, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fix Editor Overwriting Bug

Fixed bug where switching pages and then hitting Ctrl+Z would overwrite your page with the content of the previous page.

</Update>

<Update label="August 19, 2025" description="" tags={["Improvement"]}>

### 🚀 Sidebar Hover Text

Adds hover text to sidebar items that are truncated due to length

</Update>

<Update label="August 19, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Table Filter Option Overflow

Fixed a bug where long string values in the table filter overlapped each other

</Update>

<Update label="August 18, 2025" description="" tags={["Improvement"]}>

### 🚀 Charting Library Upgrade

Upgraded to ECharts 6, fixed some issues where labels got cut off



</Update>

<Update label="August 18, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Expose SQL Errors

Exposes some SQL errors that were not being shown

</Update>

<Update label="August 18, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fix High Precision Decimals in Postgres

Resolves issue where tables containing decimal columns with more that 9 digits of precision were failing to publish

</Update>

<Update label="August 12, 2025" description="" tags={["Improvement"]}>

### 🚀 Editor Loading Speed

We've significantly improved the load speeds when switching between pages in the editor.

</Update>

<Update label="August 12, 2025" description="" tags={["New Feature"]}>

### ✨ Link Button

Use the link button to link to another page in Evidence or an external location

[View Documentation](https://docs.evidence.studio/components/link_button)

</Update>

<Update label="August 12, 2025" description="" tags={["New Feature"]}>

### ✨ Print Format Components

Add page breaks, print groups, and hide elements from PDF downloads

</Update>

<Update label="August 11, 2025" description="" tags={["New Feature"]}>

### ✨ PDF Download

Download your page as a PDF

</Update>

<Update label="August 7, 2025" description="" tags={["Bug Fix"]}>

### 🐛 If / Else Behaviour Fix

Fixed some issues with the if /else components which sometimes caused them to not display information when they should

</Update>

<Update label="August 5, 2025" description="" tags={["New Feature"]}>

### ✨ Accordian components

Organize content into collapsible accordian sections

</Update>

<Update label="August 5, 2025" description="" tags={["New Feature"]}>

### ✨ Axis Label Interval Control

More control over the intervals between labels on charts

</Update>

<Update label="July 30, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Long Page Name Overflow

Long page and directory names now truncate in the sidebar to prevent the action button being hidden



</Update>

<Update label="July 30, 2025" description="" tags={["New Feature"]}>

### ✨ Range Calendar Input

New range calendar component for date filtering.

</Update>

<Update label="July 29, 2025" description="" tags={["New Feature"]}>

### ✨ Tabs

New Tabs, and Tab components for tabbed layouts.

</Update>

<Update label="July 29, 2025" description="" tags={["New Feature"]}>

### ✨ Variables

Define variables in frontmatter and use them in markdown, SQL and components

[View Documentation](https://docs.evidence.studio/core-concepts/variables)

</Update>

<Update label="July 28, 2025" description="" tags={["New Feature"]}>

### ✨ Column-level control for tables

Control formatting for each column in a table

</Update>

<Update label="July 28, 2025" description="" tags={["New Feature"]}>

### ✨ Conditional formatting in tables

Use color scale to conditionallyformat values in a table

</Update>

<Update label="July 28, 2025" description="" tags={["New Feature"]}>

### ✨ Image support in tables

Add images to columns in a table

</Update>

<Update label="July 28, 2025" description="" tags={["Improvement"]}>

### 🚀 Improved Explore page

Supports more date grain options and improved share experience

</Update>

<Update label="July 28, 2025" description="" tags={["Improvement"]}>

### 🚀 Improved pivot table

Table now supports more complex pivot table scenarios

</Update>

<Update label="July 28, 2025" description="" tags={["New Feature"]}>

### ✨ Link support in tables

Add links to columns in a table, or set up row links

</Update>

<Update label="July 28, 2025" description="" tags={["Improvement"]}>

### 🚀 New date grain options

Inclues special grains like 'day of week' and 'month of year', with built-in labels

</Update>

<Update label="July 28, 2025" description="" tags={["New Feature"]}>

### ✨ New table visualizations

Add bar charts, sparklines, and deltas to your columns

</Update>

<Update label="July 28, 2025" description="" tags={["New Feature"]}>

### ✨ Period over period comparisons

Automatically compare values vs. prior year, prior period, or target. Available in table and big value.

</Update>

<Update label="July 22, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Delete Connections Fix

Fixed a bug which only allowed you to delete the most recently added connection

</Update>

<Update label="July 22, 2025" description="" tags={["New Feature"]}>

### ✨ Hubspot Connector

Import data from Hubspot directly into Evidence

[View Documentation](https://docs.evidence.studio/data-sources/hubspot)

</Update>

<Update label="July 22, 2025" description="" tags={["New Feature"]}>

### ✨ Modals

New modal component that can contain content in a dialogue or drawer.

[View Documentation](https://docs.evidence.studio/components/modal)

</Update>

<Update label="July 17, 2025" description="" tags={["New Feature"]}>

### ✨ Motherduck Connector

Add data sources from your Motherduck DB

[View Documentation](https://docs.evidence.studio/data-sources/motherduck)

</Update>

<Update label="July 17, 2025" description="" tags={["New Feature"]}>

### ✨ Page linking

Link to other Evidence pages using markdown links <code>[]()</code> with Intellisense support

[View Documentation](https://docs.evidence.studio/components/link)

</Update>

<Update label="July 16, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Respect columns option in table filter

Fix bug which ignored columns selection in table filter

</Update>

<Update label="July 16, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Table filter responsiveness

Fix bug which prevented table filter inputs from taking effect immediately after adding the table filter to the page.

</Update>

<Update label="July 15, 2025" description="" tags={["New Feature"]}>

### ✨ Filter interpolation

Reference filter values inside of inlined queries, and view the state of your filters in the new filters pane of the devtools sidebar.

[View Documentation](https://docs.evidence.studio/core-concepts/markdown#filters)

</Update>

<Update label="July 14, 2025" description="" tags={["Improvement"]}>

### 🚀 Agent Keyboard Shortcut

Ctrl+Alt+I (Mac: Cmd+Shift+I) to open a chat with the Evidence agent from anywhere in the Editor

</Update>

<Update label="July 11, 2025" description="" tags={["New Feature"]}>

### ✨ If, Else If, Else

Use conditional blocks to choose what to render based on data.

[View Documentation](https://docs.evidence.studio/components/if)

</Update>

<Update label="July 10, 2025" description="" tags={["New Feature"]}>

### ✨ Reference Components

Use <code>reference_line</code>, <code>reference_area</code>, and <code>reference_point</code> to add reference annotations to your charts

[View Documentation](https://docs.evidence.studio/components/reference_line)

</Update>

<Update label="July 7, 2025" description="" tags={["Improvement"]}>

### 🚀 Postgres Schema Support

Use tables in any Postgres schema (not just the default "public" schema)

</Update>

<Update label="July 3, 2025" description="" tags={["New Feature"]}>

### ✨ Import Views as Sources

All supported DBs now allow importing views as sources

</Update>

<Update label="July 3, 2025" description="" tags={["Improvement"]}>

### 🚀 Public Documentation

We've published full documentation at https://docs.evidence.studio

</Update>

<Update label="June 28, 2025" description="" tags={["New Feature"]}>

### ✨ Card Option for Row and Stack Components

Added <code>card</code> option to <code>row</code> and <code>stack</code> components to display their contents as a single card.

</Update>

<Update label="June 27, 2025" description="" tags={["New Feature"]}>

### ✨ Data Point Labels

Label each data point in your chart with the <code>data_labels</code> option

</Update>

<Update label="June 26, 2025" description="" tags={["New Feature"]}>

### ✨ Downloadable Data

Right click any chart to download its data, or use the kebab menu in the top left of the published page to download a whole page's data.

</Update>

<Update label="June 25, 2025" description="" tags={["New Feature"]}>

### ✨ Chart, Axis, and Series Options

New <code>chart_options</code>, <code>x_axis_options</code>, <code>y_axis_options</code>, <code>y2_axis_options</code>, and series options for customizing your charts.

</Update>

<Update label="June 25, 2025" description="" tags={["New Feature"]}>

### ✨ Partials

Define sections of markdown for re-use across pages.

</Update>

<Update label="June 19, 2025" description="" tags={["New Feature"]}>

### ✨ Polar Chart

Added a new polar chart component.

</Update>

<Update label="June 19, 2025" description="" tags={["New Feature"]}>

### ✨ Table Search

Search bar for the Table component.

</Update>

<Update label="June 17, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Inline Query Date Validation

Fixes issue creating visualizations using inline queries with dates

</Update>

<Update label="June 16, 2025" description="" tags={["New Feature"]}>

### ✨ Histogram

Added a new histogram chart component.

</Update>

<Update label="June 16, 2025" description="" tags={["New Feature"]}>

### ✨ Markdown Comments

Adds support for mardown comments with <code>&lt;!-- --&gt;</code>. Mac: Cmd + / Windows: Ctrl + /

</Update>

<Update label="June 13, 2025" description="" tags={["New Feature"]}>

### ✨ Calendar Heatmap

Added a new calendar heatmap chart.

</Update>

<Update label="June 13, 2025" description="" tags={["New Feature"]}>

### ✨ Combo Chart

Added a <code>combo_chart</code> component that allows you to combine <code>area</code>, <code>bar</code>, <code>bubble</code>, <code>line</code>, and <code>scatter</code> series on one chart.

</Update>

<Update label="June 12, 2025" description="" tags={["New Feature"]}>

### ✨ Accept and Reject Changes Panel in Diff View

Added accept and reject buttons to the top of the diff view.

</Update>

<Update label="June 12, 2025" description="" tags={["Improvement"]}>

### 🚀 Connection Documentation

Added generaldocumentation for data connections.

</Update>

<Update label="June 12, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fix to give AI agent knowledge of inline queries

Fixed the issue where the AI agent did not know about inline queries on your page.

</Update>

<Update label="June 12, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fix to Maintain Chart Height

Fixed the issue where the chart height was shrinking when title and legend were added.

</Update>

<Update label="June 12, 2025" description="" tags={["New Feature"]}>

### ✨ Heatmap Chart

Added a new heatmap chart component.

</Update>

<Update label="June 12, 2025" description="" tags={["Improvement"]}>

### 🚀 Link to All Docs in Sidepane

Added a link to all docs in the docs tab of the editor.

</Update>

<Update label="June 11, 2025" description="" tags={["New Feature"]}>

### ✨ Custom X and Y Chart Titles

Added the ability to customize <code>x_title</code> and <code>y_title</code> for charts.

</Update>

<Update label="June 11, 2025" description="" tags={["New Feature"]}>

### ✨ Funnel Chart

Added a new funnel chart component.

</Update>

<Update label="June 11, 2025" description="" tags={["New Feature"]}>

### ✨ Sankey Chart

Added a new sankey chart component.

</Update>

<Update label="June 10, 2025" description="" tags={["New Feature"]}>

### ✨ Changelog

We're shipping features and fixes very quickly. Keep an eye out here for updates.

</Update>

<Update label="June 10, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Fix Slash Commands When Inside Parent Component

Fixed the issue where slash commands were not working when inside a parent component.

</Update>

<Update label="June 10, 2025" description="" tags={["Improvement"]}>

### 🚀 Helpful Warning for Aggregating Columns

Added a warning to consider aggregating a column for a chart.

</Update>

<Update label="June 10, 2025" description="" tags={["New Feature"]}>

### ✨ Open Chat Automatically for Fix in Chat

When the fix in chat button is pressed, the chat window will open automatically.

</Update>

<Update label="June 10, 2025" description="" tags={["New Feature"]}>

### ✨ Pie and Donut Charts

Added a new pie chart component.

</Update>

<Update label="June 9, 2025" description="" tags={["Improvement"]}>

### 🚀 Collapse the Sidebar

Added the ability to collapse and expand the sidebar on all screen sizes.

</Update>

<Update label="June 9, 2025" description="" tags={["Improvement"]}>

### 🚀 Faster Sources Page

Significantly improved loading performance on the sources page.

</Update>

<Update label="June 9, 2025" description="" tags={["Improvement"]}>

### 🚀 Fix in Chat Now Available on All Error Messages

Error messages throughout the platform now include the fix in chat feature.

</Update>

<Update label="June 9, 2025" description="" tags={["Improvement"]}>

### 🚀 More Readable SQL Errors

SQL error messages have been redesigned to be clearer and more actionable.

</Update>

<Update label="June 9, 2025" description="" tags={["Bug Fix"]}>

### 🐛 Row and Stack Components

Fixed issues with Row and Stack components rendering and layout behavior.

</Update>

<Update label="February 3, 2025" description="" tags={["New Feature"]}>

### ✨ European Number Formatting

Support for European number format using comma as the decimal separator (e.g., 1.234,56 instead of 1,234.56).

</Update>

<Update label="January 22, 2025" description="" tags={["New Feature"]}>

### ✨ Azure Postgres Connector

Connect your Azure Database for PostgreSQL to Evidence and sync your data automatically.

[View Documentation](https://docs.evidence.studio/data-sources/azure-postgres)

</Update>

<Update label="January 20, 2025" description="" tags={["New Feature"]}>

### ✨ SQL Files

Create reusable SQL queries as standalone files. SQL files can be referenced from components using `data="path/to/query"` and from inline queries using `{{path/to/query}}` syntax.

</Update>

---

### Docs.Json (`docs/docs.json`)

{
  "$schema": "https://mintlify.com/docs.json",
  "theme": "maple",
  "thumbnails": {
    "fonts": {
      "family": "Geist"
    }
  },
  "icons": {
    "library": "lucide"
  },
  "name": "Evidence Docs",
  "colors": {
    "primary": "#2c5282",
    "light": "#2c5282",
    "dark": "#15803D"
  },
  "integrations": {
    "posthog": {
      "apiKey": "phc_5gRFl1Rp6a01CZM9CX3qDvFwyxp7YzdWvdGAgi8a1fq"
    }
  },
  "favicon": "/favicon.svg",
  "redirects": [
    {
      "source": "/features/embedded",
      "destination": "/features/embedded-analytics"
    },
    {
      "source": "/features/code-managed-access",
      "destination": "/features/page-level-access-control"
    },
    {
      "source": "/features/page-frontmatter",
      "destination": "/features/page-settings"
    },
    {
      "source": "/features/access-control",
      "destination": "/features/row-level-security"
    },
    {
      "source": "/features/access-rules",
      "destination": "/features/row-level-security"
    },
    {
      "source": "/features/project-configuration",
      "destination": "/features/project-settings"
    },
    {
      "source": "/features/mcp-server",
      "destination": "/mcp/docs"
    },
    {
      "source": "/features/evidence-mcp",
      "destination": "/mcp/studio"
    },
    {
      "source": "/install-evidence",
      "destination": "/quickstart"
    },
    {
      "source": "/getting-started/install-evidence",
      "destination": "/quickstart"
    },
    {
      "source": "/build-your-first-app",
      "destination": "/quickstart"
    },
    {
      "source": "/core-concepts/queries",
      "destination": "/evidence-warehouse"
    },
    {
      "source": "/core-concepts/formatting",
      "destination": "/core-concepts/value-formatting"
    },
    {
      "source": "/core-concepts/filters",
      "destination": "/components/filter_bar"
    },
    {
      "source": "/core-concepts/themes",
      "destination": "/features/themes"
    },
    {
      "source": "/core-concepts/templated-pages",
      "destination": "/features/page-settings"
    },
    {
      "source": "/core-concepts/exports",
      "destination": "/components/download"
    },
    {
      "source": "/core-concepts/syntax",
      "destination": "/core-concepts/markdown"
    },
    {
      "source": "/core-concepts/pages",
      "destination": "/features/page-settings"
    },
    {
      "source": "/core-concepts/query-functions",
      "destination": "/core-concepts/models"
    },
    {
      "source": "/core-concepts/if-else",
      "destination": "/components/if"
    },
    {
      "source": "/core-concepts/loops",
      "destination": "/components/repeat"
    },
    {
      "source": "/core-concepts/data-sources/duckdb",
      "destination": "/evidence-warehouse"
    },
    {
      "source": "/core-concepts/data-sources/bigquery",
      "destination": "/direct-connectors/bigquery"
    },
    {
      "source": "/core-concepts/data-sources/postgres",
      "destination": "/direct-connectors/postgres"
    },
    {
      "source": "/core-concepts/data-sources/javascript",
      "destination": "/evidence-warehouse"
    },
    {
      "source": "/core-concepts/data-sources/csv",
      "destination": "/evidence-warehouse"
    },
    {
      "source": "/core-concepts/data-sources/snowflake",
      "destination": "/direct-connectors/snowflake"
    },
    {
      "source": "/core-concepts/data-sources/google-sheets",
      "destination": "/evidence-warehouse"
    },
    {
      "source": "/core-concepts/data-sources/databricks",
      "destination": "/direct-connectors/databricks"
    },
    {
      "source": "/core-concepts/data-sources/trino",
      "destination": "/evidence-warehouse"
    },
    {
      "source": "/core-concepts/data-sources/mssql",
      "destination": "/evidence-warehouse"
    },
    {
      "source": "/core-concepts/data-sources/motherduck",
      "destination": "/direct-connectors/motherduck"
    },
    {
      "source": "/components/charts/echarts-options",
      "destination": "/components/custom_echart"
    },
    {
      "source": "/components/charts/custom-echarts",
      "destination": "/components/custom_echart"
    },
    {
      "source": "/components/charts/bar-chart",
      "destination": "/components/bar_chart"
    },
    {
      "source": "/components/charts/line-chart",
      "destination": "/components/line_chart"
    },
    {
      "source": "/components/charts/sankey-diagram",
      "destination": "/components/sankey_chart"
    },
    {
      "source": "/components/charts/heatmap",
      "destination": "/components/heatmap"
    },
    {
      "source": "/components/charts/calendar-heatmap",
      "destination": "/components/calendar_heatmap"
    },
    {
      "source": "/components/charts/mixed-type-charts",
      "destination": "/components/combo_chart"
    },
    {
      "source": "/components/charts/funnel-chart",
      "destination": "/components/funnel_chart"
    },
    {
      "source": "/components/charts/annotations",
      "destination": "/components/reference_line"
    },
    {
      "source": "/components/charts/scatter-plot",
      "destination": "/components/scatter_chart"
    },
    {
      "source": "/components/charts/area-chart",
      "destination": "/components/area_chart"
    },
    {
      "source": "/components/charts/histogram",
      "destination": "/components/histogram"
    },
    {
      "source": "/components/charts/sparkline",
      "destination": "/components/sparkline"
    },
    {
      "source": "/components/charts/bubble-chart",
      "destination": "/components/bubble_chart"
    },
    {
      "source": "/components/data/data-table",
      "destination": "/components/table"
    },
    {
      "source": "/components/data/big-value",
      "destination": "/components/big_value"
    },
    {
      "source": "/components/data/value",
      "destination": "/components/value"
    },
    {
      "source": "/components/data/delta",
      "destination": "/components/delta"
    },
    {
      "source": "/components/inputs/dropdown",
      "destination": "/components/dropdown"
    },
    {
      "source": "/components/inputs/date-range",
      "destination": "/components/range_calendar"
    },
    {
      "source": "/components/inputs/date-input",
      "destination": "/components/range_calendar"
    },
    {
      "source": "/components/inputs/dimension-grid",
      "destination": "/components/dimension_grid"
    },
    {
      "source": "/components/inputs/button-group",
      "destination": "/components/button_group"
    },
    {
      "source": "/components/inputs/slider",
      "destination": "/components/slider"
    },
    {
      "source": "/components/inputs/text-input",
      "destination": "/components/text_input"
    },
    {
      "source": "/components/inputs/checkbox",
      "destination": "/components/toggle"
    },
    {
      "source": "/components/inputs",
      "destination": "/components/dropdown"
    },
    {
      "source": "/components/maps/area-map",
      "destination": "/components/area_layer"
    },
    {
      "source": "/components/maps/point-map",
      "destination": "/components/point_layer"
    },
    {
      "source": "/components/maps/bubble-map",
      "destination": "/components/point_layer"
    },
    {
      "source": "/components/maps/us-map",
      "destination": "/components/map"
    },
    {
      "source": "/components/maps/base-map",
      "destination": "/components/map"
    },
    {
      "source": "/components/ui/embed",
      "destination": "/components/iframe"
    },
    {
      "source": "/components/ui/link",
      "destination": "/components/link"
    },
    {
      "source": "/components/ui/grid",
      "destination": "/components/row"
    },
    {
      "source": "/components/ui/tabs",
      "destination": "/components/tabs"
    },
    {
      "source": "/components/ui/big-link",
      "destination": "/components/link_button"
    },
    {
      "source": "/components/ui/link-button",
      "destination": "/components/link_button"
    },
    {
      "source": "/components/ui/image",
      "destination": "/components/image"
    },
    {
      "source": "/components/ui/info",
      "destination": "/components/info"
    },
    {
      "source": "/components/ui/alert",
      "destination": "/components/callout"
    },
    {
      "source": "/components/ui/download-data",
      "destination": "/components/download"
    },
    {
      "source": "/components/ui/details",
      "destination": "/components/details"
    },
    {
      "source": "/components/ui/print-format-components",
      "destination": "/components/print_group"
    },
    {
      "source": "/components/ui/accordion",
      "destination": "/components/accordion"
    },
    {
      "source": "/components/ui/modal",
      "destination": "/components/modal"
    },
    {
      "source": "/components/ui/note",
      "destination": "/components/note"
    },
    {
      "source": "/components/custom/custom-component",
      "destination": "/core-concepts/custom-components"
    },
    {
      "source": "/components/custom/component-queries",
      "destination": "/core-concepts/custom-components"
    },
    {
      "source": "/components/all-components",
      "destination": "/core-concepts/components"
    },
    {
      "source": "/reference/layouts",
      "destination": "/features/layouts"
    },
    {
      "source": "/reference/markdown",
      "destination": "/core-concepts/markdown"
    },
    {
      "source": "/reference/cli",
      "destination": "/cli/commands"
    },
    {
      "source": "/deployment/overview",
      "destination": "/publishing"
    },
    {
      "source": "/deployment",
      "destination": "/publishing"
    },
    {
      "source": "/deployment/self-host",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/self-host/vercel",
      "destination": "/self-host/vercel"
    },
    {
      "source": "/deployment/self-host/github-pages",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/self-host/netlify",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/self-host/gitlab-pages",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/self-host/hugging-face-spaces",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/self-host/azure-static-apps",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/self-host/firebase",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/self-host/aws-amplify",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/configuration/rendering-modes",
      "destination": "/features/project-settings"
    },
    {
      "source": "/deployment/configuration/environments",
      "destination": "/features/project-settings"
    },
    {
      "source": "/deployment/configuration/base-paths",
      "destination": "/self-host"
    },
    {
      "source": "/guides/system-requirements",
      "destination": "/self-host"
    },
    {
      "source": "/guides/updating-your-app",
      "destination": "/migration-guide"
    },
    {
      "source": "/guides",
      "destination": "/quickstart"
    },
    {
      "source": "/plugins/source-plugins",
      "destination": "/evidence-warehouse"
    },
    {
      "source": "/plugins/component-plugins",
      "destination": "/core-concepts/custom-components"
    },
    {
      "source": "/plugins/create-component-plugin",
      "destination": "/core-concepts/custom-components"
    },
    {
      "source": "/plugins/create-source-plugin",
      "destination": "/evidence-warehouse"
    },
    {
      "source": "/plugins",
      "destination": "/core-concepts/custom-components"
    },
    {
      "source": "/components/charts/box-plot",
      "destination": "/components/custom_echart"
    },
    {
      "source": "/components/ui/last-refreshed",
      "destination": "/components/html"
    },
    {
      "source": "/deployment/cloud/evidence-cloud",
      "destination": "/publishing"
    },
    {
      "source": "/guides/troubleshooting",
      "destination": "/"
    },
    {
      "source": "/guides/best-practices",
      "destination": "/"
    },
    {
      "source": "/deployment/self-host/cloudflare-pages",
      "destination": "/self-host"
    },
    {
      "source": "/getting-started/what-is-evidence",
      "destination": "/"
    },
    {
      "source": "/markdown",
      "destination": "/core-concepts/markdown"
    },
    {
      "source": "/themes-and-layouts",
      "destination": "/features/layouts"
    },
    {
      "source": "/plugins/creating-a-plugin",
      "destination": "/core-concepts/custom-components"
    },
    {
      "source": "/guides/updating-your-project",
      "destination": "/migration-guide"
    },
    {
      "source": "/components/area-map",
      "destination": "/components/area_layer"
    },
    {
      "source": "/components/us-map",
      "destination": "/components/map"
    },
    {
      "source": "/components/bubble-map",
      "destination": "/components/point_layer"
    },
    {
      "source": "/components/point-map",
      "destination": "/components/point_layer"
    },
    {
      "source": "/components/base-map",
      "destination": "/components/map"
    },
    {
      "source": "/components/download-data",
      "destination": "/components/download"
    },
    {
      "source": "/components/last-refreshed",
      "destination": "/components/html"
    },
    {
      "source": "/components/alert",
      "destination": "/components/callout"
    },
    {
      "source": "/components/big-link",
      "destination": "/components/link_button"
    },
    {
      "source": "/components/link-button",
      "destination": "/components/link_button"
    },
    {
      "source": "/components/print-format-components",
      "destination": "/components/print_group"
    },
    {
      "source": "/components/grid",
      "destination": "/components/row"
    },
    {
      "source": "/components/bubble-chart",
      "destination": "/components/bubble_chart"
    },
    {
      "source": "/components/mixed-type-charts",
      "destination": "/components/combo_chart"
    },
    {
      "source": "/components/funnel-chart",
      "destination": "/components/funnel_chart"
    },
    {
      "source": "/components/bar-chart",
      "destination": "/components/bar_chart"
    },
    {
      "source": "/components/custom-echarts",
      "destination": "/components/custom_echart"
    },
    {
      "source": "/components/box-plot",
      "destination": "/components/custom_echart"
    },
    {
      "source": "/components/annotations",
      "destination": "/components/reference_line"
    },
    {
      "source": "/components/calendar-heatmap",
      "destination": "/components/calendar_heatmap"
    },
    {
      "source": "/components/area-chart",
      "destination": "/components/area_chart"
    },
    {
      "source": "/components/line-chart",
      "destination": "/components/line_chart"
    },
    {
      "source": "/components/sankey-diagram",
      "destination": "/components/sankey_chart"
    },
    {
      "source": "/components/echarts-options",
      "destination": "/components/custom_echart"
    },
    {
      "source": "/components/scatter-plot",
      "destination": "/components/scatter_chart"
    },
    {
      "source": "/components/custom-components",
      "destination": "/core-concepts/custom-components"
    },
    {
      "source": "/components/component-queries",
      "destination": "/core-concepts/custom-components"
    },
    {
      "source": "/components/big-value",
      "destination": "/components/big_value"
    },
    {
      "source": "/components/data-table",
      "destination": "/components/table"
    },
    {
      "source": "/components/dimension-grid",
      "destination": "/components/dimension_grid"
    },
    {
      "source": "/components/checkbox",
      "destination": "/components/toggle"
    },
    {
      "source": "/components/date-range",
      "destination": "/components/range_calendar"
    },
    {
      "source": "/components/text-input",
      "destination": "/components/text_input"
    },
    {
      "source": "/components/button-group",
      "destination": "/components/button_group"
    },
    {
      "source": "/deployment/github-pages",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/aws-amplify",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/azure-static-apps",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/cloudflare-pages",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/firebase",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/gitlab-pages",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/hugging-face-spaces",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/netlify",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/vercel",
      "destination": "/self-host/vercel"
    },
    {
      "source": "/deployment/rendering-modes",
      "destination": "/features/project-settings"
    },
    {
      "source": "/deployment/base-paths",
      "destination": "/self-host"
    },
    {
      "source": "/deployment/environments",
      "destination": "/features/project-settings"
    },
    {
      "source": "/core-concepts/data-sources",
      "destination": "/evidence-warehouse"
    },
    {
      "source": "/data-sources",
      "destination": "/evidence-warehouse"
    },
    {
      "source": "/warehouses/evidence-warehouse",
      "destination": "/evidence-warehouse"
    }
  ],
  "navigation": {
    "global": {
      "anchors": [
        {
          "anchor": "Evidence Studio",
          "href": "https://evidence.studio",
          "icon": "app-window"
        },
        {
          "anchor": "Community",
          "href": "https://slack.evidence.dev",
          "icon": "slack"
        },
        {
          "anchor": "Legacy Docs",
          "href": "https://legacy-docs.evidence.dev",
          "icon": "book"
        }
      ]
    },
    "tabs": [
      {
        "tab": "Docs",
        "groups": [
          {
            "group": "Get Started",
            "pages": [
              "index",
              "quickstart",
              "migration-guide",
              "editing",
              "publishing"
            ]
          },
          {
            "group": "Core Concepts",
            "pages": [
              "core-concepts/markdown",
              "core-concepts/components",
              "core-concepts/models",
              "core-concepts/metrics",
              "core-concepts/value-formatting",
              "core-concepts/variables",
              "core-concepts/partials",
              "core-concepts/custom-components"
            ]
          },
          {
            "group": "Features",
            "pages": [
              "features/version-control",
              "features/project-settings",
              "features/page-settings",
              "features/themes",
              "features/layouts",
              "features/sql-files",
              "features/page-level-access-control",
              "features/row-level-security",
              "features/evidence-agent",
              "features/translations",
              "features/embedded-analytics",
              "features/scheduled-reports"
            ]
          },
          {
            "group": "MCP",
            "pages": [
              "mcp/overview",
              "mcp/studio",
              "mcp/docs"
            ]
          },
          {
            "group": "CLI",
            "pages": [
              "cli/index",
              "cli/connections",
              "cli/commands"
            ]
          },
          {
            "group": "Self Host",
            "pages": [
              "self-host/index",
              "self-host/authentication",
              "self-host/vercel",
              "self-host/render",
              "self-host/fly",
              "self-host/railway"
            ]
          },
          {
            "group": "Direct Connectors",
            "pages": [
              "direct-connectors/snowflake",
              "direct-connectors/fabric",
              "direct-connectors/clickhouse",
              "direct-connectors/bigquery",
              "direct-connectors/databricks",
              "direct-connectors/postgres",
              "direct-connectors/cube",
              "direct-connectors/motherduck"
            ]
          },
          {
            "group": "Evidence Warehouse",
            "pages": [
              "evidence-warehouse",
              {
                "group": "Databases",
                "expanded": false,
                "icon": "database",
                "pages": [
                  "data-sources/athena",
                  "data-sources/motherduck",
                  "data-sources/redshift"
                ]
              },
              {
                "group": "Object Storage",
                "expanded": false,
                "icon": "hard-drive",
                "pages": [
                  "data-sources/abs",
                  "data-sources/backblaze",
                  "data-sources/custom",
                  "data-sources/gcs",
                  "data-sources/r2",
                  "data-sources/s3"
                ]
              },
              {
                "group": "Data Lakes",
                "expanded": false,
                "icon": "layers",
                "pages": [
                  "data-sources/deltalake_s3",
                  "data-sources/iceberg"
                ]
              },
              {
                "group": "Flat Files",
                "expanded": false,
                "icon": "file",
                "pages": [
                  "data-sources/file"
                ]
              }
            ]
          },
          {
            "group": "Components",
            "pages": [
              {
                "group": "Values",
                "expanded": false,
                "icon": "shapes",
                "pages": [
                  "components/value",
                  "components/big_value",
                  "components/delta",
                  "components/heat_grid",
                  "components/progress_bars"
                ]
              },
              {
                "group": "Tables",
                "expanded": false,
                "icon": "table-2",
                "pages": [
                  "components/table",
                  "components/dimension",
                  "components/measure",
                  "components/pivot"
                ]
              },
              {
                "group": "Charts",
                "expanded": false,
                "icon": "chart-column-increasing",
                "pages": [
                  "components/area_chart",
                  "components/bar_chart",
                  "components/bubble_chart",
                  "components/calendar_heatmap",
                  "components/candlestick",
                  "components/chord_chart",
                  "components/combo_chart",
                  "components/custom_echart",
                  "components/funnel_chart",
                  "components/heatmap",
                  "components/histogram",
                  "components/horizontal_bar_chart",
                  "components/line_chart",
                  "components/pie_chart",
                  "components/polar_chart",
                  "components/radar_chart",
                  "components/sankey_chart",
                  "components/scatter_chart",
                  "components/treemap",
                  "components/waterfall_chart",
                  "components/area",
                  "components/bar",
                  "components/bubble",
                  "components/line",
                  "components/reference_area",
                  "components/reference_line",
                  "components/reference_point",
                  "components/scatter",
                  "components/sparkline"
                ]
              },
              {
                "group": "Maps",
                "expanded": false,
                "icon": "map",
                "pages": [
                  "components/custom_map",
                  "components/map",
                  "components/area_layer",
                  "components/heatmap_layer",
                  "components/point_layer"
                ]
              },
              {
                "group": "Inputs",
                "expanded": false,
                "icon": "text-cursor-input",
                "pages": [
                  "components/button_group",
                  "components/comparison_selector",
                  "components/benchmark_comparison",
                  "components/target_comparison",
                  "components/date_grain_selector",
                  "components/dropdown",
                  "components/filter_bar",
                  "components/input_tabs",
                  "components/option",
                  "components/range_calendar",
                  "components/slider",
                  "components/table_filter",
                  "components/text_input",
                  "components/toggle",
                  "components/dimension_grid",
                  "components/period_selector"
                ]
              },
              {
                "group": "Custom",
                "expanded": false,
                "icon": "code-xml",
                "pages": [
                  "components/html"
                ]
              },
              {
                "group": "UI",
                "expanded": false,
                "icon": "layout-template",
                "pages": [
                  "components/accordion",
                  "components/accordion_item",
                  "components/accordion_title",
                  "components/audio",
                  "components/callout",
                  "components/clock",
                  "components/commentary",
                  "components/details",
                  "components/download",
                  "components/fence",
                  "components/file",
                  "components/hidden_in_print",
                  "components/icon",
                  "components/iframe",
                  "components/image",
                  "components/info",
                  "components/line_break",
                  "components/link",
                  "components/link_button",
                  "components/logo",
                  "components/modal",
                  "components/note",
                  "components/only_in_print",
                  "components/page_break",
                  "components/partial",
                  "components/print_group",
                  "components/row",
                  "components/stack",
                  "components/tab",
                  "components/tabs"
                ]
              },
              {
                "group": "Logic",
                "expanded": false,
                "icon": "trending-up-down",
                "pages": [
                  "components/if",
                  "components/else_if",
                  "components/else",
                  "components/repeat"
                ]
              }
            ]
          }
        ]
      },
      {
        "tab": "Changelog",
        "groups": [
          {
            "group": "Changelog",
            "pages": [
              "changelog"
            ]
          }
        ]
      }
    ]
  },
  "logo": {
    "light": "/logo/wordmark-light.png",
    "dark": "/logo/wordmark-dark.png"
  },
  "footer": {
    "socials": {
      "x": "https://x.com/evidence_dev",
      "github": "https://github.com/evidence-dev",
      "linkedin": "https://linkedin.com/company/evidence-dev",
      "slack": "https://slack.evidence.dev",
      "bluesky": "https://bsky.app/profile/evidence.dev"
    }
  }
}

---

### Editing (`docs/editing.mdx`)

---
title: 'Editing'
description: 'The Evidence Editor is the core of Evidence Studio, allowing you to create and edit reports in markdown and SQL.'
---

import StudioOnly from '/snippets/studio-only.mdx';

<StudioOnly />

## Code Editor

On the left hand side of your screen, you have a code editor. This is where you define your report in markdown.

The code editor is enriched for data development with:

- **Slash commands:** Type a `/` to list components, accept suggestions with `tab`.
- **Autocompletion:** For components and SQL fences, accept suggestions with `tab`.
- **Syntax highlighting:** For markdown, SQL, and components.
- **Validation**: Invalid code is underlined in red, hover to see errors, and click "Fix" for AI assistance.

## Preview

As you modify the code in the editor, the preview will update in real time, including rerunning SQL queries and rerendering charts when you make changes.

Nothing is published until you click the "Publish" button. See [Publishing](/publishing) for details.

## Evidence Agent

The right sidebar contains a chat interface with the Evidence Agent.

- The agent is trained to generate valid Evidence markdown
- It knows the schema of any data sources you have added

The agent can generate reports, fix errors, and answer general questions about Evidence Studio.

### Agent Capabilities

The agent can help you across most of what you do in Studio, including:

- **Read and edit pages:** Generate new reports or make targeted edits to existing markdown, SQL, and components.
- **Run SQL queries:** Execute SQL against your connected data sources to explore data and validate results before writing it into a report.
- **Inspect your data:** Read the schema and metadata of tables, sources, and models, and list available connections to see what data is available.
- **Read existing visualizations:** Pull the data behind a chart, table, or value already on the page to reason about and extend it.
- **Update settings:** Adjust project and page settings (theme, layout, table of contents, default date range, and more) and edit project config files like `theme.yaml` and `evidence.config.yaml`.
- **Diagnose errors:** Identify and fix invalid SQL, broken components, and other issues in your reports.
- **Search the docs:** Answer questions about Evidence Studio, components, and SQL using the documentation.

The Evidence Agent suggests changes in a "diff view", which you can accept, reject, or refine with another message.

---

### Evidence Warehouse (`docs/evidence-warehouse.mdx`)

---
title: 'Evidence Warehouse'
sidebarTitle: 'Overview'
description: 'Evidence''s built-in managed warehouse, and the connectors that load data into it.'
keywords:
  - data warehouse
  - managed warehouse
  - data integration
  - cloud warehouse
  - direct connectors
  - data lake
  - etl data integration
  - zero etl
---

import StudioOnly from '/snippets/studio-only.mdx';

<StudioOnly />

The **Evidence Warehouse** is Evidence's built-in, fully managed cloud warehouse. You connect a data source once, Evidence extracts the data into the warehouse, and every report queries it from there — fast, with no infrastructure for you to run. You choose which region the data is stored in (see [Storage Regions](#storage-regions)). When you use the managed warehouse, Evidence handles etl data integration for you — extracting, loading, and making data available for reporting on a schedule.

Connectors are how you get data into the Evidence Warehouse. You connect to your data source once, then use that data across all your reports. With this data integration workflow, your reports always query the same extracted data, regardless of which source it came from.

Evidence supports different types of connectors: **Databases**, **Object Storage**, **Data Lakes**, **Flat Files**, and **Applications**.

If you'd rather have Evidence query a warehouse you own directly — without extracting data into the Evidence Warehouse — use a [native connector](#direct-connectors) instead.

---

## Databases

Database connectors connect to your existing data warehouse or database. Evidence extracts the data, and you can define a schedule for sync.

**How it works:**

1. You provide connection credentials to your database
2. Evidence runs queries against your database to extract data
3. Data is cached in Evidence's query engine in your chosen region
4. Reports query the cached data for fast performance

You choose where your extracted data is stored. See [available regions](#storage-regions).

**Best for:**

- Existing data warehouses (Snowflake, BigQuery, Redshift, etc.)
- Data that's already modeled and ready to report on
- Teams who want Evidence to manage the data pipeline

**Supported databases:**

- [Snowflake](/direct-connectors/snowflake)
- [BigQuery](/direct-connectors/bigquery)
- [PostgreSQL](/data-sources/postgres)
- [RDS PostgreSQL](/data-sources/rds-postgres)
- [Redshift](/data-sources/redshift)
- [MotherDuck](/data-sources/motherduck)
- [Athena](/data-sources/athena)
- [MySQL](/data-sources/mysql)
- [SQL Server](/data-sources/sqlserver)
- [Azure SQL Database](/data-sources/azure-sql)
- [Azure Postgres](/data-sources/azure-postgres)
- [Databricks](/data-sources/databricks)

We are continuously adding support for new databases. Request one [here](https://evidence.dev/contact-us).

---

## Direct Connectors

Prefer to keep your data in your own warehouse? **Native connectors** are the alternative to the Evidence Warehouse: instead of extracting data, Evidence runs queries live against a warehouse you own. Each request from a viewer issues queries against your warehouse and returns the rows directly. This is a zero etl approach — since the warehouse is queried directly, there's no extraction, loading, or sync pipeline to maintain.

**How it works:**

1. You provide credentials with read access to your warehouse
2. Evidence issues queries directly to your warehouse when viewers load reports

**Key characteristics:**

- **Always live**: viewers see the current state of your warehouse on every load — no sync schedule.
- **Data stays in your warehouse**: Evidence holds credentials but doesn't store data.

**Best for:**

- Use cases where data freshness is important
- Strict data residency requirements
- Teams that already maintain RLS policies in their warehouse and want Evidence to honour them

Native connectors live in the **Warehouses** section:

- [Snowflake](/direct-connectors/snowflake)
- [Fabric](/direct-connectors/fabric)
- [ClickHouse](/direct-connectors/clickhouse)
- [BigQuery](/direct-connectors/bigquery)

---

## Object Storage

Object storage connectors read Parquet files directly from cloud storage buckets that you control. Evidence queries the data in place using ClickHouse's S3 table engine. In addition to the below named providers, any S3 compatible storage is supported (via the "custom S3" connector).

**How it works:**

1. You store Parquet files in your own bucket (S3, GCS, Azure, etc.)
2. You provide bucket credentials to Evidence
3. Evidence queries the Parquet files directly — no data is copied

**Key characteristics:**

- **Instant data availability**: When you update a Parquet file in your bucket, the new data is immediately available in Evidence—no sync or publish required
- **Schema changes require publish**: Adding or removing columns requires clicking **Publish** or setting up a refresh schedule
- **Data stays in your infrastructure**: Your data never leaves your bucket, Evidence queries it in place
- **S3-compatible**: Any storage provider with an S3-compatible API works (AWS S3, GCS, Azure Blob, Cloudflare R2, MinIO, Backblaze B2, etc.)

**Best for:**

- Data residency or sovereignty requirements
- Teams who manage their own data pipelines and produce Parquet files
- High-frequency data updates where you control the source files
- Keeping data within your own infrastructure

**Supported providers:**

- [AWS S3](/data-sources/s3)
- [Google Cloud Storage](/data-sources/gcs)
- [Azure Blob Storage](/data-sources/abs)
- [Cloudflare R2](/data-sources/r2)
- [Backblaze B2](/data-sources/backblaze)
- [Custom S3-compatible provider](/data-sources/custom)

---

## Data Lakes

Data lake connectors connect to open table formats that provide ACID transactions, schema evolution, and time travel capabilities on top of object storage.

**How it works:**

1. You provide credentials to your data lake catalog or storage
2. Evidence reads the table metadata and data files
3. Data is queried with full support for the table format's features

**Best for:**

- Teams using modern lakehouse architectures
- Large-scale data with complex partitioning
- Scenarios requiring time travel or schema evolution

**Supported data lakes:**

- [Iceberg](/data-sources/iceberg)
- [Delta Lake](/data-sources/deltalake_s3)

---

## Applications

Application connectors sync data from SaaS applications and APIs. Evidence uses Fivetran to extract and normalize data from these sources.

**How it works:**

1. You authenticate with the application (OAuth or API key)
2. Evidence syncs data on a configurable schedule
3. Data is normalized and stored in Evidence's query engine

**Best for:**

- Product analytics and operational reporting
- Combining SaaS data with your data warehouse
- Teams who want turnkey integrations without building pipelines

**Supported applications:**

- [Linear](/data-sources/linear)
- [HubSpot](/data-sources/hubspot)
- [Stripe](/data-sources/stripe)
- [GitHub](/data-sources/github)
- [Attio](/data-sources/attio)
- [PostHog](/data-sources/posthog)
- [Google Ads](/data-sources/google-ads)
- [Facebook Ads](/data-sources/facebook-ads)
- [Twilio](/data-sources/twilio)

We are continuously adding support for new applications. Request one [here](https://evidence.dev/contact-us).

---

## Flat Files

Upload flat files directly to Evidence for quick data analysis without setting up external connections.

**How it works:**

1. Upload a file directly through the Evidence interface
2. Evidence processes and stores the data
3. Query the data immediately in your reports

**Supported formats:**

- CSV
- Parquet
- JSONL
- Excel

**Best for:**

- Quick prototyping and ad-hoc analysis
- Small datasets that don't require a database
- Getting started with Evidence before connecting external sources

See [Flat Files](/data-sources/file) for details.

---

## Comparison

|                    | Databases              | Object Storage            | Data Lakes             | Flat Files             | Applications           |
| ------------------ | ---------------------- | ------------------------- | ---------------------- | ---------------------- | ---------------------- |
| **Data location**  | Data is extracted      | Stays in your bucket      | Stays in your storage  | Uploaded to Evidence   | Data is extracted      |
| **Data updates**   | Scheduled sync         | Instant (for row changes) | Scheduled sync         | Re-upload file         | Scheduled sync         |
| **Schema changes** | Requires re-publish    | Requires re-publish       | Requires re-publish    | Re-upload file         | Requires re-publish    |
| **Data residency** | Choose Evidence region | Your bucket location      | Your storage location  | Choose Evidence region | Choose Evidence region |

---

## Storage Regions

Evidence supports the following storage regions for extracted data.

| Region                    | Location               |
| ------------------------- | ---------------------- |
| `us-central1`             | Iowa, USA              |
| `us-east1`                | South Carolina, USA    |
| `us-east4`                | Virginia, USA          |
| `us-east5`                | Ohio, USA              |
| `us-west1`                | Oregon, USA            |
| `us-west2`                | Los Angeles, USA       |
| `us-west3`                | Salt Lake City, USA    |
| `us-west4`                | Las Vegas, USA         |
| `northamerica-northeast1` | Montreal, Canada       |
| `northamerica-northeast2` | Toronto, Canada        |
| `europe-west2`            | London, UK             |
| `europe-west3`            | Frankfurt, Germany     |
| `europe-west4`            | Eemshaven, Netherlands |
| `europe-west6`            | Zurich, Switzerland    |
| `europe-west8`            | Milan, Italy           |
| `europe-west9`            | Paris, France          |
| `europe-west10`           | Berlin, Germany        |
| `asia-south1`             | Mumbai, India          |
| `asia-southeast1`         | Singapore              |
| `asia-northeast1`         | Tokyo, Japan           |
| `australia-southeast1`    | Sydney, Australia      |

---

## Create a connection

(For databases only)

1. On the sources page, click New Connection
2. Enter the connection details for your database. Note that you require one connection per schema at this time.
3. Click **Test** to verify the connection is configured correctly.
4. Click **Save**.

### IP Whitelisting

If your database requires IP whitelisting, add the Evidence Studio IP addresses:

```
3.21.143.81
3.209.193.182
3.215.195.233
18.189.109.43
34.56.211.45
35.192.240.48
35.192.240.49
35.192.240.50
35.192.240.51
35.192.240.52
35.192.240.53
35.192.240.54
35.192.240.55
35.234.176.144
35.234.176.145
35.234.176.146
35.234.176.147
35.234.176.148
35.234.176.149
35.234.176.150
35.234.176.151
104.197.50.84
*.us-east4.gcp.proxy.prod.fivetran.com
*.us-central1.gcp.proxy.prod.fivetran.com
```

## Import a data source

1. On the sources page, click **New Source**.
2. Select the connection you just created.
3. Choose from the tables in the connection.
4. (Optional) Rename the source - this is used to reference the source in your reports.
5. Click **Save**.

## Import a file

1. On the sources page, click **Upload File**.
   - You can upload CSV, Parquet, and JSONL files.
2. Your file will be automatically imported, and named using a `snake_case` version of the filename.

## Updating data

<Warning>You can only update uploaded **files** by reuploading them.</Warning>

### Manual refresh

1. On the sources page, click the `...` menu on the right of the source and select **Publish**.

### Scheduled refresh

1. In the sources page, click the `...` menu on the right of the source and select **Schedule**.
2. Choose a refresh interval.
   - Current refresh intervals are: 5 mins, 15 mins, 1 hour, 1 day, 1 week. Contact Evidence for custom intervals.
3. Click **Save**.

---

### Migration Guide (`docs/migration-guide.mdx`)

---
title: Migration Guide
description: Migrate a legacy Evidence project to Evidence Studio
---

Legacy Evidence is a static website generator: Markdown and DuckDB SQL which queries data you package up in a build step. Evidence Studio has a live connection to a database, and an updated set of components that can generate SQL.

## How to migrate

The CLI has a `evidence migrate` command. It converts everything it can mechanically — component syntax, attribute names, input references, connections, source SQL - and prints a warning for items it cannot migrate.

The fastest path is to let a coding agent support your migration.

1. **Install the [Evidence CLI](/cli)** (version ≥ 0.9.0)
2. **Add the migration skill to your project:** Save the file below into your legacy project as `.claude/skills/evidence-migrate/SKILL.md`, or the equivalent path for your assistant.
3. **Ask your assistant to migrate the project:** "Migrate this Evidence project to Studio syntax." The skill tells it which commands to run and how to work through the warnings.

To run it yourself: `evidence migrate --dry-run` to preview, `evidence migrate` to convert in place, then `evidence validate` for syntax and SQL errors and `evidence dev` to inspect the result.

### The migration skill

```
/* Detailed source-code truncated for AI context efficiency. */
```

## What works differently

|                      | Legacy Evidence                                        | Evidence Studio                                                                                                              |
| -------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| **Component syntax** | Svelte: `<LineChart data={orders} x=date y=sales />`   | Markdoc: `{% line_chart data="orders" x="date" y="sum(sales)" /%}`                                                           |
| **Component data**   | Renders a query you wrote                              | Writes its own SQL — [aggregations](/core-concepts/components), `date_grain`, comparisons, `filters`, `where`                |
| **SQL**              | DuckDB, in-browser (WASM)                              | Server-side: ClickHouse, or your warehouse's dialect via a [direct connector](/direct-connectors/snowflake)                  |
| **Data prep**        | `sources/*.sql` queries run at build                   | Sync data to Evidence on a schedule, or update your data warehouse                                                           |
| **SQL files**        | `queries/*.sql`, interpolated with `${inputs.x.value}` | `/queries/*.sql` inlined verbatim — `{{ }}` variables do **not** resolve; move input-driven SQL into a SQL block on the page |
| **Variables**        | `${inputs.category.value}`                             | `{{category}}`, or `filters=["category"]` — see [Variables](/core-concepts/variables)                                        |
| **Logic**            | Svelte/JS in pages: `{#each}`, `{#if}`, `{@const}`     | [`{% repeat %}`](/components/repeat), [`{% if %}`](/components/if)                                                           |
| **Builds**           | Build required for every data or content change        | No build, Queries re-run on page load                                                                                        |
| **Deployment**       | Configure hosting and a build pipeline                 | Publish in seconds, from Evidence Studio or linked GitHub repo                                                               |
| **Scale**            | ~2M rows                                               | Hundreds of millions of rows                                                                                                 |
| **Access control**   | Build it yourself                                      | SSO, [page permissions](/features/page-level-access-control), [row-level access rules](/features/row-level-security), user groups  |
| **Self-service**     | Reports                                                | Reports + Insights + AI Chat                                                                                                 |

## Not supported

| Legacy feature                            | Instead                                                                                            |
| ----------------------------------------- | -------------------------------------------------------------------------------------------------- |
| Templated pages (`[param].md`)            | One page driven by an input — a dropdown wired to every component via `filters`                    |
| Source SQL queries (`sources/`)           | Sync the table, or a view in your database, then use [Models](/core-concepts/models)               |
| Svelte files and custom Svelte components | [Custom components](/core-concepts/custom-components), or `{% custom_echart %}` / `{% html %}`     |
| JS expressions and Svelte blocks in pages | `{% repeat %}`, `{% if %}`, or compute it in SQL                                                   |
| Box plots, Venn diagrams                  | No equivalent                                                                                      |
| Drill-through links on maps               | No equivalent — maps support tooltips only                                                         |
| Secondary y-axis (`y2=`)                  | Rebuild as [`{% combo_chart %}`](/components/combo_chart) with `axis="y2"` on the secondary series |
| `<ECharts>` config objects                | Move the config into the [`{% custom_echart %}`](/components/custom_echart) body                   |
| Horizontal 100% stacked bars              | Regular stacked `{% horizontal_bar_chart %}`                                                       |

Individual attributes without an equivalent are dropped with a warning by `evidence migrate`; run it with `--dry-run` to see the full list for your project.

## Getting help

Ask in the [Slack community](https://slack.evidence.dev), or [book a migration call](https://calendly.com/evidence-studio/evidence-studio-migration).

---

### Publishing (`docs/publishing.mdx`)

---
title: 'Publishing'
description: 'Publish your reports on Evidence Studio, or self host your reports to share them with your team.'
---

## Evidence Studio

### How to publish

There are three ways to publish:

- **From the editor.** Open the Publish menu in the top right of the editor and click **Publish**. The menu shows pending changes, any open pull request, and the current publish state.
- **From local dev.** Push to the project's published branch using git or the [Evidence CLI](/cli). The push triggers a publish automatically.
- **From GitHub.** Merge a pull request into the published branch on GitHub.

You can use any combination of these — Studio, your local environment, and GitHub stay in sync through the project's repo.

### Pull requests

When you open a pull request against the published branch, Evidence runs checks and posts a preview:

- **Markdown validation check:** Catches invalid syntax and broken components before merge.
- **`access.yaml` validation check:** Validates [page level access](/features/page-level-access-control) rules so a bad config can't take down viewer access.
- **Preview link:** A comment on the PR linking to a deployed preview of the branch, so reviewers can see the report before merging.

The checks appear as status checks on the PR — you can configure branch protection in GitHub to block merges until they pass.

### Publish history and rollback

Every project has a publish history page that lists every publish attempt (publishes, CLI/local pushes, and PR merges), with who triggered it, the commit, the result, and a detail view for failures.

From the history page you can:

- **Roll back** to any previous successful publish.
- **Retry** a failed publish.

### Reliable publishes

- **Failed publishes never affect viewers.** If a publish fails, the previous successful version stays live. Viewers don't see broken reports while you fix the issue.
- **Email alerts on failure.** Org admins get an email when a publish fails.
- **Project banner on failure.** When the latest publish failed, every project page in Studio shows a banner linking to the failure in history.

### Connecting GitHub

By default, every project is backed by an Evidence-managed git repo — you don't need to do anything to get the publish flow above. If you want the repo to live in your own GitHub organization so you can edit it locally, review changes through your existing PR process, or hook it into your own CI, connect the Evidence GitHub App:

1. **Install the Evidence GitHub App.** From **Organization Settings**, connect Evidence to your GitHub account or organization. You can grant access to all repos or just the ones you choose, and update that selection later.
2. **Link a repo to a project.** Open the project, then **Project Settings → Version Control**, and select **Connect to GitHub repository**. Pick the repo, the branch to use as the published branch, and the project root path.
3. **First publish.** Click **Publish** in the editor to push the current state to GitHub. From then on, all three publish flows (editor, local dev, GitHub PR merge) work against your repo.

See [Version Control](/features/version-control) for branching strategies and the list of files that are version controlled.

#### GitHub Enterprise Cloud

Enterprise organizations can connect a GitHub Enterprise Cloud account hosted on a dedicated `*.ghe.com` domain:

1. In **Organization Settings**, select **Connect GitHub Enterprise**.
2. Enter the enterprise hostname (for example, `arkaan.ghe.com`) and the GitHub organization that owns your repositories.
3. Continue to GitHub to create and install the private, organization-owned Evidence Studio GitHub App.
4. Return to a project's **Version Control** settings and select one of the repositories available to the App.

Evidence supports GitHub Enterprise Cloud with data residency on `*.ghe.com`. Self-hosted GitHub Enterprise Server domains are not supported. An Evidence organization can connect to either GitHub.com or one GHE.com host at a time. Disconnect all projects from the current host before replacing the organization connection.

### Sharing access

Once a report is published, control who can view it with `access.yaml`. See [Page Level Access Control](/features/page-level-access-control) for the full schema and patterns for sharing with teammates, groups, and external customers.

Roles are managed from the [Team Settings](https://www.evidence.studio/settings/team) page:

- **Viewer:** Can view published reports they've been granted access to.
- **Org Viewer:** Can view all published reports in the org.
- **Developer:** Can edit reports and configure data sources.
- **Admin:** Developer permissions plus organization settings.

## Self Host

Alternatively, run your project as a self-hosted site — no Evidence Studio account required. See [Self Host](/self-host) for the Docker image, project setup, and platform guides for Vercel, Render, Fly.io, and Railway, plus a [feature comparison](/self-host#self-host-vs-evidence-studio) with Evidence Studio.

---

### Cli Commands (`docs/cli/commands.mdx`)

---
title: 'Commands'
description: 'Reference for all Evidence CLI commands.'
---

## Development

### `evidence init`

Scaffold a new Evidence project.

```bash
evidence init my-project
evidence init my-project --warehouse snowflake
```

| Option        | Description                                                                                                                                |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `--warehouse` | Scaffold a `connection.yaml` for a direct warehouse connection: `snowflake` or `bigquery`. See [Connecting a Warehouse](/cli/connections). |

Without `--warehouse`, the project uses the managed Evidence Warehouse. With it, the CLI writes a `connection.yaml` (gitignored) so queries run directly against your own warehouse.

### `evidence dev`

Start the local development server.

```bash
evidence dev
evidence dev --port 8080
```

| Option         | Description                    |
| -------------- | ------------------------------ |
| `--port`, `-p` | Port to run on (default: 3000) |

## Deploy

### `evidence launch`

Connect this project to Evidence Studio and GitHub, then deploy by pushing to your repo. Interactive by default — it walks you through installing the GitHub App and creating (or linking) the Studio project.

```bash
evidence launch
evidence launch --name "My Project" --upload-credentials
```

| Option                 | Description                                                                                                                                                         |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--name`               | Name for the Studio project to create.                                                                                                                              |
| `--branch`             | Branch to publish from (default: auto-detected).                                                                                                                    |
| `--root-directory`     | Project root within the repo (default: auto-detected).                                                                                                              |
| `--upload-credentials` | Upload warehouse credentials from [`connection.yaml`](/cli/connections) to your org. Prompted for interactively; required to opt in when running non-interactively. |

`evidence launch` recognizes GitHub.com and GitHub Enterprise Cloud (`*.ghe.com`) remotes over HTTPS and SSH. If the detected GHE.com host is not connected yet, the CLI opens Organization Settings to guide an Evidence admin through creating and installing the private Enterprise GitHub App. GHE.com connections require Evidence Studio on the Enterprise plan.

### `evidence link`

Attach this repo to an **existing** Studio project. The project's content becomes git-managed — the next `git push` overwrites it with the repo's contents.

```bash
evidence link my-project
evidence link --project my-project
```

| Option             | Description                                                                      |
| ------------------ | -------------------------------------------------------------------------------- |
| `--project`        | Studio project to attach, by slug or id. Also accepted as a positional argument. |
| `--branch`         | Branch to publish from (default: auto-detected).                                 |
| `--root-directory` | Project root within the repo (default: auto-detected).                           |

The repository host must match the GitHub host connected to the Evidence organization.

### `evidence unlink`

Disconnect this repo from its Studio project. The org's GitHub App install and the project itself are left intact.

```bash
evidence unlink
evidence unlink --project my-project
```

| Option      | Description                                                                                                                     |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `--project` | Studio project to unlink, by slug or id. Inferred from the repo's binding when omitted. Also accepted as a positional argument. |

## Data

### `evidence query`

Run a SQL query against connected data sources.

```bash
evidence query "SELECT * FROM orders LIMIT 10"
evidence query --file query.sql
cat query.sql | evidence query -
```

| Option           | Description                                              |
| ---------------- | -------------------------------------------------------- |
| `--format`       | Output format: `json` (default), `jsonl`, `table`, `csv` |
| `--limit`, `-l`  | Limit number of rows                                     |
| `--quiet`, `-q`  | Suppress status messages                                 |
| `--columns`      | Output only column names and types                       |
| `--file`         | Read SQL from a file                                     |
| `--output`, `-o` | Write results to a file                                  |

### `evidence tables`

List available data tables.

```bash
evidence tables
```

### `evidence describe`

Show schema for a table.

```bash
evidence describe demo_daily_orders
```

### `evidence schema`

Show all tables with their columns.

```bash
evidence schema
```

### `evidence connectors`

List all connectors with health status.

```bash
evidence connectors
evidence connectors --json
```

Shows connector name, type, status, last sync, schedule, table count, and reference count for all connector types.

### `evidence models`

List all models with refresh status.

```bash
evidence models
evidence models --json
```

Shows model name, status, last refresh time, and schedule.

### `evidence lineage`

Show where connections and tables are used across projects, pages, models, and queries.

```bash
evidence lineage
evidence lineage table orders
evidence lineage --branch dev/alex
evidence lineage --json
```

| Option         | Description                               |
| -------------- | ----------------------------------------- |
| `table <name>` | Show where a specific table is referenced |
| `--branch`     | Query a specific branch (default: main)   |
| `--json`       | Output JSON for tooling                   |

## Project

### `evidence validate`

Validate all markdown files in the current project.

```bash
evidence validate
evidence validate --json
```

### `evidence docs`

Browse and search component documentation.

```bash
evidence docs                         # Overview
evidence docs search "chart"          # Search docs
evidence docs component bar_chart     # Component details
```

## Authentication

### `evidence signup`

Create an account and workspace. Opens Evidence in your browser; once done, run `evidence login` to connect the CLI.

```bash
evidence signup
```

### `evidence login`

Authenticate with Evidence Studio using your browser.

```bash
evidence login
```

### `evidence logout`

Clear stored credentials.

```bash
evidence logout
```

### `evidence whoami`

Show the currently authenticated user.

```bash
evidence whoami
```

### `evidence orgs`

List available organizations.

```bash
evidence orgs
```

### `evidence switch`

Switch to a different organization.

```bash
evidence switch "My Organization"
```

### `evidence token`

Generate a token for headless/CI use. Prints an `EVIDENCE_AUTH_TOKEN` value you can set as an environment variable to authenticate without an interactive login. Requires an active login and a selected organization.

```bash
evidence token
```

<Warning>The generated token contains a long-lived access token. Treat it as a secret.</Warning>

## Utility

### `evidence version`

Print the current CLI version.

```bash
evidence version
```

### `evidence upgrade`

Upgrade to the latest CLI version.

```bash
evidence upgrade
```

### `evidence help`

Show help and available commands.

```bash
evidence help
```

### `evidence telemetry`

Show or change anonymous usage reporting. See [Telemetry](/cli#telemetry) for what is sent.

```bash
evidence telemetry            # same as status
evidence telemetry status
evidence telemetry disable
evidence telemetry enable
```

## Self-hosting

### `evidence serve`

Serve the project as a self-hosted site. Runs the built-in production server — no Evidence Studio account or session required.

```bash
evidence serve
evidence serve --port 8080
evidence serve --host 0.0.0.0
```

| Option         | Description                                    |
| -------------- | ---------------------------------------------- |
| `--port`, `-p` | Port to run on (default: 3000)                 |
| `--host`       | Bind address (default: `127.0.0.1`)            |
| `--open`       | Open the browser after starting (default: off) |

Requires a direct connector configured in [`connection.yaml`](/cli/connections) — the managed query engine is not supported for self-hosting.

To serve beyond localhost, set `EVIDENCE_BASIC_USER` and `EVIDENCE_BASIC_PASSWORD` to protect the site with HTTP Basic Auth. The server refuses to start on a non-localhost `--host` without these set.

On a trusted private network (VPN, Tailscale, internal VPC), `EVIDENCE_AUTH_DISABLED=true` skips authentication entirely.

---

### Cli Connections (`docs/cli/connections.mdx`)

---
title: 'Connect your CLI to your data'
sidebarTitle: 'Connections'
description: 'Connect the Evidence CLI to the Evidence Warehouse or to a warehouse you own.'
---

How the CLI gets data depends on how your project is set up.

## Evidence Warehouse

If you use the [Evidence Warehouse](/evidence-warehouse), run `evidence login`. No further setup is needed.

## Other warehouses

If you use a [direct connection](/evidence-warehouse#direct-connectors) to a warehouse you own, add a `connection.yaml` file to the root of your project. When this file is present, the CLI queries your warehouse **directly from your machine** — no login required.

### Scaffold with `evidence init`

The quickest way to create a `connection.yaml` is to pass `--warehouse` to `evidence init`:

```bash
evidence init my-project --warehouse snowflake
# or
evidence init my-project --warehouse bigquery
```

This writes a `connection.yaml` in the project root pre-filled with placeholder values, and adds it to `.gitignore` (the file holds credentials — keep it out of version control).

<Warning>
`connection.yaml` and any files it references — the Snowflake private-key `.pem` or the BigQuery service-account JSON — contain credentials. Never commit them. `evidence init --warehouse` gitignores `connection.yaml` for you, but **not** the referenced key files: add those to `.gitignore` yourself, or use the inline `private_key` / `keyfile_json` fields so there's no separate file to leak.
</Warning>

Fill in the placeholders with your own connection details. If `--warehouse` is omitted, no `connection.yaml` is written and the project uses the Evidence Warehouse.

### Configuration

<Tabs>
  <Tab title="Snowflake">
    ```yaml
    type: snowflake
    account: xy12345.us-east-1
    user: evidence_user
    private_key_path: ./snowflake-key.pem
    warehouse: COMPUTE_WH
    database: ANALYTICS
    # role: EVIDENCE_READER
    # schema: { production: ANALYTICS, devSchemas: [DEV_ALICE] }
    ```

    Provide exactly one of `password`, `private_key`, or `private_key_path`. Paths (`private_key_path`) are resolved relative to `connection.yaml`.

    See the [Snowflake direct connector](/direct-connectors/snowflake) for the full field reference and how to create a read-only Snowflake user.
  </Tab>
  <Tab title="BigQuery">
    ```yaml
    type: bigquery
    project: my-gcp-project
    keyfile: ./evidence-bq-primary.json
    datasets:
      - analytics
      - reporting
    # dataset: analytics
    # location: US
    ```

    Provide exactly one of `keyfile` or `keyfile_json`. The `keyfile` path is resolved relative to `connection.yaml`.

    See the [BigQuery direct connector](/direct-connectors/bigquery) for the full field reference and the service-account setup steps.
  </Tab>
</Tabs>

---

### Components Accordion (`docs/components/accordion.mdx`)

---
title: Accordion
description: An accordion component that organizes content into collapsible sections.
keywords: ["collapsible","expandable","disclosure"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

```liquid
{% accordion %}
  ...
{% /accordion %}
```

## Attributes

<ResponseField name="single" type="boolean" default="false">
  Whether only one item can be open at a time
</ResponseField>

<ResponseField name="variant" type="string" default="default">
  Visual style variant of the accordion

**Allowed values:**
- `default`
- `well`
- `card`
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

## Allowed Children

- [accordion_item](/components/accordion_item)

---

### Components Accordion Item (`docs/components/accordion_item.mdx`)

---
title: Accordion Item
description: An accordion item that can be expanded or collapsed.
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% accordion %}
    {% accordion_item title="Section 1" open=true %}
        Content for section 1.
    {% /accordion_item %}
    {% accordion_item title="Section 2" %}
        Content for section 2.
    {% /accordion_item %}
    {% accordion_item title="Section 3" icon="settings" %}
        Content for section 3 with an icon.
    {% /accordion_item %}
{% /accordion %}
````

## Examples

### Accordion with Items

````liquid
{% accordion %}
    {% accordion_item title="Section 1" open=true %}
        Content for section 1.
    {% /accordion_item %}
    {% accordion_item title="Section 2" %}
        Content for section 2.
    {% /accordion_item %}
    {% accordion_item title="Section 3" icon="settings" %}
        Content for section 3 with an icon.
    {% /accordion_item %}
{% /accordion %}
````

## Attributes

<ResponseField name="title" type="string">
  Title displayed in the accordion item header. For rich titles (e.g. containing another component), nest an `accordion_title` tag instead. When both are provided, the nested `accordion_title` takes precedence and this attribute is ignored.
</ResponseField>

<ResponseField name="icon" type="string">
  Icon to display in the accordion item header

**Allowed values:**
- `trending-up`
- `trending-down`
- `clock`
- `calendar`
- `check`
- `x`
- `info`
- `alert-circle`
- `help-circle`
- `eye`
- `eye-off`
- `user`
- `users`
- `settings`
- `cog`
- `plus`
- `minus`
- `up`
- `down`
- `right`
- `left`
- `star`
- `heart`
- `search`
- `file`
- `file-text`
- `home`
- `mail`
- `filter`
- `share`
- `bell`
- `trash`
- `credit-card`
- `globe`
- `key`
- `croissant`
- `map`
- `rotate`
- `rewind`
- `bank`
- `receipt`
- `activity`
- `chart-column`
- `chart-pie`
- `chart-no-axes-combined`
- `goal`
- `rocket`
- `trophy`
- `apple`
- `cookie`
- `donut`
- `beef`
- `cake`
- `soup`
- `utensils`
- `milk`
- `nut`
- `pyramid`
- `triangle`
- `arrow-down`
- `arrow-left`
- `arrow-right`
- `arrow-up`
- `chevron-down`
- `chevron-left`
- `chevron-right`
- `chevron-up`
- `chevrons-down`
- `chevrons-left`
- `chevrons-right`
- `chevrons-up`
- `menu`
- `external-link`
- `check-circle`
- `x-circle`
- `edit`
- `trash-2`
- `copy`
- `save`
- `download`
- `upload`
- `send`
- `refresh`
- `redo`
- `undo`
- `folder`
- `folder-open`
- `image`
- `file-image`
- `user-plus`
- `user-minus`
- `user-check`
- `lock`
- `unlock`
- `log-in`
- `log-out`
- `message-square`
- `message-circle`
- `phone`
- `phone-call`
- `bell-off`
- `video`
- `video-off`
- `play`
- `pause`
- `stop`
- `skip-back`
- `skip-forward`
- `volume`
- `volume-1`
- `volume-2`
- `volume-off`
- `volume-x`
- `bookmark`
- `tag`
- `link`
- `unlink`
- `share-2`
- `alert-triangle`
- `loader`
- `more-vertical`
- `more-horizontal`
- `grid`
- `list`
- `maximize`
- `minimize`
- `zoom-in`
- `zoom-out`
- `thumbs-up`
- `thumbs-down`
- `shopping-cart`
- `dollar-sign`
- `camera`
- `printer`
- `monitor`
- `smartphone`
- `laptop`
- `calculator`
- `cloud-sun-rain`
- `sun-snow`
- `thermometer-sun`
- `thermometer-snowflake`
- `cloudy`
- `cloud-rain-wind`
- `cloud-rain`
- `wind`
- `sun`
- `cloud-snow`
- `thermometer`
- `cloud-drizzle`
- `cloud-sun`
- `cloud`
- `cloud-lightning`
- `snowflake`
- `flame`
- `atom`
- `fuel`
- `magnet`
- `factory`
- `tree-deciduous`
- `waypoints`
- `plug`
- `dam`
- `battery`
</ResponseField>

<ResponseField name="open" type="boolean" default="false">
  Whether the accordion item is initially open
</ResponseField>



## Allowed Parents

- [accordion](/components/accordion)

---

### Components Accordion Title (`docs/components/accordion_title.mdx`)

---
title: Accordion Title
description: Rich title content for an accordion item. Use this instead of the `title` attribute when the title needs to contain other components (e.g. `big_value`).
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

## Examples

### Accordion item with a big_value in the title

````liquid
{% accordion %}
    {% accordion_item %}
        {% accordion_title padding_top=8 padding_bottom=8 %}
            {% big_value data="orders" value="sum(sales)" fmt="usd" /%}
        {% /accordion_title %}
        Body content for this section.
    {% /accordion_item %}
{% /accordion %}
````

## Attributes

<ResponseField name="padding_top" type="number" default="16">
  Top padding of the accordion trigger, in pixels. Lower this when the slotted content already provides its own top padding.
</ResponseField>

<ResponseField name="padding_bottom" type="number" default="16">
  Bottom padding of the accordion trigger, in pixels. Lower this when the slotted content already provides its own bottom padding.
</ResponseField>



## Allowed Parents

- [accordion_item](/components/accordion_item)

---

### Components Area (`docs/components/area.mdx`)

---
title: Area
description: Add an area series to a [combo_chart](/components/combo_chart)
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% area y="sum(total_sales)" /%}
{% /combo_chart %}
````

## Examples

### Basic Area Series

````liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% area y="sum(total_sales)" /%}
{% /combo_chart %}
````

### Unstacked Areas

````liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% area y="sum(total_sales)" series="category" stacked=false /%}
{% /combo_chart %}
````

### Area with Gradient Fill

````liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% area y="sum(total_sales)" stacked=false options={
        gradient=true
    } /%}
{% /combo_chart %}
````

## Attributes

<ResponseField name="y" type="string">
  Column name for y-axis. Aggregated at the parent combo_chart's `x=`. Omit when using `metric`.
</ResponseField>

<ResponseField name="metric" type="string">
  Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes.
</ResponseField>

<ResponseField name="series" type="string">
  Column name for series grouping
</ResponseField>

<ResponseField name="axis" type="string" default="y1">
  The axis to render the series on

**Allowed values:**
- `y1`
- `y2`
</ResponseField>

<ResponseField name="fmt" type="string">
  Format for this series' values. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.
</ResponseField>

<ResponseField name="data_labels" type="options group">
  Label each point in the series with its value

**Example:**
```
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}
```

**Attributes:**
- position: `string` - Position the label relative to its data point
  - **Allowed values:**
    - `above`
    - `below`
    - `left`
    - `right`
    - `middle`
- fmt: `string` - Format the label value. Defaults to series or axis fmt.
  - **Allowed values:** See [Value Formatting](/core-concepts/value-formatting) for all available formats.
- size: `number` - Font size in px
- distance: `number` - How far the label is from the data point
- rotate: `number` - Rotate each label (degrees)
- color: `string` - Change the text color of the labels
- border_color: `string` - Change the border color surrounding text labels, defaults to chart background
- show_overlap: `boolean` - Show labels for every point even when they overlap

</ResponseField>

<ResponseField name="options" type="options group">
  

**Example:**
```
options={
  step = "start"
  smooth = true
  gradient = true
}
```

**Attributes:**
- step: `string` - Show a stepped line rather than a smooth line between points and control where the step happens (start, middle, or end)
  - **Allowed values:**
    - `start`
    - `middle`
    - `end`
- smooth: `boolean`
- gradient: `boolean` - Apply a color-to-transparent gradient fill to the area, fading from the series color at the top to transparent at the bottom

</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into this series only. For overrides that apply to every series on the chart, set `echarts_series_options` on the parent chart instead.

**Example:**
```
echarts_options={
    endLabel={ show=true }
    markPoint={ data=[{ type="max" }, { type="min" }] }
}
```
</ResponseField>

<ResponseField name="stacked" type="boolean | string" default="true">
  Whether to stack areas with the same series value. Set to "100%" for percentage stacking.
</ResponseField>

<ResponseField name="stack_id" type="string">
  Stack identifier - areas with the same stack_id value will be stacked together. Overrides the stacked prop.
</ResponseField>



## Allowed Parents

- [combo_chart](/components/combo_chart)

---

### Components Area Chart (`docs/components/area_chart.mdx`)

---
title: Area Chart
description: Display an area chart
keywords: ["area graph","area plot","stacked area"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% area_chart
	data="demo.daily_orders"
	x="date"
	y="sum(total_sales)"
	date_grain="month"
/%}
````

## Examples

### Basic Usage



````liquid
{% area_chart
	data="demo.daily_orders"
	x="date"
	y="sum(total_sales)"
	date_grain="month"
/%}
````

### Area Chart with Series



````liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    series="category"
    date_grain="month"
/%}
````

### Area Chart with Formatting



````liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    title="Sales Over Time"
    subtitle="Monthly sales performance"
    date_grain="month"
/%}
````

### 100% Stacked Area Chart



````liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    series="category"
    stacked="100%"
    date_grain="month"
    title="Sales Distribution by Category"
/%}
````

### Revenue by Day of Week



````liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="day of week"
    title="Revenue by Day of Week"
    subtitle="Weekday vs weekend sales patterns"
/%}
````

### Seasonality Analysis (Month of Year)



````liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="month of year"
    title="Seasonality Analysis"
    subtitle="Sales patterns across months"
/%}
````

### Quarterly Trends



````liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="quarter of year"
    title="Quarterly Performance"
    subtitle="Q1 through Q4 comparison"
/%}
````

### Monthly Billing Cycle Patterns



````liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="day of month"
    title="Daily Revenue by Day of Month"
    subtitle="Identify billing cycle patterns"
/%}
````

### Week Number Analysis



````liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="week of year"
    title="Revenue by Week of Year"
    subtitle="Weekly performance across the year"
/%}
````

### Day of Year Analysis



````liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="day of year"
    title="Revenue by Day of Year"
    subtitle="Identify patterns across 365 days"
/%}
````

### Area Chart with Gradient Fill



````liquid
{% area_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="month"
    stacked=false
    area_options={
        gradient=true
    }
/%}
````

## Attributes

<ResponseField name="data" type="string">
  Name of the table to query. Required unless every child series uses `metric="..."` — metric children resolve their own base from the metric view.
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="date_grain" type="string">
  Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

**Allowed values:**
- `day`
- `week`
- `month`
- `quarter`
- `year`
- `hour`
- `day of week`
- `day of month`
- `day of year`
- `week of year`
- `month of year`
- `quarter of year`
</ResponseField>

<ResponseField name="handle_missing" type="string" default="connect">
  How to handle missing data points. "connect" auto-connects points (default), "gaps" shows visual breaks, "zero" fills with zeros.

**Allowed values:**
- `connect`
- `gaps`
- `zero`
</ResponseField>

<ResponseField name="x" type="string">
  Column name for x-axis. Required unless every child series uses `metric="..."` — metric children fall back to the metric view's time column.
</ResponseField>

<ResponseField name="x_fmt" type="string">
  Format for x values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="y_fmt" type="string">
  Format for y values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="y2_fmt" type="string">
  Format for y2 values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="series" type="string">
  Column name for series grouping (applies to all series)
</ResponseField>

<ResponseField name="point_title" type="string">
  Column name for individual point labels displayed at the top of the tooltip
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the component
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text (can only be used with title). Displays an info icon next to the title.
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>

<ResponseField name="x_sort" type="string">
  Sort order for x-axis categories. Options: `asc` (alphabetical), `desc` (reverse alphabetical), `data` (preserve query order), or an array for custom order like `["A", "B", "C"]`

**Allowed values:**
- `asc`
- `desc`
- `data`
</ResponseField>

<ResponseField name="y_axis_options" type="options group">
  Configure the y-axis

**Example:**
```
y_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}
```

**Attributes:**
- title: `string`
- title_position: `string` - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
  - **Allowed values:**
    - `top`
    - `side`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.

</ResponseField>

<ResponseField name="y2_axis_options" type="options group">
  Configure the secondary y-axis

**Example:**
```
y2_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}
```

**Attributes:**
- title: `string`
- title_position: `string` - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
  - **Allowed values:**
    - `top`
    - `side`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.

</ResponseField>

<ResponseField name="x_axis_options" type="options group">
  Configure the x-axis

**Example:**
```
x_axis_options={
  title = "string"
  show_title = true
  label_wrap = true
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  min_interval = "year"
  max_interval = "year"
  interval = 0
  label_rotate = 0
  title_arrow = true
  max_label_length = 0
}
```

**Attributes:**
- title: `string`
- show_title: `boolean` - When `true`, renders the auto-derived axis title (the x column name) below the chart. Ignored when `title` is set explicitly. Defaults to `false` — auto-derived column-name titles usually read as visual noise and the axis labels speak for themselves.
- label_wrap: `boolean`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0. Defaults to true for numeric x-axes, false otherwise.
- min_interval: `string` - Minimum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
- max_interval: `string` - Maximum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
- label_rotate: `number` - Rotation angle of axis label in degrees. Positive values rotate clockwise, negative values rotate counter-clockwise.
- title_arrow: `boolean` - Show/hide the arrow (→) on the axis title
- max_label_length: `number` - Maximum character length for axis labels. Labels exceeding this length will be truncated with an ellipsis. Defaults to 20 characters when labels are rotated.

</ResponseField>

<ResponseField name="legend" type="boolean" default="true">
  Show legend. Studio's built-in legend renders a compact color swatch + series name. For chart-wide style overrides that need the legend to reflect them precisely (line width, custom symbols, richer styling), set `legend=false` and provide `legend={ show=true ... }` inside `echarts_options` to use ECharts' native legend instead.
</ResponseField>

<ResponseField name="legend_location" type="string" default="top">
  Position of the legend (top or bottom)

**Allowed values:**
- `top`
- `bottom`
</ResponseField>

<ResponseField name="series_order" type="array">
  Array of series names to define the order of series in the chart and legend. Series not in the array will appear after the ordered ones.
</ResponseField>

<ResponseField name="chart_options" type="options group">
  Studio-shaped chart styling shortcuts (palette, series colors, zoom, padding). For raw ECharts overrides, use `echarts_options` instead.

**Example:**
```
chart_options={
  color_palette = ["#3b82f6", "#8b5cf6", "#ec4899"]
  series_colors = {
    "Series A" = "#3b82f6"
    "Series B" = "#10b981"
    "Series C" = "#f59e0b"
  }
  zoom = true
  top_padding = 0
}
```

**Attributes:**
- color_palette: `array of strings` - Array of hex color codes to use for series colors
- series_colors: `map of key-value pairs` - Map of series names to hex color codes for custom series coloring
- zoom: `boolean` - Enables zoom by dragging on the chart area
- top_padding: `number` - Additional padding (in px) above the chart area to prevent labels from being cut off

</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `dataZoom`, `visualMap`, `graphic`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For per-series overrides, use `echarts_series_options` or the per-series `echarts_options` on a `line`/`bar`/etc. child.

**Example:**
```
echarts_options={
    tooltip={ position="top" }
    dataZoom=[{ type="slider" }]
}
```
</ResponseField>

<ResponseField name="echarts_series_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into every data series in the chart. Use when the same override should apply to all series. Skips reference lines/areas/points. For a single series, set `echarts_options` on the series child instead.

**Example:**
```
echarts_series_options={
    itemStyle={ borderRadius=8 }
    markLine={ data=[{ type="average" }] }
}
```
</ResponseField>

<ResponseField name="y" type="string | array">
  Column name for y-axis
</ResponseField>

<ResponseField name="metric" type="string | array">
  Semantic metric name(s) to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. Pass an array for multiple series (e.g. `metric=["revenue", "orders"]`).
</ResponseField>

<ResponseField name="fmt" type="string">
  Format for this series' values. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.
</ResponseField>

<ResponseField name="data_labels" type="options group">
  Label each point in the series with its value

**Example:**
```
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}
```

**Attributes:**
- position: `string` - Position the label relative to its data point
  - **Allowed values:**
    - `above`
    - `below`
    - `left`
    - `right`
    - `middle`
- fmt: `string` - Format the label value. Defaults to series or axis fmt.
  - **Allowed values:** See [Value Formatting](/core-concepts/value-formatting) for all available formats.
- size: `number` - Font size in px
- distance: `number` - How far the label is from the data point
- rotate: `number` - Rotate each label (degrees)
- color: `string` - Change the text color of the labels
- border_color: `string` - Change the border color surrounding text labels, defaults to chart background
- show_overlap: `boolean` - Show labels for every point even when they overlap

</ResponseField>

<ResponseField name="options" type="options group">
  

**Example:**
```
options={
  step = "start"
  smooth = true
  gradient = true
}
```

**Attributes:**
- step: `string` - Show a stepped line rather than a smooth line between points and control where the step happens (start, middle, or end)
  - **Allowed values:**
    - `start`
    - `middle`
    - `end`
- smooth: `boolean`
- gradient: `boolean` - Apply a color-to-transparent gradient fill to the area, fading from the series color at the top to transparent at the bottom

</ResponseField>

<ResponseField name="stacked" type="boolean | string" default="true">
  Whether to stack the areas. Set to "100%" for percentage stacking where each area shows its proportion of the total.
</ResponseField>

<ResponseField name="y2" type="string | array">
  Column name for secondary y-axis
</ResponseField>

<ResponseField name="area_options" type="options group">
  

**Example:**
```
area_options={
  step = "start"
  smooth = true
  gradient = true
}
```

**Attributes:**
- step: `string` - Show a stepped line rather than a smooth line between points and control where the step happens (start, middle, or end)
  - **Allowed values:**
    - `start`
    - `middle`
    - `end`
- smooth: `boolean`
- gradient: `boolean` - Apply a color-to-transparent gradient fill to the area, fading from the series color at the top to transparent at the bottom

</ResponseField>

## Allowed Children

- [reference_line](/components/reference_line)
- [reference_area](/components/reference_area)
- [reference_point](/components/reference_point)

---

### Components Area Layer (`docs/components/area_layer.mdx`)

---
title: Area Layer
description: Add a choropleth layer to a map
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% map %}
    {% area_layer
        geography="us_states"
        match_by="name"
        data="state_sales"
        area_id="state"
        value="sum(sales)"
    /%}
{% /map %}
````

## Examples

### US States by Name

````liquid
{% map %}
    {% area_layer
        geography="us_states"
        match_by="name"
        data="state_sales"
        area_id="state"
        value="sum(sales)"
    /%}
{% /map %}
````

### US States by Abbreviation

````liquid
{% map %}
    {% area_layer
        geography="us_states"
        match_by="abbr"
        data="state_sales"
        area_id="state_abbr"
        value="sum(sales)"
    /%}
{% /map %}
````

### US Counties by State + County

````liquid
{% map %}
    {% area_layer
        geography="us_counties"
        match_by="state-county"
        data="county_sales"
        area_id="state || '-' || county"
        value="sum(sales)"
    /%}
{% /map %}
````

### US Counties by FIPS

````liquid
{% map %}
    {% area_layer
        geography="us_counties"
        match_by="fips"
        data="county_sales"
        area_id="state_fips || county_fips"
        value="sum(sales)"
    /%}
{% /map %}
````

### Custom GeoJSON

````liquid
{% area_layer
    geojson_url="https://example.com/custom.geojson"
    geojson_id="id"
    data="my_data"
    area_id="region_id"
    value="sum(sales)"
/%}
````

### Diverging Scale Centered at 0

````liquid
{% map %}
    {% area_layer
        geography="us_states"
        match_by="abbr"
        data="state_growth"
        area_id="state_abbr"
        value="growth_pct"
        color_scale=["#d73027", "#ffffbf", "#1a9850"]
        min=-100
        max=100
        midpoint=0
    /%}
{% /map %}
````

### Custom Breakpoints

````liquid
{% map %}
    {% area_layer
        geography="us_states"
        match_by="abbr"
        data="state_sales"
        area_id="state_abbr"
        value="sum(sales)"
        color_stops=[
            { value=0 color="#ffffff" },
            { value=10000 color="#f59e0b" },
            { value=50000 color="#1a9850" }
        ]
    /%}
{% /map %}
````

## Attributes

<ResponseField name="data" type="string" required>
  Name of the table to query
</ResponseField>

<ResponseField name="filters" type="array">
  Array of filter IDs to apply
</ResponseField>

<ResponseField name="geography" type="string">
  Pre-provided geography (use this OR geojson_url + geojson_id)

**Allowed values:**
- `us_states`
- `us_counties`
</ResponseField>

<ResponseField name="match_by" type="string">
  How to match areas. For us_states: "name", "abbr", or "fips". For us_counties: "state-county" or "fips".
</ResponseField>

<ResponseField name="geojson_url" type="string">
  URL to custom GeoJSON file (use with geojson_id for custom maps)
</ResponseField>

<ResponseField name="geojson_id" type="string">
  GeoJSON property to join on. Use a string for single property (e.g., "NAME") or array for composite key (e.g., ["STATE", "COUNTY"]).
</ResponseField>

<ResponseField name="area_id" type="string" required>
  Column name in data that matches geo_id (e.g., "state_id")
</ResponseField>

<ResponseField name="value" type="string" required>
  Column or expression for coloring the choropleth (e.g., "sum(sales)")
</ResponseField>

<ResponseField name="color_scale" type="array">
  Array of colors for the choropleth gradient. A single-color array auto-expands to [background, color].
</ResponseField>

<ResponseField name="color_palette" type="array">
  Deprecated. Use `color_scale`.
</ResponseField>

<ResponseField name="min" type="number">
  Lower bound for the color scale. Values below this clamp to the first color in the scale. Defaults to the minimum value in the data.
</ResponseField>

<ResponseField name="max" type="number">
  Upper bound for the color scale. Values above this clamp to the last color in the scale. Defaults to the maximum value in the data.
</ResponseField>

<ResponseField name="midpoint" type="number">
  Anchor a specific value (typically 0) at the middle of a diverging color scale. Requires a color_scale with 3 or more colors.
</ResponseField>

<ResponseField name="color_stops" type="array">
  Pin specific data values to specific colors, interpolating between them. Provide an array of value and color pairs. Values beyond the first and last breakpoint are clamped to the end colors. Takes precedence over color_scale, min, max, and midpoint.
</ResponseField>

<ResponseField name="show_unmatched" type="boolean" default="true">
  Whether to show areas that do not have matching data
</ResponseField>

<ResponseField name="tooltip" type="boolean" default="true">
  Show tooltips on hover
</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Array of SQL expressions for additional fields to show in tooltip (e.g., ["category", "emissions"])
</ResponseField>

<ResponseField name="name_property" type="string">
  GeoJSON property to use for area name in tooltip (defaults to "NAME")
</ResponseField>

<ResponseField name="value_fmt" type="string" default="num">
  Format for values in tooltip. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="zoom_threshold" type="array">
  Zoom range [min, max] where this layer is visible (e.g., [0, 8] shows layer from zoom 0 to 8)
</ResponseField>

<ResponseField name="legend" type="boolean" default="true">
  Show legend for this layer
</ResponseField>

<ResponseField name="legend_label" type="string">
  Custom label for the legend (defaults to table name)
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>



## Allowed Parents

- [map](/components/map)

---

### Components Audio (`docs/components/audio.mdx`)

---
title: Audio
description: Embed an audio player for mp3, wav, and other audio formats
keywords: ["sound","music","podcast","mp3","wav","media","player"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% audio url="https://files.example.com/podcast/episode-01.mp3" /%}
````

## Examples

### Basic Audio Player

````liquid
{% audio url="https://files.example.com/podcast/episode-01.mp3" /%}
````

### WAV File with Title

````liquid
{% audio url="https://files.example.com/recordings/call.wav" type="wav" title="Call Recording" /%}
````

## Attributes

<ResponseField name="url" type="string" required>
  URL of the audio file (may include query parameters such as SAS tokens)
</ResponseField>

<ResponseField name="type" type="string" default="mpeg">
  MIME subtype of the audio file (e.g. mpeg, wav, ogg, mp4). Mapped to audio/[type] for the browser.
</ResponseField>

<ResponseField name="title" type="string">
  Accessible label for the audio player
</ResponseField>

---

### Components Bar (`docs/components/bar.mdx`)

---
title: Bar
description: Add a bar series to a [combo_chart](/components/combo_chart)
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bar y="sum(total_sales)" /%}
{% /combo_chart %}
````

## Examples

### Basic Bar Series

````liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bar y="sum(total_sales)" /%}
{% /combo_chart %}
````

### Unstacked Bars

````liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bar y="sum(total_sales)" series="category" stacked=false /%}
{% /combo_chart %}
````

### Multiple Stacks

````liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bar y="sum(total_sales)" stack_id="sales" /%}
    {% bar y="sum(total_sales)+1000000" stack_id="sales" /%}
    {% bar y="sum(quantity)" stack_id="quantity" /%}
{% /combo_chart %}
````

### Extra tooltip fields

````liquid

{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bar
        y="sum(total_sales)"
        fmt="usd"
        tooltip_fields=[
            { value="count(distinct order_id)" label="Orders" },
            { value="sum(total_sales) - lag(sum(total_sales)) over (order by date_trunc('month', date))" label="MoM Δ" fmt="usd" color_by_sign=true }
        ]
    /%}
{% /combo_chart %}
````

## Attributes

<ResponseField name="y" type="string">
  Column name for y-axis. Aggregated at the parent combo_chart's `x=`. Omit when using `metric`.
</ResponseField>

<ResponseField name="metric" type="string">
  Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes.
</ResponseField>

<ResponseField name="series" type="string">
  Column name for series grouping
</ResponseField>

<ResponseField name="axis" type="string" default="y1">
  The axis to render the series on

**Allowed values:**
- `y1`
- `y2`
</ResponseField>

<ResponseField name="fmt" type="string">
  Format for this series' values. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.
</ResponseField>

<ResponseField name="data_labels" type="options group">
  Label each point in the series with its value

**Example:**
```
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}
```

**Attributes:**
- position: `string` - Position the label relative to its data point
  - **Allowed values:**
    - `above`
    - `below`
    - `left`
    - `right`
    - `middle`
- fmt: `string` - Format the label value. Defaults to series or axis fmt.
  - **Allowed values:** See [Value Formatting](/core-concepts/value-formatting) for all available formats.
- size: `number` - Font size in px
- distance: `number` - How far the label is from the data point
- rotate: `number` - Rotate each label (degrees)
- color: `string` - Change the text color of the labels
- border_color: `string` - Change the border color surrounding text labels, defaults to chart background
- show_overlap: `boolean` - Show labels for every point even when they overlap

</ResponseField>

<ResponseField name="options" type="options group">
  

**Attributes:**
- color: `string`
- opacity: `number` - Between 0 and 1

</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into this series only. For overrides that apply to every series on the chart, set `echarts_series_options` on the parent chart instead.

**Example:**
```
echarts_options={
    endLabel={ show=true }
    markPoint={ data=[{ type="max" }, { type="min" }] }
}
```
</ResponseField>

<ResponseField name="stacked" type="boolean | string" default="true">
  Whether to stack bars with the same series value. Set to "100%" for percentage stacking.
</ResponseField>

<ResponseField name="stack_id" type="string">
  Stack identifier - bars with the same stack_id value will be stacked together. Overrides the stacked prop.
</ResponseField>



## Allowed Parents

- [combo_chart](/components/combo_chart)

---

### Components Bar Chart (`docs/components/bar_chart.mdx`)

---
title: Bar Chart
description: Display a bar chart
keywords: ["column chart","bar graph","bar plot"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% bar_chart
	data="demo.daily_orders"
	x="category"
	y="sum(total_sales)"
/%}
````

## Examples

### Basic Usage



````liquid
{% bar_chart
	data="demo.daily_orders"
	x="category"
	y="sum(total_sales)"
/%}
````

### Bar Chart with Date Grain



````liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    date_grain="month"
/%}
````

### Sorting by Value



````liquid
{% bar_chart
    data="demo.daily_orders"
    x="category"
    y="sum(total_sales)"
    order="sum(total_sales) desc"
/%}
````

### Custom Category Order



````liquid
{% bar_chart
    data="demo.daily_orders"
    x="category"
    y="sum(total_sales)"
    x_sort=["Clothing", "Home", "Sports", "Electronics"]
/%}
````

### Bar Chart with Series Colors



````liquid
{% bar_chart
    data="demo.daily_orders"
    x="category"
    y="sum(total_sales)"
    series="case when sum(total_sales) > 7000 then '>$7k' when sum(total_sales) > 3500 then '>$3.5k' else '<$3.5k' end"
    title="Sales by Category and Performance"
    chart_options={
        series_colors={
            ">$7k"="#22c55e"
            ">$3.5k"="#f59e0b"
            "<$3.5k"="#ef4444"
        }
    }
/%}
````

### 100% Stacked Bar Chart



````liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    series="category"
    stacked="100%"
    date_grain="month"
    title="Sales Distribution by Category"
/%}
````

### Revenue by Day of Week



````liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="day of week"
    title="Revenue by Day of Week"
    subtitle="Weekday vs weekend sales patterns"
/%}
````

### Seasonality Analysis (Month of Year)



````liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="month of year"
    title="Seasonality Analysis"
    subtitle="Sales patterns across months"
/%}
````

### Quarterly Trends



````liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="quarter of year"
    title="Quarterly Performance"
    subtitle="Q1 through Q4 comparison"
/%}
````

### Monthly Billing Cycle Patterns



````liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="day of month"
    title="Daily Revenue by Day of Month"
    subtitle="Identify billing cycle patterns"
/%}
````

### Week Number Analysis



````liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="week of year"
    title="Revenue by Week of Year"
    subtitle="Weekly performance across the year"
/%}
````

### Day of Year Analysis



````liquid
{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="day of year"
    title="Revenue by Day of Year"
    subtitle="Identify patterns across 365 days"
/%}
````

### Extra tooltip fields

````liquid

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    y_fmt="usd"
    date_grain="month"
    tooltip_fields=[
        { value="count(distinct order_id)" label="Orders" },
        { value="sum(total_sales) / nullif(count(distinct order_id), 0)" label="Avg order" fmt="usd" }
    ]
/%}
````

### Raw ECharts overrides (rounded bars, background track)

````liquid
{% bar_chart
    data="demo.daily_orders"
    x="category"
    y="sum(total_sales)"
    echarts_series_options={
        itemStyle={ borderRadius=[6, 6, 0, 0] }
        showBackground=true
        backgroundStyle={ color="rgba(0,0,0,0.04)" }
    }
/%}
````

## Attributes

<ResponseField name="data" type="string">
  Name of the table to query. Required unless every child series uses `metric="..."` — metric children resolve their own base from the metric view.
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="date_grain" type="string">
  Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

**Allowed values:**
- `day`
- `week`
- `month`
- `quarter`
- `year`
- `hour`
- `day of week`
- `day of month`
- `day of year`
- `week of year`
- `month of year`
- `quarter of year`
</ResponseField>

<ResponseField name="handle_missing" type="string" default="connect">
  How to handle missing data points. "connect" auto-connects points (default), "gaps" shows visual breaks, "zero" fills with zeros.

**Allowed values:**
- `connect`
- `gaps`
- `zero`
</ResponseField>

<ResponseField name="x" type="string">
  Column name for x-axis. Required unless every child series uses `metric="..."` — metric children fall back to the metric view's time column.
</ResponseField>

<ResponseField name="x_fmt" type="string">
  Format for x values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="y_fmt" type="string">
  Format for y values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="y2_fmt" type="string">
  Format for y2 values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="series" type="string">
  Column name for series grouping (applies to all series)
</ResponseField>

<ResponseField name="point_title" type="string">
  Column name for individual point labels displayed at the top of the tooltip
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the component
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text (can only be used with title). Displays an info icon next to the title.
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>

<ResponseField name="x_sort" type="string">
  Sort order for x-axis categories. Options: `asc` (alphabetical), `desc` (reverse alphabetical), `data` (preserve query order), or an array for custom order like `["A", "B", "C"]`

**Allowed values:**
- `asc`
- `desc`
- `data`
</ResponseField>

<ResponseField name="y_axis_options" type="options group">
  Configure the y-axis

**Example:**
```
y_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}
```

**Attributes:**
- title: `string`
- title_position: `string` - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
  - **Allowed values:**
    - `top`
    - `side`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.

</ResponseField>

<ResponseField name="y2_axis_options" type="options group">
  Configure the secondary y-axis

**Example:**
```
y2_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}
```

**Attributes:**
- title: `string`
- title_position: `string` - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
  - **Allowed values:**
    - `top`
    - `side`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.

</ResponseField>

<ResponseField name="x_axis_options" type="options group">
  Configure the x-axis

**Example:**
```
x_axis_options={
  title = "string"
  show_title = true
  label_wrap = true
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  min_interval = "year"
  max_interval = "year"
  interval = 0
  label_rotate = 0
  title_arrow = true
  max_label_length = 0
}
```

**Attributes:**
- title: `string`
- show_title: `boolean` - When `true`, renders the auto-derived axis title (the x column name) below the chart. Ignored when `title` is set explicitly. Defaults to `false` — auto-derived column-name titles usually read as visual noise and the axis labels speak for themselves.
- label_wrap: `boolean`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0. Defaults to true for numeric x-axes, false otherwise.
- min_interval: `string` - Minimum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
- max_interval: `string` - Maximum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
- label_rotate: `number` - Rotation angle of axis label in degrees. Positive values rotate clockwise, negative values rotate counter-clockwise.
- title_arrow: `boolean` - Show/hide the arrow (→) on the axis title
- max_label_length: `number` - Maximum character length for axis labels. Labels exceeding this length will be truncated with an ellipsis. Defaults to 20 characters when labels are rotated.

</ResponseField>

<ResponseField name="legend" type="boolean" default="true">
  Show legend. Studio's built-in legend renders a compact color swatch + series name. For chart-wide style overrides that need the legend to reflect them precisely (line width, custom symbols, richer styling), set `legend=false` and provide `legend={ show=true ... }` inside `echarts_options` to use ECharts' native legend instead.
</ResponseField>

<ResponseField name="legend_location" type="string" default="top">
  Position of the legend (top or bottom)

**Allowed values:**
- `top`
- `bottom`
</ResponseField>

<ResponseField name="series_order" type="array">
  Array of series names to define the order of series in the chart and legend. Series not in the array will appear after the ordered ones.
</ResponseField>

<ResponseField name="chart_options" type="options group">
  Studio-shaped chart styling shortcuts (palette, series colors, zoom, padding). For raw ECharts overrides, use `echarts_options` instead.

**Example:**
```
chart_options={
  color_palette = ["#3b82f6", "#8b5cf6", "#ec4899"]
  series_colors = {
    "Series A" = "#3b82f6"
    "Series B" = "#10b981"
    "Series C" = "#f59e0b"
  }
  zoom = true
  top_padding = 0
}
```

**Attributes:**
- color_palette: `array of strings` - Array of hex color codes to use for series colors
- series_colors: `map of key-value pairs` - Map of series names to hex color codes for custom series coloring
- zoom: `boolean` - Enables zoom by dragging on the chart area
- top_padding: `number` - Additional padding (in px) above the chart area to prevent labels from being cut off

</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `dataZoom`, `visualMap`, `graphic`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For per-series overrides, use `echarts_series_options` or the per-series `echarts_options` on a `line`/`bar`/etc. child.

**Example:**
```
echarts_options={
    tooltip={ position="top" }
    dataZoom=[{ type="slider" }]
}
```
</ResponseField>

<ResponseField name="echarts_series_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into every data series in the chart. Use when the same override should apply to all series. Skips reference lines/areas/points. For a single series, set `echarts_options` on the series child instead.

**Example:**
```
echarts_series_options={
    itemStyle={ borderRadius=8 }
    markLine={ data=[{ type="average" }] }
}
```
</ResponseField>

<ResponseField name="y" type="string | array">
  Column name for y-axis
</ResponseField>

<ResponseField name="metric" type="string | array">
  Semantic metric name(s) to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes. Pass an array for multiple series (e.g. `metric=["revenue", "orders"]`).
</ResponseField>

<ResponseField name="fmt" type="string">
  Format for this series' values. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.
</ResponseField>

<ResponseField name="data_labels" type="options group">
  Label each point in the series with its value

**Example:**
```
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}
```

**Attributes:**
- position: `string` - Position the label relative to its data point
  - **Allowed values:**
    - `above`
    - `below`
    - `left`
    - `right`
    - `middle`
- fmt: `string` - Format the label value. Defaults to series or axis fmt.
  - **Allowed values:** See [Value Formatting](/core-concepts/value-formatting) for all available formats.
- size: `number` - Font size in px
- distance: `number` - How far the label is from the data point
- rotate: `number` - Rotate each label (degrees)
- color: `string` - Change the text color of the labels
- border_color: `string` - Change the border color surrounding text labels, defaults to chart background
- show_overlap: `boolean` - Show labels for every point even when they overlap

</ResponseField>

<ResponseField name="options" type="options group">
  

**Attributes:**
- color: `string`
- opacity: `number` - Between 0 and 1

</ResponseField>

<ResponseField name="stacked" type="boolean | string" default="true">
  Whether to stack the bars. Set to "100%" for percentage stacking where each bar shows its proportion of the total.
</ResponseField>

<ResponseField name="y2" type="string | array">
  Column name for secondary y-axis
</ResponseField>

<ResponseField name="bar_options" type="options group">
  

**Attributes:**
- color: `string`
- opacity: `number` - Between 0 and 1

</ResponseField>

## Allowed Children

- [reference_line](/components/reference_line)
- [reference_area](/components/reference_area)
- [reference_point](/components/reference_point)

---

### Components Benchmark Comparison (`docs/components/benchmark_comparison.mdx`)

---
title: Benchmark Comparison
description: Define a custom benchmark comparison option for a comparison_selector
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% benchmark_comparison 
    name="vs Franchisees" 
    agg="avg" 
    subject="store_id"
    where="ownership_type = 'franchise'"
/%}
````

## Examples

### Compare vs Franchisees

````liquid
{% benchmark_comparison 
    name="vs Franchisees" 
    agg="avg" 
    subject="store_id"
    where="ownership_type = 'franchise'"
/%}
````

### Compare vs Full Network

````liquid
{% benchmark_comparison 
    name="vs Full Network" 
    agg="avg" 
    subject="store_id"
/%}
````

### Compare vs Region Average

````liquid
{% benchmark_comparison 
    name="vs Region Avg" 
    agg="avg" 
    subject="store_id"
    within=["region"]
/%}
````

## Attributes

<ResponseField name="name" type="string" required>
  Display name shown in the dropdown (e.g., "vs Franchisees")
</ResponseField>

<ResponseField name="agg" type="string" required>
  Aggregation function to apply across benchmark entities. Options: avg, median, min, max, sum, count, count_distinct

**Allowed values:**
- `avg`
- `median`
- `min`
- `max`
- `sum`
- `count`
- `count_distinct`
</ResponseField>

<ResponseField name="subject" type="string" required>
  Column that defines individual entities (e.g., "store_id", "customer_id"). Required for benchmark calculations.
</ResponseField>

<ResponseField name="value" type="string">
  Optional column or expression to use for benchmark calculation. If not specified, uses the main value column. Useful if you have a pre-aggregated benchmark table for RLS reasons.
</ResponseField>

<ResponseField name="where" type="string">
  SQL WHERE clause to filter which entities are included in the benchmark (e.g., "ownership_type = 'franchise'")
</ResponseField>

<ResponseField name="within" type="array">
  Dimension columns to group the benchmark by (e.g., ["region"]). Leave empty for dataset-wide benchmark.
</ResponseField>

<ResponseField name="exclude_self" type="boolean" default="false">
  Exclude the current row from its own benchmark calculation (table context only). Default: false
</ResponseField>

<ResponseField name="display_type" type="string">
  Default display type for this comparison. Options: pct (percentage change), abs (absolute change), compared_value (benchmark value)

**Allowed values:**
- `pct`
- `abs`
- `compared_value`
</ResponseField>

<ResponseField name="text" type="string">
  Custom comparison label text (overrides default "vs {name}")
</ResponseField>

<ResponseField name="pct_fmt" type="string">
  Format code for percentage values. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="abs_fmt" type="string">
  Format code for absolute values. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="down_is_good" type="boolean">
  If true, negative changes are shown as positive (green). Defaults to the page's `down_is_good` setting.
</ResponseField>



## Allowed Parents

- [comparison_selector](/components/comparison_selector)

---

### Components Big Value (`docs/components/big_value.mdx`)

---
title: Big Value
description: Display a big value with optional comparison, delta, and sparkline
keywords: ["KPI","metric","big number","scorecard","headline number"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% big_value
  data="demo.daily_orders"
  value="sum(total_sales)"
  fmt="usd1m"
/%}
````

## Examples

### Basic Usage



````liquid
{% big_value
  data="demo.daily_orders"
  value="sum(total_sales)"
  fmt="usd1m"
/%}
````

### Comparison



````liquid
{% big_value
	data="demo.daily_orders"
	value="sum(total_sales)"
	fmt="usd1m"
	date_range={
		date="date"
		range="last 12 months"
	}
	comparison={
		compare_vs="prior year"
	}
/%}
````

### Sparkline



````liquid
{% big_value
	data="demo.daily_orders"
	value="sum(total_sales)"
	fmt="usd1m"
	sparkline={
		type="line"
		x="date"
	}
/%}
````

### Text Size



````liquid
{% big_value
	data="demo.daily_orders"
	value="sum(total_sales)"
	fmt="usd1m"
	text_size="4xl"
/%}
````

## Attributes

<ResponseField name="data" type="string">
  Table or view to query. Omit when using `metric`.
</ResponseField>

<ResponseField name="metric" type="string">
  Semantic metric to display (the whole reference — a metric is a single number). Use instead of `data` + `value`.
</ResponseField>

<ResponseField name="value" type="string">
  The SQL aggregation to display (with `data`). Omit when using `metric`.
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="comparison" type="options group">
  Comparison configuration object

**Example:**
```
comparison={
  compare_vs = "prior year"
  display_type = "compared_value"
  target = "string"
  benchmark = {
    agg = "avg"
    subject = "store_name"
    within = ["region"]
  }
  hide_pct = true
  pct_fmt = "string"
  abs_fmt = "string"
  text = "string"
  delta = true
  down_is_good = true
  neutral_range = []
}
```

**Attributes:**
- compare_vs: `string` - Type of comparison to perform. Options: prior year (same period last year), prior period (previous period of same duration), target (compare against a target value), benchmark (compare against group average/aggregate)
  - **Allowed values:**
    - `prior year`
    - `prior period`
    - `target`
    - `benchmark`
- display_type: `string` - What to display for comparison. Options: compared_value (comparison period value), abs (absolute change), pct (percentage change). Default: pct
  - **Allowed values:**
    - `compared_value`
    - `abs`
    - `pct`
- target: `string` - Target value for target comparison. Can be a column name, aggregation (e.g., "sum(target_sales)"), or literal value.
- benchmark: `options group`
  - **Options:**
    - agg: `string` - Aggregation function to apply across benchmark group. Options: avg (average), median, min, max, sum, count, count_distinct
      - **Allowed values:**
        - `avg`
        - `median`
        - `min`
        - `max`
        - `sum`
        - `count`
        - `count_distinct`
    - subject: `string` - Column or expression that defines individual entities in the benchmark (e.g., "store_name", "customer_id"). Required for single-value components.
    - value: `string` - Optional column or expression to use for benchmark calculation. If not specified, uses the main value column. Useful if you have a pre-aggregated benchmark table for RLS reasons.
    - within: `array of strings` - Dimension columns to group the benchmark by (e.g., ["region"]). Leave empty for dataset-wide benchmark.
    - where: `string` - SQL WHERE clause to filter which entities are included in the benchmark
    - exclude_self: `boolean` - Exclude the current row from its own benchmark calculation (table context only). Default: false
- hide_pct: `boolean` - Hide the percentage change line in comparison tooltips
- pct_fmt: `string` - Format code for percentage values in comparison tooltips
- abs_fmt: `string` - Format code for absolute values in comparison tooltips
- text: `string` - Text displayed after the comparison value
- delta: `boolean` - Whether to display the comparison as a delta
- down_is_good: `boolean` - Whether a decrease is considered positive. Defaults to the page's `down_is_good` setting.
- neutral_range: `array` - Range [min, max] for neutral values. Use null for infinity (e.g., [null, 0] means anything ≤ 0 is neutral)

</ResponseField>

<ResponseField name="sparkline" type="options group">
  Sparkline configuration object

**Example:**
```
sparkline={
  type = "line"
  color = "string"
  x = "string"
  y_fmt = "string"
  x_fmt = "string"
  fit_to_data = true
  connect_group = "string"
  date_grain = "year"
  date_range = {
    range = "today"
    date = "string"
  }
}
```

**Attributes:**
- type: `string` - The type of sparkline to display
  - **Allowed values:**
    - `line`
    - `area`
    - `bar`
- color: `string` - Color for the sparkline
- x: `string` - X column for the sparkline
- y_fmt: `string` - Value format for the sparkline tooltips
- x_fmt: `string` - Date format for the sparkline tooltips
- fit_to_data: `boolean` - Whether to fit the Y axis scale to the data range
- connect_group: `string` - Connect group for the sparkline
- date_grain: `string` - Time grain for the sparkline data points
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
    - `minute`
- date_range: `options group`
  - **Options:**
    - range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
      - **Allowed values:**
        - `today`
        - `yesterday`
        - `last 7 days`
        - `last 30 days`
        - `last 3 months`
        - `last 6 months`
        - `last 12 months`
        - `previous week`
        - `previous month`
        - `previous quarter`
        - `previous year`
        - `this week`
        - `this month`
        - `this quarter`
        - `this year`
        - `next week`
        - `next month`
        - `next quarter`
        - `next year`
        - `week to date`
        - `month to date`
        - `quarter to date`
        - `year to date`
        - `all time`
    - date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="fmt" type="string">
  Format for the main value. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="title" type="string">
  Title for the main value
</ResponseField>

<ResponseField name="max_width" type="string" default="fit-content">
  Maximum width of the component
</ResponseField>

<ResponseField name="min_width" type="string" default="auto">
  Minimum width of the component
</ResponseField>

<ResponseField name="text_size" type="string">
  Text size for the value. Options: sm, base, lg, xl (default), 2xl, 3xl, 4xl, 5xl

**Allowed values:**
- `sm`
- `base`
- `lg`
- `xl`
- `2xl`
- `3xl`
- `4xl`
- `5xl`
</ResponseField>

<ResponseField name="title_class" type="string">
  Additional CSS classes for the title
</ResponseField>

<ResponseField name="value_class" type="string">
  Additional CSS classes for the value
</ResponseField>

<ResponseField name="link" type="string">
  URL to link the title to
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="class_name" type="string">
  Additional CSS classes for the component
</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

---

### Components Bubble (`docs/components/bubble.mdx`)

---
title: Bubble
description: Add a bubble series to a [combo_chart](/components/combo_chart)
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bubble
        y="avg(avg_transaction_value)"
        size="sum(transactions)"
    /%}
{% /combo_chart %}
````

## Examples

### Basic Bubble Series

````liquid
{% combo_chart data="demo.daily_orders" x="date" date_grain="month" %}
    {% bubble
        y="avg(avg_transaction_value)"
        size="sum(transactions)"
    /%}
{% /combo_chart %}
````

## Attributes

<ResponseField name="y" type="string">
  Column name for y-axis. Aggregated at the parent combo_chart's `x=`. Omit when using `metric`.
</ResponseField>

<ResponseField name="metric" type="string">
  Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes.
</ResponseField>

<ResponseField name="series" type="string">
  Column name for series grouping
</ResponseField>

<ResponseField name="axis" type="string" default="y1">
  The axis to render the series on

**Allowed values:**
- `y1`
- `y2`
</ResponseField>

<ResponseField name="fmt" type="string">
  Format for this series' values. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.
</ResponseField>

<ResponseField name="data_labels" type="options group">
  Label each point in the series with its value

**Example:**
```
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}
```

**Attributes:**
- position: `string` - Position the label relative to its data point
  - **Allowed values:**
    - `above`
    - `below`
    - `left`
    - `right`
    - `middle`
- fmt: `string` - Format the label value. Defaults to series or axis fmt.
  - **Allowed values:** See [Value Formatting](/core-concepts/value-formatting) for all available formats.
- size: `number` - Font size in px
- distance: `number` - How far the label is from the data point
- rotate: `number` - Rotate each label (degrees)
- color: `string` - Change the text color of the labels
- border_color: `string` - Change the border color surrounding text labels, defaults to chart background
- show_overlap: `boolean` - Show labels for every point even when they overlap

</ResponseField>

<ResponseField name="opacity" type="number" default="0.7">
  The opacity of the series
</ResponseField>

<ResponseField name="size" type="string" required>
  Column to use for the size of the bubbles
</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into this series only. For overrides that apply to every series on the chart, set `echarts_series_options` on the parent chart instead.

**Example:**
```
echarts_options={
    endLabel={ show=true }
    markPoint={ data=[{ type="max" }, { type="min" }] }
}
```
</ResponseField>



## Allowed Parents

- [combo_chart](/components/combo_chart)

---

### Components Bubble Chart (`docs/components/bubble_chart.mdx`)

---
title: Bubble Chart
description: Display a bubble chart
keywords: ["bubble plot","bubble graph"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% bubble_chart
    data="demo.daily_orders"
    x="sum(total_sales)"
    y="avg(avg_transaction_value)"
    size="sum(transactions)"
    series="category"
/%}
````

## Examples

### Basic Usage



````liquid
{% bubble_chart
    data="demo.daily_orders"
    x="sum(total_sales)"
    y="avg(avg_transaction_value)"
    size="sum(transactions)"
    series="category"
/%}
````

### Bubble Chart with Formatting



````liquid
{% bubble_chart
    data="demo.daily_orders"
    x="sum(total_sales)"
    y="avg(avg_transaction_value)"
    size="sum(transactions)"
    x_fmt="usd"
    y_fmt="usd"
    title="Sales Performance Analysis"
    subtitle="Bubble size represents transaction count"
    series="category"
/%}
````

### Bubble Chart with Point Titles



````liquid
{% bubble_chart
    data="demo.daily_orders"
    x="sum(total_sales)"
    y="avg(avg_transaction_value)"
    size="sum(transactions)"
    point_title="category"
    x_fmt="usd"
    y_fmt="usd"
/%}
````

## Attributes

<ResponseField name="data" type="string" required>
  Name of the table to query. Required unless every child series uses `metric="..."` — metric children resolve their own base from the metric view.
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="date_grain" type="string">
  Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

**Allowed values:**
- `day`
- `week`
- `month`
- `quarter`
- `year`
- `hour`
- `day of week`
- `day of month`
- `day of year`
- `week of year`
- `month of year`
- `quarter of year`
</ResponseField>

<ResponseField name="handle_missing" type="string" default="connect">
  How to handle missing data points. "connect" auto-connects points (default), "gaps" shows visual breaks, "zero" fills with zeros.

**Allowed values:**
- `connect`
- `gaps`
- `zero`
</ResponseField>

<ResponseField name="x" type="string" required>
  Column name for x-axis. Required unless every child series uses `metric="..."` — metric children fall back to the metric view's time column.
</ResponseField>

<ResponseField name="x_fmt" type="string">
  Format for x values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="y_fmt" type="string">
  Format for y values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="y2_fmt" type="string">
  Format for y2 values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="series" type="string">
  Column name for series grouping (applies to all series)
</ResponseField>

<ResponseField name="point_title" type="string">
  Column name for individual point labels displayed at the top of the tooltip
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the component
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text (can only be used with title). Displays an info icon next to the title.
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>

<ResponseField name="x_sort" type="string">
  Sort order for x-axis categories. Options: `asc` (alphabetical), `desc` (reverse alphabetical), `data` (preserve query order), or an array for custom order like `["A", "B", "C"]`

**Allowed values:**
- `asc`
- `desc`
- `data`
</ResponseField>

<ResponseField name="y_axis_options" type="options group">
  Configure the y-axis

**Example:**
```
y_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}
```

**Attributes:**
- title: `string`
- title_position: `string` - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
  - **Allowed values:**
    - `top`
    - `side`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.

</ResponseField>

<ResponseField name="y2_axis_options" type="options group">
  Configure the secondary y-axis

**Example:**
```
y2_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}
```

**Attributes:**
- title: `string`
- title_position: `string` - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
  - **Allowed values:**
    - `top`
    - `side`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.

</ResponseField>

<ResponseField name="x_axis_options" type="options group">
  Configure the x-axis

**Example:**
```
x_axis_options={
  title = "string"
  show_title = true
  label_wrap = true
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  min_interval = "year"
  max_interval = "year"
  interval = 0
  label_rotate = 0
  title_arrow = true
  max_label_length = 0
}
```

**Attributes:**
- title: `string`
- show_title: `boolean` - When `true`, renders the auto-derived axis title (the x column name) below the chart. Ignored when `title` is set explicitly. Defaults to `false` — auto-derived column-name titles usually read as visual noise and the axis labels speak for themselves.
- label_wrap: `boolean`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0. Defaults to true for numeric x-axes, false otherwise.
- min_interval: `string` - Minimum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
- max_interval: `string` - Maximum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
- label_rotate: `number` - Rotation angle of axis label in degrees. Positive values rotate clockwise, negative values rotate counter-clockwise.
- title_arrow: `boolean` - Show/hide the arrow (→) on the axis title
- max_label_length: `number` - Maximum character length for axis labels. Labels exceeding this length will be truncated with an ellipsis. Defaults to 20 characters when labels are rotated.

</ResponseField>

<ResponseField name="legend" type="boolean" default="true">
  Show legend. Studio's built-in legend renders a compact color swatch + series name. For chart-wide style overrides that need the legend to reflect them precisely (line width, custom symbols, richer styling), set `legend=false` and provide `legend={ show=true ... }` inside `echarts_options` to use ECharts' native legend instead.
</ResponseField>

<ResponseField name="legend_location" type="string" default="top">
  Position of the legend (top or bottom)

**Allowed values:**
- `top`
- `bottom`
</ResponseField>

<ResponseField name="series_order" type="array">
  Array of series names to define the order of series in the chart and legend. Series not in the array will appear after the ordered ones.
</ResponseField>

<ResponseField name="chart_options" type="options group">
  Studio-shaped chart styling shortcuts (palette, series colors, zoom, padding). For raw ECharts overrides, use `echarts_options` instead.

**Example:**
```
chart_options={
  color_palette = ["#3b82f6", "#8b5cf6", "#ec4899"]
  series_colors = {
    "Series A" = "#3b82f6"
    "Series B" = "#10b981"
    "Series C" = "#f59e0b"
  }
  zoom = true
  top_padding = 0
}
```

**Attributes:**
- color_palette: `array of strings` - Array of hex color codes to use for series colors
- series_colors: `map of key-value pairs` - Map of series names to hex color codes for custom series coloring
- zoom: `boolean` - Enables zoom by dragging on the chart area
- top_padding: `number` - Additional padding (in px) above the chart area to prevent labels from being cut off

</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `dataZoom`, `visualMap`, `graphic`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For per-series overrides, use `echarts_series_options` or the per-series `echarts_options` on a `line`/`bar`/etc. child.

**Example:**
```
echarts_options={
    tooltip={ position="top" }
    dataZoom=[{ type="slider" }]
}
```
</ResponseField>

<ResponseField name="echarts_series_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into every data series in the chart. Use when the same override should apply to all series. Skips reference lines/areas/points. For a single series, set `echarts_options` on the series child instead.

**Example:**
```
echarts_series_options={
    itemStyle={ borderRadius=8 }
    markLine={ data=[{ type="average" }] }
}
```
</ResponseField>

<ResponseField name="y" type="string | array" required>
  Column name for y-axis
</ResponseField>

<ResponseField name="metric" type="string">
  Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes.
</ResponseField>

<ResponseField name="fmt" type="string">
  Format for this series' values. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.
</ResponseField>

<ResponseField name="data_labels" type="options group">
  Label each point in the series with its value

**Example:**
```
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}
```

**Attributes:**
- position: `string` - Position the label relative to its data point
  - **Allowed values:**
    - `above`
    - `below`
    - `left`
    - `right`
    - `middle`
- fmt: `string` - Format the label value. Defaults to series or axis fmt.
  - **Allowed values:** See [Value Formatting](/core-concepts/value-formatting) for all available formats.
- size: `number` - Font size in px
- distance: `number` - How far the label is from the data point
- rotate: `number` - Rotate each label (degrees)
- color: `string` - Change the text color of the labels
- border_color: `string` - Change the border color surrounding text labels, defaults to chart background
- show_overlap: `boolean` - Show labels for every point even when they overlap

</ResponseField>

<ResponseField name="opacity" type="number" default="0.7">
  The opacity of the series
</ResponseField>

<ResponseField name="size" type="string" required>
  Column to use for the size of the bubbles
</ResponseField>

<ResponseField name="y2" type="string | array">
  Column name for secondary y-axis
</ResponseField>

<ResponseField name="size_fmt" type="string">
  Format for size values in tooltips. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

## Allowed Children

- [reference_line](/components/reference_line)
- [reference_area](/components/reference_area)
- [reference_point](/components/reference_point)

---

### Components Button Group (`docs/components/button_group.mdx`)

---
title: Button Group
description: Display a segmented button group with distinct values from a database column to use in filters
keywords: ["radio buttons","segmented control","chip selector"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% button_group
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    filters=["category_filter"]
    date_grain="month"
/%}
````

## Examples

### Using `filters`



````liquid
{% button_group
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    filters=["category_filter"]
    date_grain="month"
/%}
````

### Using `where`



````liquid
{% button_group
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    where="category = {{category_filter}}"
    date_grain="month"
/%}
````

### Using Inline SQL

````liquid
{% button_group
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

```sql filtered_orders
select * from demo.daily_orders
where category = {{category_filter}}
```

{% table data="filtered_orders" /%}
````

### Vertical orientation inside a row



````liquid
{% row %}

{% button_group
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
    orientation="vertical"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    filters=["category_filter"]
    date_grain="month"
/%}

{% /row %}
````

## Attributes

<ResponseField name="id" type="string" required>
  The id of the button group to be used in a `filters` prop
</ResponseField>

<ResponseField name="data" type="string">
  Name of the table to query
</ResponseField>

<ResponseField name="filters" type="array">
  Array of filter IDs to apply when querying for options
</ResponseField>

<ResponseField name="value_column" type="string">
  Column name to use as the value for each option, and the column to filter by when this button group's `id` is used in the `filters` prop of a chart
</ResponseField>

<ResponseField name="label_column" type="string">
  Column name to use as the label for each option
</ResponseField>

<ResponseField name="title" type="string">
  Text displayed above the button group
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text
</ResponseField>

<ResponseField name="initial_value" type="string | number | array">
  Initial selected value(s)
</ResponseField>

<ResponseField name="multiple" type="boolean" default="false">
  Allows multiple selections
</ResponseField>

<ResponseField name="select_first" type="boolean" default="false">
  Automatically select the first option when the component loads
</ResponseField>

<ResponseField name="orientation" type="string" default="horizontal">
  Layout direction of the button group. Use "vertical" to stack buttons in a column. Best paired with a sibling element inside a `row` so the stack sits alongside its target content.

**Allowed values:**
- `horizontal`
- `vertical`
</ResponseField>

<ResponseField name="max_height" type="number">
  Maximum height in pixels for the button stack when `orientation="vertical"`. Buttons scroll if the list overflows. Ignored when horizontal.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

## Using the Filter Variable

Reference this filter using `{{filter_id}}`. The value returned depends on where you use it.

The examples below show values for three scenarios:
- **No selection**
- **Single select:** "Electronics" selected
- **Multi select:** "Sports" and "Home" selected (when `multiple=true`)

| Context | Default Property | No Selection | Single Select | Multi Select |
|---------|-----------------|--------------|---------------|-------------|
| Inline SQL query | `.selected` | `''` | `'Electronics'` | `('Sports', 'Home')` |
| `where` attribute | `.selected` | `''` | `'Electronics'` | `('Sports', 'Home')` |
| Text / Markdown | `.literal` |  | `Electronics` | `Sports, Home` |

### Available Properties

You can also access specific properties using `{{filter_id.property}}`:

#### .filter
Returns a complete SQL filter expression ready to use in WHERE clauses. Returns `true` when no value is selected.

````liquid
{% button_group id="category_filter" data="products" value_column="category" /%}

```sql filtered_products
select * from products
where {{category_filter.filter}}
```
````

| No Selection | Single Select | Multi Select |
|--------------|---------------|-------------|
| `true` | `category = 'Electronics'` | `category IN ('Sports', 'Home')` |

#### .selected
Returns the selected value(s) wrapped in quotes, suitable for SQL comparisons. Returns an empty string when no value is selected.

````liquid
{% button_group id="category_filter" data="products" value_column="category" /%}

```sql products_by_category
select * from products
where category = {{category_filter.selected}}
```
````

| No Selection | Single Select | Multi Select |
|--------------|---------------|-------------|
| `''` | `'Electronics'` | `('Sports', 'Home')` |

#### .literal
Returns the raw unescaped selected value(s), useful for display in text or dynamic column selection.

````liquid
{% button_group id="sort_column" data="products" value_column="column_name" /%}

```sql dynamic_sort
select * from products
order by {{sort_column.literal}}
```
````

| No Selection | Single Select | Multi Select |
|--------------|---------------|-------------|
| `` | `Electronics` | `Sports, Home` |

#### .label
Returns the display label for the selected option(s). Falls back to the value if no label is defined.

````liquid
{% button_group id="category_filter" %}
    {% option value="Electronics" label="Electronics" /%}
    {% option value="Sports" label="Sports" /%}
    {% option value="Home" label="Home" /%}
{% /button_group %}

Selected: {{category_filter.label}}
````

| No Selection | Single Select | Multi Select |
|--------------|---------------|-------------|
| `` | `Electronics` | `Sports, Home` |

#### .fmt
Returns the format string associated with the selected option. For multiple selections, returns the first format.

````liquid
{% button_group id="metric_selector" %}
    {% option value="revenue" label="Revenue" fmt="usd" /%}
    {% option value="growth_rate" label="Growth Rate" fmt="pct1" /%}
{% /button_group %}

{% big_value data={metrics} value=value fmt={{metric_selector.fmt}} /%}
````

| No Selection | Single Select | Multi Select |
|--------------|---------------|-------------|
| `` | `usd` | `usd` |


## Allowed Children

- [option](/components/option)

---

### Components Calendar Heatmap (`docs/components/calendar_heatmap.mdx`)

---
title: Calendar Heatmap
description: Display a calendar heatmap visualization
keywords: ["calendar chart","activity chart","contribution graph"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% calendar_heatmap
    data="demo.daily_orders"
    date="date"
    value="sum(total_sales)"
/%}
````

## Examples

### Basic Usage



````liquid
{% calendar_heatmap
    data="demo.daily_orders"
    date="date"
    value="sum(total_sales)"
/%}
````

### Calendar Heatmap with Custom Colors



````liquid
{% calendar_heatmap
    data="demo.daily_orders"
    date="date"
    value="sum(total_sales)"
    title="Daily Sales Heatmap"
    chart_options={
        color_scale = ["#0d0887", "#6300a7", "#a62098", "#d5546e", "#f68d45", "#fcd225", "#f0f921"]
    }
/%}
````

### Calendar Heatmap with Conditional Colors



````liquid
{% calendar_heatmap
    data="demo.daily_orders"
    date="date"
    value="sum(total_sales)"
    title="Sales Performance Heatmap"
    chart_options={
        conditional_colors = "case when sum(total_sales) > 65000 then '#22c55e' when sum(total_sales) > 40000 then '#f59e0b' else '#ef4444' end"
    }
/%}
````

### Calendar Heatmap with Conditional Colors and Legend



````liquid
{% calendar_heatmap
    data="demo.daily_orders"
    date="date"
    value="sum(total_sales)"
    title="Sales Performance Heatmap"
    chart_options={
        conditional_colors="case when sum(total_sales) > 65000 then '#22c55e' when sum(total_sales) > 40000 then '#f59e0b' else '#ef4444' end"
        color_map={
            "#22c55e"="High Sales"
            "#f59e0b"="Medium Sales"
            "#ef4444"="Low Sales"
        }
    }
/%}
````

## Attributes

<ResponseField name="data" type="string">
  Name of the table to query. Omit when using `metric`.
</ResponseField>

<ResponseField name="metric" type="string">
  Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes.
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="date" type="string" required>
  Column name for dates
</ResponseField>

<ResponseField name="value" type="string">
  Column name for cell values. Omit when using `metric`.
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the chart
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text (can only be used with title)
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="value_fmt" type="string">
  Format for values (defaults to `num`, or the metric format in metric mode). See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="legend" type="boolean" default="true">
  Show color scale legend
</ResponseField>

<ResponseField name="borders" type="boolean" default="true">
  Show borders between calendar cells
</ResponseField>

<ResponseField name="chart_options" type="options group">
  Color and styling options for the heatmap

**Example:**
```
chart_options={
  color_scale = ["value1", "value2"]
  color_palette = ["value1", "value2"]
  conditional_colors = "string"
  color_map = {
    "key1" = "value1"
    "key2" = "value2"
  }
}
```

**Attributes:**
- color_scale: `array of strings` - Array of hex colors for the heatmap gradient. A single-color array auto-expands to [background, color].
- color_palette: `array of strings` - Deprecated. Use `color_scale`.
- conditional_colors: `string` - SQL CASE expression returning hex colors based on value
- color_map: `map of key-value pairs` - Maps hex colors to legend labels when using conditional_colors

</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.
</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `graphic`, `visualMap`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For overrides scoped to the data series, use `echarts_series_options`.

**Example:**
```
echarts_options={
    tooltip={ position="top" }
    graphic=[{ type="text" }]
}
```
</ResponseField>

<ResponseField name="echarts_series_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into the chart series. Use for series-level styling the structured props do not expose.

**Example:**
```
echarts_series_options={
    itemStyle={ borderRadius=8 }
}
```
</ResponseField>

---

### Components Callout (`docs/components/callout.mdx`)

---
title: Callout
description: Add a callout box to show a message or highlight a section of text
keywords: ["alert","banner","notice","admonition"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% callout type="info" title="Report Info"%}
This is an info callout
{% /callout %}
````

## Examples

### Basic Usage



````liquid
{% callout type="info" title="Report Info"%}
This is an info callout
{% /callout %}
````

## Attributes

<ResponseField name="type" type="string" default="info">
  

**Allowed values:**
- `info`
- `success`
- `warning`
- `error`
</ResponseField>

<ResponseField name="title" type="string" default="">
  
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

---

### Components Candlestick (`docs/components/candlestick.mdx`)

---
title: Candlestick
description: Display a candlestick chart for OHLC (Open, High, Low, Close) financial data visualization
keywords: ["ohlc","stock chart","financial chart"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
```sql stock_prices
SELECT '2024-01-01'::date as date, 100.0 as open, 105.0 as high, 95.0 as low, 102.0 as close
UNION ALL SELECT '2024-01-02'::date, 102.0, 108.0, 100.0, 105.0
UNION ALL SELECT '2024-01-03'::date, 105.0, 110.0, 103.0, 108.0
UNION ALL SELECT '2024-01-04'::date, 108.0, 112.0, 106.0, 104.0
UNION ALL SELECT '2024-01-05'::date, 104.0, 107.0, 98.0, 100.0
```

{% candlestick
    data="stock_prices"
    x="date"
    open="open"
    high="high"
    low="low"
    close="close"
    y_axis_options={
        min=90
        max=115
    }
/%}
````

## Examples

### Basic Usage



````liquid
```sql stock_prices
SELECT '2024-01-01'::date as date, 100.0 as open, 105.0 as high, 95.0 as low, 102.0 as close
UNION ALL SELECT '2024-01-02'::date, 102.0, 108.0, 100.0, 105.0
UNION ALL SELECT '2024-01-03'::date, 105.0, 110.0, 103.0, 108.0
UNION ALL SELECT '2024-01-04'::date, 108.0, 112.0, 106.0, 104.0
UNION ALL SELECT '2024-01-05'::date, 104.0, 107.0, 98.0, 100.0
```

{% candlestick
    data="stock_prices"
    x="date"
    open="open"
    high="high"
    low="low"
    close="close"
    y_axis_options={
        min=90
        max=115
    }
/%}
````

### With Volume



````liquid
```sql stock_prices
SELECT '2024-01-01'::date as date, 100.0 as open, 105.0 as high, 95.0 as low, 102.0 as close, 1500000 as volume
UNION ALL SELECT '2024-01-02'::date, 102.0, 108.0, 100.0, 105.0, 2100000
UNION ALL SELECT '2024-01-03'::date, 105.0, 110.0, 103.0, 108.0, 1800000
UNION ALL SELECT '2024-01-04'::date, 108.0, 112.0, 106.0, 104.0, 2500000
UNION ALL SELECT '2024-01-05'::date, 104.0, 107.0, 98.0, 100.0, 3200000
```

{% candlestick
    data="stock_prices"
    x="date"
    open="open"
    high="high"
    low="low"
    close="close"
    volume="volume"
    y2_fmt="num0"
    title="Stock Price with Volume"
    y_axis_options={
        min=90
        max=115
    }
/%}
````

### With Custom Colors



````liquid
```sql stock_prices
SELECT '2024-01-01'::date as date, 100.0 as open, 105.0 as high, 95.0 as low, 102.0 as close
UNION ALL SELECT '2024-01-02'::date, 102.0, 108.0, 100.0, 105.0
UNION ALL SELECT '2024-01-03'::date, 105.0, 110.0, 103.0, 108.0
UNION ALL SELECT '2024-01-04'::date, 108.0, 112.0, 106.0, 104.0
UNION ALL SELECT '2024-01-05'::date, 104.0, 107.0, 98.0, 100.0
```

{% candlestick
    data="stock_prices"
    x="date"
    open="open"
    high="high"
    low="low"
    close="close"
    chart_options={
        up_color="#22c55e"
        down_color="#ef4444"
    }
    y_axis_options={
        min=90
        max=115
    }
/%}
````

## Attributes

<ResponseField name="data" type="string" required>
  Name of the table or view to query
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="date_grain" type="string">
  Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

**Allowed values:**
- `day`
- `week`
- `month`
- `quarter`
- `year`
- `hour`
- `day of week`
- `day of month`
- `day of year`
- `week of year`
- `month of year`
- `quarter of year`
</ResponseField>

<ResponseField name="x" type="string" required>
  Column for x-axis (typically date/time)
</ResponseField>

<ResponseField name="open" type="string" required>
  Column for opening price
</ResponseField>

<ResponseField name="high" type="string" required>
  Column for high price
</ResponseField>

<ResponseField name="low" type="string" required>
  Column for low price
</ResponseField>

<ResponseField name="close" type="string" required>
  Column for closing price
</ResponseField>

<ResponseField name="volume" type="string">
  Column for trading volume (displayed as bars on secondary y-axis)
</ResponseField>

<ResponseField name="x_fmt" type="string">
  Format for x-axis values and labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="y_fmt" type="string">
  Format for y-axis values and labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="y2_fmt" type="string">
  Format for secondary y-axis (volume) values. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the component
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text (can only be used with title). Displays an info icon next to the title.
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="y_axis_options" type="options group">
  Configure the y-axis

**Example:**
```
y_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}
```

**Attributes:**
- title: `string`
- title_position: `string` - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
  - **Allowed values:**
    - `top`
    - `side`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.

</ResponseField>

<ResponseField name="x_axis_options" type="options group">
  Configure the x-axis

**Example:**
```
x_axis_options={
  title = "string"
  show_title = true
  label_wrap = true
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  min_interval = "year"
  max_interval = "year"
  interval = 0
  label_rotate = 0
  title_arrow = true
  max_label_length = 0
}
```

**Attributes:**
- title: `string`
- show_title: `boolean` - When `true`, renders the auto-derived axis title (the x column name) below the chart. Ignored when `title` is set explicitly. Defaults to `false` — auto-derived column-name titles usually read as visual noise and the axis labels speak for themselves.
- label_wrap: `boolean`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0. Defaults to true for numeric x-axes, false otherwise.
- min_interval: `string` - Minimum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
- max_interval: `string` - Maximum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
- label_rotate: `number` - Rotation angle of axis label in degrees. Positive values rotate clockwise, negative values rotate counter-clockwise.
- title_arrow: `boolean` - Show/hide the arrow (→) on the axis title
- max_label_length: `number` - Maximum character length for axis labels. Labels exceeding this length will be truncated with an ellipsis. Defaults to 20 characters when labels are rotated.

</ResponseField>

<ResponseField name="chart_options" type="options group">
  Candlestick chart configuration options

**Attributes:**
- up_color: `string` - Color for bullish (up) candles
- down_color: `string` - Color for bearish (down) candles
- zoom: `boolean` - Enables zoom by dragging on the chart area

</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.
</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `graphic`, `visualMap`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For overrides scoped to the data series, use `echarts_series_options`.

**Example:**
```
echarts_options={
    tooltip={ position="top" }
    graphic=[{ type="text" }]
}
```
</ResponseField>

---

### Components Chord Chart (`docs/components/chord_chart.mdx`)

---
title: Chord Chart
description: Display a chord diagram showing flows between nodes around a circle
keywords: ["chord diagram","circular flow","relationship diagram"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% chord_chart
    data="demo.order_details"
    source="category"
    target="item_name"
    value="sum(quantity)"
/%}
````

## Examples

### Basic Usage

````liquid
{% chord_chart
    data="demo.order_details"
    source="category"
    target="item_name"
    value="sum(quantity)"
/%}
````

### Chord Chart with Custom Colors

````liquid
{% chord_chart
    data="demo.order_details"
    source="category"
    target="item_name"
    value="sum(quantity)"
    title="Category to Item Flow"
    chart_options={
        color_palette = ["#0d0887", "#6300a7", "#a62098", "#d5546e", "#f68d45", "#fcd225", "#f0f921"]
    }
/%}
````

### Chord Chart with Raw ECharts Overrides

````liquid
{% chord_chart
    data="demo.order_details"
    source="category"
    target="item_name"
    value="sum(quantity)"
    echarts_options={
        series=[{ startAngle=0 padAngle=6 }]
    }
    echarts_series_options={
        itemStyle={ borderRadius=6 }
    }
/%}
````

## Attributes

<ResponseField name="data" type="string">
  Name of the table or view to query. Omit when using `metric`.
</ResponseField>

<ResponseField name="metric" type="string">
  Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes.
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="source" type="string" required>
  Column name for source nodes
</ResponseField>

<ResponseField name="target" type="string" required>
  Column name for target nodes
</ResponseField>

<ResponseField name="value" type="string">
  Column name for flow values (chord thickness). Omit when using `metric`.
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the component
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text (can only be used with title). Displays an info icon next to the title.
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="value_fmt" type="string">
  Format for values (defaults to `num`, or the metric format in metric mode). See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="labels" type="boolean" default="true">
  Show node labels around the circle
</ResponseField>

<ResponseField name="chart_options" type="options group">
  Chart configuration options

**Example:**
```
chart_options={
  color_palette = ["value1", "value2"]
  series_colors = {
    "key1" = "value1"
    "key2" = "value2"
  }
}
```

**Attributes:**
- color_palette: `array of strings`
- series_colors: `map of key-value pairs`

</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `graphic`, `visualMap`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For overrides scoped to the data series, use `echarts_series_options`.

**Example:**
```
echarts_options={
    tooltip={ position="top" }
    graphic=[{ type="text" }]
}
```
</ResponseField>

<ResponseField name="echarts_series_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into the chart series. Use for series-level styling the structured props do not expose.

**Example:**
```
echarts_series_options={
    itemStyle={ borderRadius=8 }
}
```
</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.
</ResponseField>

---

### Components Clock (`docs/components/clock.mdx`)

---
title: Clock
description: Display a live clock with running seconds and the current date
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% clock /%}
````

## Examples

### Default Clock (12h)

````liquid
{% clock /%}
````

### 24-Hour Clock

````liquid
{% clock format="24h" /%}
````

## Attributes

<ResponseField name="format" type="string" default="12h">
  Time format: 12-hour or 24-hour

**Allowed values:**
- `12h`
- `24h`
</ResponseField>

<ResponseField name="variant" type="string" default="sans">
  Font variant: sans-serif or monospace

**Allowed values:**
- `sans`
- `mono`
</ResponseField>

<ResponseField name="align" type="string" default="left">
  Text alignment

**Allowed values:**
- `left`
- `right`
</ResponseField>

---

### Components Combo Chart (`docs/components/combo_chart.mdx`)

---
title: Combo Chart
description: Display a chart with a combination of multiple series types. Accepts area, bar, bubble, line, and scatter children series.
keywords: ["mixed chart","combination chart","dual axis"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% combo_chart
    data="demo.daily_orders"
    x="date"
    date_grain="month"
%}
    {% line
        y="sum(total_sales)"
    /%}
    {% bar
        y="sum(transactions)"
        axis="y2"
    /%}
{% /combo_chart %}
````

## Examples

### Basic Usage



````liquid
{% combo_chart
    data="demo.daily_orders"
    x="date"
    date_grain="month"
%}
    {% line
        y="sum(total_sales)"
    /%}
    {% bar
        y="sum(transactions)"
        axis="y2"
    /%}
{% /combo_chart %}
````

### Combo Chart with Area and Line



````liquid
{% combo_chart
    data="demo.daily_orders"
    x="date"
    date_grain="month"
%}
    {% area
        y="sum(total_sales)"
    /%}
    {% line
        y="avg(avg_transaction_value)"
        axis="y2"
    /%}
{% /combo_chart %}
````

### Combo Chart with Formatting



````liquid
{% combo_chart
    data="demo.daily_orders"
    x="date"
    y_fmt="usd"
    y2_fmt="num0"
    title="Sales and Transactions Overview"
    subtitle="Combined view of sales and transaction volume"
    date_grain="month"
%}
    {% line
        y="sum(total_sales)"
    /%}
    {% bar
        y="sum(transactions)"
        axis="y2"
    /%}
{% /combo_chart %}
````

### Raw ECharts overrides



````liquid
{% combo_chart
    data="demo.daily_orders"
    x="date"
    date_grain="month"
    echarts_options={
        dataZoom=[{ type="slider" }]
        tooltip={ position="top" }
    }
    echarts_series_options={
        itemStyle={ borderRadius=4 }
    }
%}
    {% bar y="sum(total_sales)" /%}
{% /combo_chart %}
````

## Attributes

<ResponseField name="data" type="string">
  Name of the table to query. Required unless every child series uses `metric="..."` — metric children resolve their own base from the metric view.
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="date_grain" type="string">
  Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

**Allowed values:**
- `day`
- `week`
- `month`
- `quarter`
- `year`
- `hour`
- `day of week`
- `day of month`
- `day of year`
- `week of year`
- `month of year`
- `quarter of year`
</ResponseField>

<ResponseField name="handle_missing" type="string" default="connect">
  How to handle missing data points. "connect" auto-connects points (default), "gaps" shows visual breaks, "zero" fills with zeros.

**Allowed values:**
- `connect`
- `gaps`
- `zero`
</ResponseField>

<ResponseField name="x" type="string">
  Column name for x-axis. Required unless every child series uses `metric="..."` — metric children fall back to the metric view's time column.
</ResponseField>

<ResponseField name="x_fmt" type="string">
  Format for x values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="y_fmt" type="string">
  Format for y values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="y2_fmt" type="string">
  Format for y2 values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="series" type="string">
  Column name for series
</ResponseField>

<ResponseField name="point_title" type="string">
  Column name for individual point labels displayed at the top of the tooltip
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the component
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text (can only be used with title). Displays an info icon next to the title.
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>

<ResponseField name="x_sort" type="string">
  Sort order for x-axis categories. Options: `asc` (alphabetical), `desc` (reverse alphabetical), `data` (preserve query order), or an array for custom order like `["A", "B", "C"]`

**Allowed values:**
- `asc`
- `desc`
- `data`
</ResponseField>

<ResponseField name="y_axis_options" type="options group">
  Configure the y-axis

**Example:**
```
y_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}
```

**Attributes:**
- title: `string`
- title_position: `string` - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
  - **Allowed values:**
    - `top`
    - `side`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.

</ResponseField>

<ResponseField name="y2_axis_options" type="options group">
  Configure the secondary y-axis

**Example:**
```
y2_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}
```

**Attributes:**
- title: `string`
- title_position: `string` - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
  - **Allowed values:**
    - `top`
    - `side`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.

</ResponseField>

<ResponseField name="x_axis_options" type="options group">
  Configure the x-axis

**Example:**
```
x_axis_options={
  title = "string"
  show_title = true
  label_wrap = true
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  min_interval = "year"
  max_interval = "year"
  interval = 0
  label_rotate = 0
  title_arrow = true
  max_label_length = 0
}
```

**Attributes:**
- title: `string`
- show_title: `boolean` - When `true`, renders the auto-derived axis title (the x column name) below the chart. Ignored when `title` is set explicitly. Defaults to `false` — auto-derived column-name titles usually read as visual noise and the axis labels speak for themselves.
- label_wrap: `boolean`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0. Defaults to true for numeric x-axes, false otherwise.
- min_interval: `string` - Minimum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
- max_interval: `string` - Maximum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
- label_rotate: `number` - Rotation angle of axis label in degrees. Positive values rotate clockwise, negative values rotate counter-clockwise.
- title_arrow: `boolean` - Show/hide the arrow (→) on the axis title
- max_label_length: `number` - Maximum character length for axis labels. Labels exceeding this length will be truncated with an ellipsis. Defaults to 20 characters when labels are rotated.

</ResponseField>

<ResponseField name="legend" type="boolean" default="true">
  Show legend. Studio's built-in legend renders a compact color swatch + series name. For chart-wide style overrides that need the legend to reflect them precisely (line width, custom symbols, richer styling), set `legend=false` and provide `legend={ show=true ... }` inside `echarts_options` to use ECharts' native legend instead.
</ResponseField>

<ResponseField name="legend_location" type="string" default="top">
  Position of the legend (top or bottom)

**Allowed values:**
- `top`
- `bottom`
</ResponseField>

<ResponseField name="series_order" type="array">
  Array of series names to define the order of series in the chart and legend. Series not in the array will appear after the ordered ones.
</ResponseField>

<ResponseField name="chart_options" type="options group">
  Studio-shaped chart styling shortcuts (palette, series colors, zoom, padding). For raw ECharts overrides, use `echarts_options` instead.

**Example:**
```
chart_options={
  color_palette = ["#3b82f6", "#8b5cf6", "#ec4899"]
  series_colors = {
    "Series A" = "#3b82f6"
    "Series B" = "#10b981"
    "Series C" = "#f59e0b"
  }
  zoom = true
  top_padding = 0
}
```

**Attributes:**
- color_palette: `array of strings` - Array of hex color codes to use for series colors
- series_colors: `map of key-value pairs` - Map of series names to hex color codes for custom series coloring
- zoom: `boolean` - Enables zoom by dragging on the chart area
- top_padding: `number` - Additional padding (in px) above the chart area to prevent labels from being cut off

</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `dataZoom`, `visualMap`, `graphic`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For per-series overrides, use `echarts_series_options` or the per-series `echarts_options` on a `line`/`bar`/etc. child.

**Example:**
```
echarts_options={
    tooltip={ position="top" }
    dataZoom=[{ type="slider" }]
}
```
</ResponseField>

<ResponseField name="echarts_series_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into every data series in the chart. Use when the same override should apply to all series. Skips reference lines/areas/points. For a single series, set `echarts_options` on the series child instead.

**Example:**
```
echarts_series_options={
    itemStyle={ borderRadius=8 }
    markLine={ data=[{ type="average" }] }
}
```
</ResponseField>

## Allowed Children

- [area](/components/area)
- [bar](/components/bar)
- [bubble](/components/bubble)
- [line](/components/line)
- [scatter](/components/scatter)
- [reference_line](/components/reference_line)
- [reference_area](/components/reference_area)
- [reference_point](/components/reference_point)

---

### Components Commentary (`docs/components/commentary.mdx`)

---
title: Commentary
description: Allows users to input commentary to be saved with the page
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% commentary id="overview" /%}
````

## Examples

### Page-wide commentary

````liquid
{% commentary id="overview" /%}
````

### Reporting-period commentary

````liquid
{% commentary id="monthly-review" scope="period" /%}
````

### Commentary per period and input

````liquid
{% dropdown id="category" data="demo.daily_orders" value_column="category" select_first=true /%}

{% commentary id="category-review" scope=["period", "category"] /%}
````

## Attributes

<ResponseField name="id" type="string" required>
  Unique identifier for the commentary component
</ResponseField>

<ResponseField name="scope" type="string" default="page">
  What the commentary is kept for: `page` (one for the whole page), `period` (one per reporting period; requires `workflow.period` in the frontmatter), an input id, or a list such as `["period", "fund"]` (one per combination of selected values). Inputs must be single-select: dropdown, button_group, input_tabs, toggle or period_selector.
</ResponseField>

<ResponseField name="placeholder" type="string">
  Placeholder text to show when the commentary is empty
</ResponseField>

<ResponseField name="className" type="string">
  Additional CSS classes to apply to the component
</ResponseField>

<ResponseField name="allowedEditors" type="array">
  Emails of allowed commentary editors
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the commentary
</ResponseField>

<ResponseField name="hideEditMetadata" type="string" default="print">
  When to hide the edit metadata

**Allowed values:**
- `always`
- `never`
- `print`
</ResponseField>

<ResponseField name="style" type="string" default="normal">
  Style of the commentary

**Allowed values:**
- `quote`
- `normal`
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

---

### Components Comparison Selector (`docs/components/comparison_selector.mdx`)

---
title: Comparison Selector
description: Display a selector for comparison options to use in SQL query templates
keywords: ["period over period","year over year","prior period","prior year","comparison","time comparison","date comparison","compare periods"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% comparison_selector
    id="comp"
    default_value="prior year"
/%}

{% big_value
    data="demo.daily_orders"
    value="sum(total_sales)"
    fmt="usd1m"
    date_range={
        date="date"
        range="last 12 months"
    }
    comparison={
        compare_vs={{comp}}
    }
/%}
````

## Examples

### Using `comparison`



````liquid
{% comparison_selector
    id="comp"
    default_value="prior year"
/%}

{% big_value
    data="demo.daily_orders"
    value="sum(total_sales)"
    fmt="usd1m"
    date_range={
        date="date"
        range="last 12 months"
    }
    comparison={
        compare_vs={{comp}}
    }
/%}
````

## Attributes

<ResponseField name="id" type="string" required>
  The id of the comparison selector to be used in SQL query templates
</ResponseField>

<ResponseField name="preset_values" type="array">
  Optional array of preset comparison values to show. If not provided, all comparison options will be available.
</ResponseField>

<ResponseField name="default_value" type="string">
  Default comparison to select on load

**Allowed values:**
- `prior year`
- `prior period`
- `target`
- `benchmark`
</ResponseField>

<ResponseField name="title" type="string" default="Comparison">
  Text displayed above the selector
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="placeholder" type="string">
  Placeholder text displayed when no value is selected
</ResponseField>

<ResponseField name="icon" type="string" default="triangle">
  Icon to display
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

## Using the Filter Variable

Reference this filter using `{{filter_id}}`. The value returned depends on where you use it.

| Context | Default Property | No Selection | Result |
|---------|-----------------|--------------|--------|
| Inline SQL query | `.comparison` |  | `{"compare_vs": "prior year"}` |
| `where` attribute | `.comparison` |  | `{"compare_vs": "prior year"}` |
| Text / Markdown | `.comparison` |  | `{"compare_vs": "prior year"}` |

### Available Properties

You can also access specific properties using `{{filter_id.property}}`:

#### .selected
Returns the selected comparison value with quotes. Returns an empty string when no value is selected.

````liquid
{% comparison_selector id="comparison" preset_values=["prior year", "prior period"] /%}

```sql sales_comparison
select 
  date,
  sum(sales) as total_sales,
  '{{comparison.selected}}' as comparison_type
from orders
group by date
```
````

**Example value:** `'prior year'`

#### .literal
Returns the raw unescaped selected value.

````liquid
{% comparison_selector id="comparison" preset_values=["prior year", "prior period"] /%}

```sql sales_comparison
select 
  date,
  sum(sales) as total_sales,
  {{comparison.literal}} as comparison_type
from orders
group by date
```
````

**Example value:** `prior year`

#### .compare_vs
Returns the comparison type.

**Example value:** `prior year`

#### .comparison
Returns the full comparison configuration as JSON. Use `{{comp}}` directly with `compare_vs` to dynamically configure comparisons.

````liquid
{% comparison_selector id="comp" /%}

{% big_value 
    data="demo.daily_orders"
    value="sum(total_sales)"
    comparison={ compare_vs={{comp}} }
/%}
````

**Example value:** `{"compare_vs": "prior year"}`

#### .agg
For benchmark comparisons: returns the aggregation function.

**Example value:** `avg`

#### .subject
For benchmark comparisons: returns the subject column that defines entities.

**Example value:** `region`

#### .target
For target comparisons: returns the target value or expression.

**Example value:** `100000`


## Allowed Children

- [benchmark_comparison](/components/benchmark_comparison)
- [target_comparison](/components/target_comparison)

---

### Components Custom Echart (`docs/components/custom_echart.mdx`)

---
title: Custom Echart
description: Render any Apache ECharts chart type using a raw ECharts config in the tag body. An escape hatch for charts the built-in components cannot express.
keywords: ["echarts","custom chart","advanced chart","escape hatch","config","waterfall","bridge"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% custom_echart data="demo.daily_orders" %}
{
  xAxis: { type: 'category' },
  yAxis: {},
  series: [{ type: 'bar', encode: { x: 'category', y: 'total_sales' } }]
}
{% /custom_echart %}
````

## Examples

### Basic Usage

````liquid
{% custom_echart data="demo.daily_orders" %}
{
  xAxis: { type: 'category' },
  yAxis: {},
  series: [{ type: 'bar', encode: { x: 'category', y: 'total_sales' } }]
}
{% /custom_echart %}
````

### Multiple Series with Tooltip

````liquid
{% custom_echart data="demo.daily_orders" %}
{
  tooltip: { trigger: 'axis' },
  legend: { show: true },
  xAxis: { type: 'category' },
  yAxis: {},
  series: [
    { type: 'bar', name: 'Sales', encode: { x: 'category', y: 'total_sales' } },
    { type: 'line', name: 'Transactions', encode: { x: 'category', y: 'transactions' } }
  ]
}
{% /custom_echart %}
````

### Dataset Transform

````liquid
{% custom_echart data="demo.daily_orders" %}
{
  dataset: [
    {},
    { transform: { type: 'sort', config: { dimension: 'total_sales', order: 'desc' } } }
  ],
  xAxis: { type: 'category' },
  yAxis: {},
  series: [{ type: 'bar', datasetIndex: 1, encode: { x: 'category', y: 'total_sales' } }]
}
{% /custom_echart %}
````

### Waterfall (EBITDA Bridge)

````liquid

```sql ebitda_bridge
select 'Prior EBITDA' as step, 1 as ord, 0 as placeholder, null as inc, null as dec, 32000000 as tot
union all select 'Home', 2, 32000000, 6200000, null, null
union all select 'Sports', 3, 38200000, 4100000, null, null
union all select 'Groceries', 4, 40000000, null, 2300000, null
union all select 'Current EBITDA', 5, 0, null, null, 40000000
order by ord
```

{% custom_echart data="ebitda_bridge" title="EBITDA Bridge" %}
{
  tooltip: { trigger: 'axis', valueFormatter: 'fmt:usd1m' },
  xAxis: { type: 'category', axisLabel: { interval: 0 } },
  yAxis: { axisLabel: { formatter: 'fmt:usd0m' } },
  series: [
    { type: 'bar', stack: 'bridge', silent: true,
      itemStyle: { color: 'transparent' },
      encode: { x: 'step', y: 'placeholder' } },
    { type: 'bar', stack: 'bridge', name: 'Increase',
      itemStyle: { color: '#22A39F' },
      label: { show: true, position: 'top', formatter: 'fmt:usd1m' },
      encode: { x: 'step', y: 'inc' } },
    { type: 'bar', stack: 'bridge', name: 'Decrease',
      itemStyle: { color: '#E2483D' },
      label: { show: true, position: 'bottom', formatter: 'fmt:usd1m' },
      encode: { x: 'step', y: 'dec' } },
    { type: 'bar', stack: 'bridge', name: 'Total',
      itemStyle: { color: '#475569' },
      label: { show: true, position: 'top', formatter: 'fmt:usd1m' },
      encode: { x: 'step', y: 'tot' } }
  ]
}
{% /custom_echart %}
````

### JavaScript mode (functions, gradients)

````liquid

{% custom_echart data="demo.daily_orders" %}
{
  tooltip: { trigger: 'axis', valueFormatter: (value) => fmt(value, 'usd0') },
  xAxis: { type: 'category' },
  yAxis: { axisLabel: { formatter: (value) => fmt(value, 'usd0m') } },
  series: [
    {
      type: 'bar',
      encode: { x: 'category', y: 'total_sales' },
      itemStyle: {
        color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
          { offset: 0, color: theme.colorPalettes.default[0] },
          { offset: 1, color: theme.colorPalettes.default[1] }
        ])
      },
      label: { show: true, formatter: (params) => fmt(params.value.total_sales, 'usd0') }
    }
  ]
}
{% /custom_echart %}
````

## Attributes

<ResponseField name="data" type="string" required>
  Name of the table to query
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the chart
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text (can only be used with title)
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="renderer" type="string" default="canvas">
  ECharts rendering engine

**Allowed values:**
- `canvas`
- `svg`
</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>

---

### Components Custom Map (`docs/components/custom_map.mdx`)

---
title: Custom Map
description: Write a map in JavaScript with Mapbox GL or MapLibre GL, using your page data. Use it when the built-in map component does not cover what you need.
keywords: ["map","mapbox","maplibre","custom map","geospatial","gl"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% custom_map height=400 %}
// mapgl is Mapbox GL when a token is available, else MapLibre GL.
// container and the access token are provided for you.
const map = new mapgl.Map({
  container,
  center: [-71.06, 42.36],
  zoom: 9
});
// Tiles load asynchronously — signal readiness once painted so PDF/PNG
// export captures a finished map rather than a blank frame.
map.on('idle', () => evidence.ready());
{% /custom_map %}
````

## Examples

### Basic map

````liquid
{% custom_map height=400 %}
// mapgl is Mapbox GL when a token is available, else MapLibre GL.
// container and the access token are provided for you.
const map = new mapgl.Map({
  container,
  center: [-71.06, 42.36],
  zoom: 9
});
// Tiles load asynchronously — signal readiness once painted so PDF/PNG
// export captures a finished map rather than a blank frame.
map.on('idle', () => evidence.ready());
{% /custom_map %}
````

### Plot Evidence data as points

````liquid
```sql locations
select 'New York'    as name, -74.01  as lng, 40.71 as lat
union all select 'Los Angeles', -118.24, 34.05
union all select 'Chicago',      -87.63, 41.88
union all select 'Houston',      -95.37, 29.76
union all select 'Denver',      -104.99, 39.74
union all select 'Seattle',     -122.33, 47.61
union all select 'Miami',        -80.19, 25.76
```

{% custom_map height=500 %}
const map = new mapgl.Map({ container, center: [-98, 39], zoom: 3 });
map.on('load', async () => {
  const rows = await evidence.query('locations');
  map.addSource('pts', {
    type: 'geojson',
    data: {
      type: 'FeatureCollection',
      features: rows.map((r) => ({
        type: 'Feature',
        geometry: { type: 'Point', coordinates: [r.lng, r.lat] },
        properties: r
      }))
    }
  });
  map.addLayer({ id: 'pts', type: 'circle', source: 'pts', paint: { 'circle-radius': 5 } });
});
{% /custom_map %}
````

### Import a plugin (lasso / draw)

````liquid
{% custom_map height=500 %}
// The draw control's buttons are CSS sprites — load its stylesheet or they render blank.
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://cdn.jsdelivr.net/npm/@mapbox/mapbox-gl-draw@1/dist/mapbox-gl-draw.css';
document.head.appendChild(link);

const { default: MapboxDraw } = await import('https://cdn.jsdelivr.net/npm/@mapbox/mapbox-gl-draw@1/+esm');
const map = new mapgl.Map({ container, center: [-98, 39], zoom: 3 });
map.on('load', () => {
  map.addControl(new MapboxDraw({ displayControlsDefault: false, controls: { polygon: true, trash: true } }));
});
{% /custom_map %}
````

## How it works

The body of the tag is JavaScript that draws a map. It runs in a sandboxed iframe with three things already in scope:

- `container` — the element to render the map into.
- `mapgl` — the map library (Mapbox GL, or MapLibre GL when there is no Mapbox token). Write standard Mapbox / MapLibre code against it.
- `evidence` — your page's data and state: run queries, read and write filters, and follow the report theme.

A minimal map:

```js
const map = new mapgl.Map({ container, center: [-71.06, 42.36], zoom: 9 });
map.on('idle', () => evidence.ready());
```

From there you write the same code you would anywhere else with Mapbox GL or MapLibre GL: load data with `evidence.query`, add sources and layers, and import any map plugin from a CDN. Because the code runs in an isolated iframe it cannot reach the rest of the page — it interacts with the report only through `evidence`. The full list of what is in scope is below.

## Globals available to your code

The tag body runs as JavaScript inside an isolated iframe with these globals already in scope:

| Global | What it is |
| --- | --- |
| `container` | The element to mount your map into. |
| `mapgl` | The active map library — Mapbox GL when a token is available, otherwise MapLibre GL. Use `new mapgl.Map({ container, ... })` for provider-agnostic code. |
| `maplibregl` | MapLibre GL, always available. |
| `mapboxgl` | Mapbox GL, with the access token already set. `undefined` when there is no token. |
| `provider` / `token` | The resolved provider and Mapbox token. |
| `evidence.query(name)` | Rows for a named query or `sql` block on the page. Returns a promise; page filters are already applied. |
| `evidence.variables` | Values passed via `variables={…}`. Always current; `onVariablesChange` fires on change. |
| `evidence.onVariablesChange(cb)` | Fires when any `variables` value changes. Returns an unsubscribe fn. |
| `evidence.filters` | `get()`, `set(id, value)`, `create(id, value, { column })`, `subscribe(cb)` — read and write page filters. |
| `evidence.subscribe(cb)` | Fires on any state change (variables, filters, or theme). Returns unsubscribe. |
| `evidence.theme` | `{ mode, palette }` — resolved light/dark mode and categorical palette. |
| `evidence.onThemeChange(cb)` | Fires on theme/mode change — swap the basemap style here for dark mode. |
| `evidence.onResize(cb)` | Fires when the block resizes. Call `map.resize()` in the callback. |
| `evidence.onTeardown(cb)` | Register cleanup (e.g. `() => map.remove()`) run before the map re-renders on an edit. |
| `evidence.ready()` | Signal the first render is done, so PDF/PNG export captures a finished frame. |

## Basemaps and keys

You don't need a Mapbox key in Studio. Maps render with a Mapbox basemap and the token is applied for you, so `new mapboxgl.Map({ container })` works with no `accessToken`.

Where no token is configured — such as the open-source CLI or local development — maps use **MapLibre GL** with a free OpenFreeMap basemap instead. `mapgl` points at whichever library is active, so `new mapgl.Map({ container })` works either way.

- `provider="maplibre"` always uses the keyless MapLibre basemap.
- `token="..."` uses your own Mapbox account.

Choose a basemap style for the current theme with `evidence.theme.mode`:

- Mapbox — `mapbox://styles/mapbox/light-v11`, `mapbox://styles/mapbox/dark-v11`
- MapLibre — `https://tiles.openfreemap.org/styles/positron` (light), `https://tiles.openfreemap.org/styles/dark`

Switch the style when the report toggles light/dark:

```js
evidence.onThemeChange((t) => map.setStyle(styleFor(t.mode)));
```

## Theming panels and overlays

Custom panels, legends, and controls you add to the map match the report theme with these CSS variables — set for you and updated on light/dark toggle (a sandboxed iframe has no host CSS otherwise, so use these rather than assuming a background):

- `var(--evidence-background)` — surface background
- `var(--evidence-foreground)` — text
- `var(--evidence-muted-foreground)` — secondary text
- `var(--evidence-border)` — borders / dividers

`evidence.theme.mode` (`light` / `dark`) plus `evidence.onThemeChange(cb)` let you swap the basemap style to match dark mode.

## Reacting to page filters and variables

A map and the rest of the page interact in three separate ways. Pick the one that matches what you need:

**1. Filter the map's data by a page input (dropdown, date range).** A filter takes effect where a query *references* it — passing it via `variables=` does not filter anything. Reference it in the SQL of the query the map runs, then `evidence.query()` that query:

```sql
-- city_sales (the query the map consumes)
select * from city_sales_all where {{ region_filter.filter }}
```

```js
const rows = await evidence.query('city_sales'); // re-runs with a region predicate when the dropdown changes
```

Selecting the dropdown re-runs `city_sales`; call `evidence.query` again from `evidence.subscribe` / `evidence.filters.subscribe` to redraw with the filtered rows.

**2. Read a filter/variable value in map JS (labels, client-side logic — not filtering).** Pass it via `variables=` as a quoted `{{ }}` expression — use `.literal` for the raw value or `.selected` for a SQL-quoted value. This gives you the value in `evidence.variables`; it does not filter any query.

```
{% custom_map height=400 variables={ region="{{ region_filter.literal }}" } %}
const label = evidence.variables.region; // e.g. show the selected region in a badge
evidence.onVariablesChange((v) => { /* re-label */ });
{% /custom_map %}
```

**3. Write a filter back from the map (lasso/click → filter other components or a server re-query).** Use `evidence.filters` and reference the filter in your query's SQL — the large-dataset pattern where you can't ship every row to the browser. A viewport-driven re-query on pan/zoom:

```js
const map = new mapgl.Map({ container, center: [-98, 39], zoom: 4 });
async function load() {
  const rows = await evidence.query('points_in_view'); // SQL references {{ min_lng.literal }} etc.
  // ...update your source with rows...
}
map.on('load', load);
map.on('moveend', () => {
  const b = map.getBounds();
  evidence.filters.set('min_lng', b.getWest());
  evidence.filters.set('max_lng', b.getEast());
  evidence.filters.set('min_lat', b.getSouth());
  evidence.filters.set('max_lat', b.getNorth());
});
evidence.filters.subscribe(load); // re-query when the bbox filters change
```

Call `evidence.filters.create('min_lng', -130)` once at startup for any filter the page's SQL references before the user interacts.

When you write a selection back as a list of ids, an empty list is ambiguous — it can mean "nothing selected yet" or "selected, matched nothing." Track selection state explicitly rather than checking the array length. And because `id IN ()` is invalid SQL, write a value that matches no rows (e.g. `['__none__']`) rather than an empty array when a selection matches nothing.

## PDF and PNG export

Map tiles load after your setup code returns, so signal completion once the map has painted or export captures a blank frame:

```js
map.on('idle', () => evidence.ready());
```

PNG export (image download) reads the WebGL canvas, which requires `preserveDrawingBuffer` — custom_map turns it on for you, so image export works by default. (PDF export uses a page screenshot and needs nothing extra.) On a very heavy map you can trade image export for a small perf win by opting out:

```js
const map = new mapgl.Map({ container, preserveDrawingBuffer: false }); // opt out: PNG blank, PDF still works
```

## Adding plugins

Import any map-ecosystem library from a CDN — mapbox-gl-draw (lasso / box select), deck.gl, turf, h3-js, and so on. They load as normal dynamic imports. A plugin with its own UI (buttons, icons) also needs its stylesheet loaded, or its controls render blank:

```js
// load the plugin's CSS too — icons are CSS sprites
const link = document.createElement('link');
link.rel = 'stylesheet';
link.href = 'https://cdn.jsdelivr.net/npm/@mapbox/mapbox-gl-draw@1/dist/mapbox-gl-draw.css';
document.head.appendChild(link);

const { default: MapboxDraw } = await import('https://cdn.jsdelivr.net/npm/@mapbox/mapbox-gl-draw@1/+esm');
map.addControl(new MapboxDraw());
```

mapbox-gl-draw's controls appear only on the Mapbox provider; on MapLibre use `@maplibre/maplibre-gl-draw`.

## Common issues

**Blank map.** If you passed a `token`, check it is valid — an invalid token still loads Mapbox but then fails to fetch tiles. Remove the token to fall back to the keyless MapLibre basemap.

**Export shows a blank map.** Tiles load after your setup code returns, so call `evidence.ready()` once the map has painted: `map.on('idle', () => evidence.ready())`.

**Different basemap locally than when published.** Local development and the CLI often have no Mapbox token, so they use MapLibre while Studio uses Mapbox. Set `PUBLIC_MAPBOX_TOKEN` locally to match, or set `provider` to pin one everywhere. If you rely on a Mapbox-only plugin, pin `provider="mapbox"`.

## Attributes

<ResponseField name="title" type="string">
  Title shown above the map
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle shown below the title
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text (can only be used with title)
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Custom text for the info link
</ResponseField>

<ResponseField name="token" type="string">
  Mapbox access token. Not required in Studio — a token is provided for you. Pass one to use your own Mapbox account. With no token, maps use keyless MapLibre.
</ResponseField>

<ResponseField name="provider" type="string">
  Force a basemap provider. Defaults to Mapbox when a token is available, otherwise MapLibre.

**Allowed values:**
- `mapbox`
- `maplibre`
</ResponseField>

<ResponseField name="variables" type="object">
  Page values to expose to the map as `evidence.variables` — e.g. `variables={ region=$region label="static" }` (Markdoc object syntax: whitespace-separated `key=value`, no commas). Changing a value fires `evidence.onVariablesChange(cb)` / `evidence.subscribe(cb)`.
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

---

### Components Date Grain Selector (`docs/components/date_grain_selector.mdx`)

---
title: Date Grain Selector
description: Display a selector for date grain options to use in SQL query templates
keywords: ["date grain","time grain","date bucket","date interval","date truncate","date grouping","time period","day week month year","date aggregation"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% date_grain_selector
    id="time_grain"
    default_value="month"
/%}

{% line_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    date_grain={{time_grain}}
/%}
````

## Examples

### Using `date_grain`



````liquid
{% date_grain_selector
    id="time_grain"
    default_value="month"
/%}

{% line_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    date_grain={{time_grain}}
/%}
````

### Using Inline SQL



````liquid
{% date_grain_selector
    id="time_grain"
    default_value="month"
/%}

```sql sales_by_period
select 
    date_trunc({{time_grain}}, date) as period,
    sum(total_sales) as total_sales
from demo.daily_orders
group by 1
order by 1
```

{% line_chart
    data="sales_by_period"
    x="period"
    y="total_sales"
/%}
````

## Attributes

<ResponseField name="id" type="string" required>
  The id of the date grain selector to be used in SQL query templates
</ResponseField>

<ResponseField name="preset_values" type="array">
  Optional array of preset date grain values to show. If not provided, all date grain options will be available.
</ResponseField>

<ResponseField name="default_value" type="string">
  Default date grain to select on load

**Allowed values:**
- `day`
- `week`
- `month`
- `quarter`
- `year`
- `hour`
- `day of week`
- `day of month`
- `day of year`
- `week of year`
- `month of year`
- `quarter of year`
</ResponseField>

<ResponseField name="title" type="string" default="Date Grain">
  Text displayed above the selector
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="placeholder" type="string">
  Placeholder text displayed when no value is selected
</ResponseField>

<ResponseField name="icon" type="string" default="clock">
  Icon to display
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

## Using the Filter Variable

Reference this filter using `{{filter_id}}`. The value returned depends on where you use it.

| Context | Default Property | No Selection | Result |
|---------|-----------------|--------------|--------|
| Inline SQL query | `.selected` | `''` | `'month'` |
| `where` attribute | `.selected` | `''` | `'month'` |
| Text / Markdown | `.literal` |  | `month` |

### Available Properties

You can also access specific properties using `{{filter_id.property}}`:

#### .selected
Returns the selected date grain value with quotes. Returns an empty string when no value is selected.

````liquid
{% date_grain_selector id="grain" preset_values=["day", "week", "month"] /%}

```sql sales_by_grain
select 
  toStartOf{{grain.selected}}(date) as period,
  sum(sales) as total_sales
from orders
group by period
```
````

**Example value:** `'month'`

#### .literal
Returns the raw unescaped selected value. Use this with the `date_grain` attribute.

````liquid
{% date_grain_selector id="grain" preset_values=["day", "week", "month"] /%}

```sql sales_by_grain
select 
  {{grain.literal}} as period,
  sum(sales) as total_sales
from orders
group by period
```
````

**Example value:** `month`

---

### Components Delta (`docs/components/delta.mdx`)

---
title: Delta
description: Display an inline delta value with an up/down indicator
keywords: ["change","difference","variance","comparison"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% delta
	data="demo.daily_orders"
	value="sum(total_sales)"
	comparison={
		compare_vs="target"
		target="120000000"
	}
/%}
````

## Examples

### Basic Usage



````liquid
{% delta
	data="demo.daily_orders"
	value="sum(total_sales)"
	comparison={
		compare_vs="target"
		target="120000000"
	}
/%}
````

### Semantic metric

````liquid
{% delta metric="revenue" comparison={ compare_vs="prior year" } /%}
````

## Attributes

<ResponseField name="data" type="string">
  Table or view to query. Omit when using `metric`.
</ResponseField>

<ResponseField name="metric" type="string">
  Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes.
</ResponseField>

<ResponseField name="value" type="string">
  SQL expression to insert into the SELECT part of the query (e.g., "COUNT(*)", "SUM(sales)"). Omit when using `metric`.
</ResponseField>

<ResponseField name="fmt" type="string">
  Format code for the value (e.g., "num", "usd", "pct"). See formatValue documentation for available formats. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="text" type="string">
  Text appearing after the delta (e.g., vs. prev month)
</ResponseField>

<ResponseField name="chip" type="boolean" default="false">
  Whether to display as a chip
</ResponseField>

<ResponseField name="comparison" type="options group">
  Comparison configuration object

**Example:**
```
comparison={
  compare_vs = "prior year"
  display_type = "compared_value"
  target = "string"
  benchmark = {
    agg = "avg"
    subject = "store_name"
    within = ["region"]
  }
  hide_pct = true
  pct_fmt = "string"
  abs_fmt = "string"
  down_is_good = true
}
```

**Attributes:**
- compare_vs: `string` - Type of comparison to perform. Options: prior year (same period last year), prior period (previous period of same duration), target (compare against a target value), benchmark (compare against group average/aggregate)
  - **Allowed values:**
    - `prior year`
    - `prior period`
    - `target`
    - `benchmark`
- display_type: `string` - What to display for comparison. Options: compared_value (comparison period value), abs (absolute change), pct (percentage change). Default: pct
  - **Allowed values:**
    - `compared_value`
    - `abs`
    - `pct`
- target: `string` - Target value for target comparison. Can be a column name, aggregation (e.g., "sum(target_sales)"), or literal value.
- benchmark: `options group`
  - **Options:**
    - agg: `string` - Aggregation function to apply across benchmark group. Options: avg (average), median, min, max, sum, count, count_distinct
      - **Allowed values:**
        - `avg`
        - `median`
        - `min`
        - `max`
        - `sum`
        - `count`
        - `count_distinct`
    - subject: `string` - Column or expression that defines individual entities in the benchmark (e.g., "store_name", "customer_id"). Required for single-value components.
    - value: `string` - Optional column or expression to use for benchmark calculation. If not specified, uses the main value column. Useful if you have a pre-aggregated benchmark table for RLS reasons.
    - within: `array of strings` - Dimension columns to group the benchmark by (e.g., ["region"]). Leave empty for dataset-wide benchmark.
    - where: `string` - SQL WHERE clause to filter which entities are included in the benchmark
    - exclude_self: `boolean` - Exclude the current row from its own benchmark calculation (table context only). Default: false
- hide_pct: `boolean` - Hide the percentage change line in comparison tooltips
- pct_fmt: `string` - Format code for percentage values in comparison tooltips
- abs_fmt: `string` - Format code for absolute values in comparison tooltips
- down_is_good: `boolean` - Whether a downward trend is considered positive. Defaults to the page's `down_is_good` setting.

</ResponseField>

<ResponseField name="show_value" type="boolean" default="true">
  Whether to show the value
</ResponseField>

<ResponseField name="show_symbol" type="boolean" default="true">
  Whether to show the delta symbol
</ResponseField>

<ResponseField name="symbol_position" type="string" default="right">
  Position of the delta symbol relative to the value

**Allowed values:**
- `left`
- `right`
</ResponseField>

<ResponseField name="neutral_range" type="array" default="[0,0]">
  Range [min, max] for neutral values. Use null for infinity (e.g., [null, 0] means anything ≤ 0 is neutral)
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

---

### Components Details (`docs/components/details.mdx`)

---
title: Details
description: The details component
keywords: ["expandable","collapsible section","show more"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% details
    title="Metric Definitions"
%}

**Sales:** includes sales of all core products in all regions

**Sales Growth:** YoY growth in sales

{% /details %}
````

## Examples

### Basic Usage



````liquid
{% details
    title="Metric Definitions"
%}

**Sales:** includes sales of all core products in all regions

**Sales Growth:** YoY growth in sales

{% /details %}
````

### Open on Desktop, Collapsed on Mobile

````liquid
{% details
    title="Metric Definitions"
    open=true
    open_mobile=false
%}

**Sales:** includes sales of all core products in all regions

**Sales Growth:** YoY growth in sales

{% /details %}
````

## Attributes

<ResponseField name="title" type="string" required>
  Title of the details section
</ResponseField>

<ResponseField name="open" type="boolean" default="false">
  Whether the details section starts open
</ResponseField>

<ResponseField name="open_mobile" type="boolean">
  Whether the details section starts open on mobile screens. Defaults to the value of `open`
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

---

### Components Dimension (`docs/components/dimension.mdx`)

---
title: Dimension
description: Add a dimension to a table, including date filtering, date grains, formatting, and more
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% table data="demo.daily_orders" %}
    {% dimension value="category" /%}
    {% dimension value="date" date_grain="month" title="Month" /%}
{% /table %}
````

## Examples

### Table with Dimensions

````liquid
{% table data="demo.daily_orders" %}
    {% dimension value="category" /%}
    {% dimension value="date" date_grain="month" title="Month" /%}
{% /table %}
````

### With Image

````liquid
{% table data="demo.daily_orders" %}
    {% dimension value="category" image="image_url" /%}
    {% measure value="sum(total_sales)" /%}
{% /table %}
````

### With Link

````liquid
{% table data="demo.daily_orders" %}
    {% dimension value="category" link="concat('https://www.google.com/search?q=', category)" /%}
    {% measure value="sum(total_sales)" /%}
{% /table %}
````

### With Logo

````liquid
{% table data="sales" %}
    {% dimension value="vendor" logo="domain" /%}
    {% measure value="sum(amount)" /%}
{% /table %}
````

### Conditional Colors

````liquid
{% table data="demo.daily_orders" %}
    {% dimension value="category" conditional_colors="case when sum(total_sales) > 20000000 then '#22c55e' when sum(total_sales) > 10000000 then '#f59e0b' else '#ef4444' end" /%}
    {% measure value="sum(total_sales)" fmt="usd1m" /%}
{% /table %}
````

## Attributes

<ResponseField name="value" type="string" required>
  
</ResponseField>

<ResponseField name="title" type="string">
  
</ResponseField>

<ResponseField name="align" type="string">
  

**Allowed values:**
- `left`
- `center`
- `right`
</ResponseField>

<ResponseField name="wrap" type="boolean">
  Whether to allow content in this dimension column to wrap across multiple lines
</ResponseField>

<ResponseField name="info" type="string">
  
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="hide" type="boolean" default="false">
  Whether to hide this column from the table display. Hidden columns are still included in queries and can be referenced by other columns.
</ResponseField>

<ResponseField name="html" type="boolean" default="false">
  Whether to render the dimension value as HTML
</ResponseField>

<ResponseField name="image_options" type="options group">
  Image display options (used when image prop is set)

**Attributes:**
- height: `number` - Height of the image in pixels
- width: `number` - Width of the image in pixels
- alt: `string` - Alt text for the image
- hide_label: `boolean` - Whether to hide the text label and show only the image

</ResponseField>

<ResponseField name="image" type="string">
  Column name or SQL expression containing the image URL for this dimension
</ResponseField>

<ResponseField name="logo" type="string">
  Column name or SQL expression containing the domain to look up a company logo for this dimension
</ResponseField>

<ResponseField name="logo_options" type="options group">
  Logo display options (used when logo prop is set)

**Example:**
```
logo_options={
  size = "sm"
  grayscale = true
  hide_label = true
}
```

**Attributes:**
- size: `string` - Logo size: sm, base, lg, xl
  - **Allowed values:**
    - `sm`
    - `base`
    - `lg`
    - `xl`
- grayscale: `boolean` - Display logo in grayscale
- hide_label: `boolean` - Whether to hide the text label and show only the logo

</ResponseField>

<ResponseField name="link" type="string">
  Column name or SQL expression containing the URL for linking this dimension
</ResponseField>

<ResponseField name="link_label" type="string">
  Static text to use as the link label instead of the cell content
</ResponseField>

<ResponseField name="link_new_tab" type="boolean" default="false">
  Whether to open the link in a new tab
</ResponseField>

<ResponseField name="date_grain" type="string">
  Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

**Allowed values:**
- `day`
- `week`
- `month`
- `quarter`
- `year`
- `hour`
- `day of week`
- `day of month`
- `day of year`
- `week of year`
- `month of year`
- `quarter of year`
</ResponseField>

<ResponseField name="fmt" type="string">
  Format code for displaying dimension values (e.g., "yyyy" for years, "mmm" for months)
</ResponseField>

<ResponseField name="sort" type="string">
  Sort direction for this dimension column. When specified, the table will be sorted by this column.

**Allowed values:**
- `asc`
- `desc`
</ResponseField>

<ResponseField name="column_group" type="string">
  Group name for this column. Columns with matching group names will be visually grouped under a shared header.
</ResponseField>

<ResponseField name="repeat_values" type="boolean">
  Whether to repeat this dimension value on every row. When true, the value is displayed on every row even when it is the same as the row above. Overrides the table-level repeat_values setting for this dimension.
</ResponseField>

<ResponseField name="conditional_colors" type="string">
  SQL expression that returns color values for each row. Used to conditionally color dimension cells based on data (e.g., "case when count(*) > 0 then '#22c55e' else null end").
</ResponseField>



## Allowed Parents

- [table](/components/table)

---

### Components Dimension Grid (`docs/components/dimension_grid.mdx`)

---
title: Dimension Grid
description: Display an interactive grid of dimension columns with aggregated metrics and bar visualizations for filtering
keywords: ["facet filter","dimension filter","multi-select grid"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% dimension_grid
    id="product_filter"
    data="demo.daily_orders"
/%}
````

## Examples

### Basic Usage



````liquid
{% dimension_grid
    id="product_filter"
    data="demo.daily_orders"
/%}
````

### With Explicit Dimensions and Metric

````liquid
{% dimension_grid
    id="sales_filter"
    data="orders"
    dimensions=["category", "region"]
    metric="sum(sales)"
    fmt="usd"
    limit=5
/%}
````

### Using Filter in Query



````liquid
{% dimension_grid id="order_filter" data="orders" /%}

```sql filtered_orders
select * from orders
where {{order_filter.filter}}
```
````

## Attributes

<ResponseField name="id" type="string" required>
  The id of the dimension grid to use in a `filters` prop
</ResponseField>

<ResponseField name="data" type="string" required>
  Name of the table to query
</ResponseField>

<ResponseField name="dimensions" type="array">
  Array of column names to display as dimensions. If not provided, auto-detects string columns.
</ResponseField>

<ResponseField name="metric" type="string" default="count(*)">
  SQL aggregation expression (default: count(*))
</ResponseField>

<ResponseField name="metric_label" type="string">
  Label displayed above the metric values
</ResponseField>

<ResponseField name="fmt" type="string">
  Format code for the metric values (e.g., "num0", "usd", "pct1"). See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="limit" type="number" default="10">
  Maximum number of values to show per dimension (default: 10)
</ResponseField>

<ResponseField name="multiple" type="boolean" default="true">
  Allow multiple selections per dimension (default: true)
</ResponseField>

<ResponseField name="filters" type="array">
  Array of filter IDs to apply when querying dimension values
</ResponseField>

<ResponseField name="where" type="string">
  SQL WHERE clause to filter data
</ResponseField>

<ResponseField name="title" type="string">
  Title displayed above the dimension grid
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle displayed below the title
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

## Using the Filter Variable

Reference this filter using `{{filter_id}}`. The value returned depends on where you use it.

| Context | Default Property | No Selection | Result |
|---------|-----------------|--------------|--------|

### Available Properties

You can also access specific properties using `{{filter_id.property}}`:

#### .filter
Returns a complete SQL filter expression combining all dimension selections. Returns `true` when no values are selected.

````liquid
{% dimension_grid id="dim_filter" data="orders" /%}

```sql filtered_orders
select * from orders
where {{dim_filter.filter}}
```
````

#### .selected
Returns an object with dimension names as keys and selected values as arrays. Useful for accessing individual dimension selections.

````liquid
{% dimension_grid id="dim_filter" data="orders" dimensions=["category", "region"] /%}

Selected categories: {{dim_filter.category}}
Selected regions: {{dim_filter.region}}
````

#### .literal
Returns a human-readable summary of all selections.

````liquid
{% dimension_grid id="dim_filter" data="orders" /%}

Active filters: {{dim_filter.literal}}
````

---

### Components Download (`docs/components/download.mdx`)

---
title: Download
description: A button to download data as an Excel file, supports up to 500,000 row downloads via the limit attribute.
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% download data="demo.daily_orders" /%}
````

## Examples

### Basic Usage



````liquid
{% download data="demo.daily_orders" /%}
````

### Custom Label and Filename



````liquid
{% download
  data="demo.daily_orders"
  label="Export Orders"
  filename="daily_orders_export"
/%}
````

### With Variant



````liquid
{% download
  data="demo.daily_orders"
  label="Export Data"
  variant="primary"
/%}
````

### With Large Limit



````liquid
{% download
  data="demo.daily_orders"
  label="Download Recent Orders"
  limit=50000
/%}
````

## Attributes

<ResponseField name="data" type="string" required>
  Table or view to download
</ResponseField>

<ResponseField name="label" type="string" default="Download">
  Text displayed on the download button
</ResponseField>

<ResponseField name="filename" type="string">
  Name of the downloaded file (without extension)
</ResponseField>

<ResponseField name="variant" type="string" default="default">
  Button style variant

**Allowed values:**
- `default`
- `primary`
- `destructive`
- `secondary`
- `ghost`
- `link`
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

---

### Components Dropdown (`docs/components/dropdown.mdx`)

---
title: Dropdown
description: Display a dropdown with distinct values from a database column to use in filters
keywords: ["cascading","linked","dependent","hierarchical","filter","select","relevant values"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% dropdown
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    filters=["category_filter"]
    date_grain="month"
/%}
````

## Examples

### Using `filters`



````liquid
{% dropdown
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    filters=["category_filter"]
    date_grain="month"
/%}
````

### Using `where`



````liquid
{% dropdown
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

{% bar_chart
    data="demo.daily_orders"
    x="date"
    y="sum(total_sales)"
    where="category = {{category_filter}}"
    date_grain="month"
/%}
````

### Using Inline SQL



````liquid
{% dropdown
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
/%}

```sql filtered_orders
select * from demo.daily_orders
where category = {{category_filter}}
```

{% table data="filtered_orders" /%}
````

### Using `date_range`



````liquid
{% dropdown
    id="category_filter"
    data="demo.daily_orders"
    value_column="category"
    date_range={
        date="date"
        range="last 12 months"
    }
/%}
````

### Cascading Dropdowns (Linked Filters)



````liquid
{% dropdown
    id="category"
    data="demo.order_details"
    value_column="category"
    title="Category"
/%}

{% dropdown
    id="item"
    data="demo.order_details"
    value_column="item_name"
    title="Item"
    filters=["category"]
/%}

{% table
    data="demo.order_details"
    filters=["category", "item"]
/%}
````

## Attributes

<ResponseField name="id" type="string" required>
  The id of the dropdown to be used in a `filters` prop
</ResponseField>

<ResponseField name="data" type="string">
  Name of the table to query
</ResponseField>

<ResponseField name="filters" type="array">
  Array of filter IDs to apply when querying for dropdown options. Use this to create cascading/linked dropdowns where selecting a value in one dropdown narrows the available options in this dropdown.
</ResponseField>

<ResponseField name="value_column" type="string">
  Column name to use as the value for each option, and the column to filter by when this dropdown's `id` is used in the `filters` prop of a chart
</ResponseField>

<ResponseField name="label_column" type="string">
  Column name to use as the label for each option
</ResponseField>

<ResponseField name="options" type="array">
  List of options to display in the dropdown
</ResponseField>

<ResponseField name="title" type="string">
  Text displayed above the dropdown
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="icon" type="string">
  Icon to display in the dropdown trigger

**Allowed values:**
- `trending-up`
- `trending-down`
- `clock`
- `calendar`
- `check`
- `x`
- `info`
- `alert-circle`
- `help-circle`
- `eye`
- `eye-off`
- `user`
- `users`
- `settings`
- `cog`
- `plus`
- `minus`
- `up`
- `down`
- `right`
- `left`
- `star`
- `heart`
- `search`
- `file`
- `file-text`
- `home`
- `mail`
- `filter`
- `share`
- `bell`
- `trash`
- `credit-card`
- `globe`
- `key`
- `croissant`
- `map`
- `rotate`
- `rewind`
- `bank`
- `receipt`
- `activity`
- `chart-column`
- `chart-pie`
- `chart-no-axes-combined`
- `goal`
- `rocket`
- `trophy`
- `apple`
- `cookie`
- `donut`
- `beef`
- `cake`
- `soup`
- `utensils`
- `milk`
- `nut`
- `pyramid`
- `triangle`
- `arrow-down`
- `arrow-left`
- `arrow-right`
- `arrow-up`
- `chevron-down`
- `chevron-left`
- `chevron-right`
- `chevron-up`
- `chevrons-down`
- `chevrons-left`
- `chevrons-right`
- `chevrons-up`
- `menu`
- `external-link`
- `check-circle`
- `x-circle`
- `edit`
- `trash-2`
- `copy`
- `save`
- `download`
- `upload`
- `send`
- `refresh`
- `redo`
- `undo`
- `folder`
- `folder-open`
- `image`
- `file-image`
- `user-plus`
- `user-minus`
- `user-check`
- `lock`
- `unlock`
- `log-in`
- `log-out`
- `message-square`
- `message-circle`
- `phone`
- `phone-call`
- `bell-off`
- `video`
- `video-off`
- `play`
- `pause`
- `stop`
- `skip-back`
- `skip-forward`
- `volume`
- `volume-1`
- `volume-2`
- `volume-off`
- `volume-x`
- `bookmark`
- `tag`
- `link`
- `unlink`
- `share-2`
- `alert-triangle`
- `loader`
- `more-vertical`
- `more-horizontal`
- `grid`
- `list`
- `maximize`
- `minimize`
- `zoom-in`
- `zoom-out`
- `thumbs-up`
- `thumbs-down`
- `shopping-cart`
- `dollar-sign`
- `camera`
- `printer`
- `monitor`
- `smartphone`
- `laptop`
- `calculator`
- `cloud-sun-rain`
- `sun-snow`
- `thermometer-sun`
- `thermometer-snowflake`
- `cloudy`
- `cloud-rain-wind`
- `cloud-rain`
- `wind`
- `sun`
- `cloud-snow`
- `thermometer`
- `cloud-drizzle`
- `cloud-sun`
- `cloud`
- `cloud-lightning`
- `snowflake`
- `flame`
- `atom`
- `fuel`
- `magnet`
- `factory`
- `tree-deciduous`
- `waypoints`
- `plug`
- `dam`
- `battery`
</ResponseField>

<ResponseField name="initial_value" type="string | number | array">
  Initial selected value(s)
</ResponseField>

<ResponseField name="select_first" type="boolean" default="false">
  Automatically select the first option when the component loads
</ResponseField>

<ResponseField name="default_top_n" type="number">
  For a multi-select dropdown, pre-selects the first N options (after `order` is applied) when the component loads. Generalizes `select_first`. Does not limit the option list and has no effect when `multiple=false`.
</ResponseField>

<ResponseField name="placeholder" type="string">
  Placeholder text displayed when no value is selected
</ResponseField>

<ResponseField name="search" type="boolean" default="true">
  Includes a search input within the dropdown menu
</ResponseField>

<ResponseField name="multiple" type="boolean" default="false">
  Allows multiple selections
</ResponseField>

<ResponseField name="clear" type="boolean" default="true">
  Includes a clear button to unselect the selected value(s)
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

## Using the Filter Variable

Reference this filter using `{{filter_id}}`. The value returned depends on where you use it.

The examples below show values for three scenarios:
- **No selection**
- **Single select:** "Electronics" selected
- **Multi select:** "Sports" and "Home" selected (when `multiple=true`)

| Context | Default Property | No Selection | Single Select | Multi Select |
|---------|-----------------|--------------|---------------|-------------|
| Inline SQL query | `.selected` | `''` | `'Electronics'` | `('Sports', 'Home')` |
| `where` attribute | `.selected` | `''` | `'Electronics'` | `('Sports', 'Home')` |
| Text / Markdown | `.literal` |  | `Electronics` | `Sports, Home` |

### Available Properties

You can also access specific properties using `{{filter_id.property}}`:

#### .filter
Returns a complete SQL filter expression ready to use in WHERE clauses. Returns `true` when no value is selected.

````liquid
{% dropdown id="category_filter" data="products" value_column="category" /%}

```sql filtered_products
select * from products
where {{category_filter.filter}}
```
````

| No Selection | Single Select | Multi Select |
|--------------|---------------|-------------|
| `true` | `category = 'Electronics'` | `category IN ('Sports', 'Home')` |

#### .selected
Returns the selected value(s) wrapped in quotes, suitable for SQL comparisons. Returns an empty string when no value is selected.

````liquid
{% dropdown id="category_filter" data="products" value_column="category" /%}

```sql products_by_category
select * from products
where category = {{category_filter.selected}}
```
````

| No Selection | Single Select | Multi Select |
|--------------|---------------|-------------|
| `''` | `'Electronics'` | `('Sports', 'Home')` |

#### .literal
Returns the raw unescaped selected value(s), useful for display in text or dynamic column selection.

````liquid
{% dropdown id="sort_column" data="products" value_column="column_name" /%}

```sql dynamic_sort
select * from products
order by {{sort_column.literal}}
```
````

| No Selection | Single Select | Multi Select |
|--------------|---------------|-------------|
| `` | `Electronics` | `Sports, Home` |

#### .label
Returns the display label for the selected option(s). Falls back to the value if no label is defined.

````liquid
{% dropdown id="category_filter" %}
    {% option value="Electronics" label="Electronics" /%}
    {% option value="Sports" label="Sports" /%}
    {% option value="Home" label="Home" /%}
{% /dropdown %}

Selected: {{category_filter.label}}
````

| No Selection | Single Select | Multi Select |
|--------------|---------------|-------------|
| `` | `Electronics` | `Sports, Home` |

#### .fmt
Returns the format string associated with the selected option. For multiple selections, returns the first format.

````liquid
{% dropdown id="metric_selector" %}
    {% option value="revenue" label="Revenue" fmt="usd" /%}
    {% option value="growth_rate" label="Growth Rate" fmt="pct1" /%}
{% /dropdown %}

{% big_value data={metrics} value=value fmt={{metric_selector.fmt}} /%}
````

| No Selection | Single Select | Multi Select |
|--------------|---------------|-------------|
| `` | `usd` | `usd` |


## Allowed Children

- [option](/components/option)

---

### Components Else (`docs/components/else.mdx`)

---
title: Else
description: If prior conditional blocks do not pass, the contents of the else block are rendered.
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% if data="demo.daily_orders" %}
	If Content
{% /if %}
{% else %}
	Else Content
{% /else %}
````

## Examples

### Basic Usage

````liquid
{% if data="demo.daily_orders" %}
	If Content
{% /if %}
{% else %}
	Else Content
{% /else %}
````

## Attributes

This component has no attributes.

---

### Components Else If (`docs/components/else_if.mdx`)

---
title: Else If
description: If prior conditional blocks do not pass, conditionally render the contents based on whether rows are returned by the query.
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% if data="demo.daily_orders" condition="no_rows" %}
	If Content
{% /if %}
{% else_if data="demo.daily_orders" %}
	Else If Content
{% /else_if %}
````

## Examples

### Basic Usage

````liquid
{% if data="demo.daily_orders" condition="no_rows" %}
	If Content
{% /if %}
{% else_if data="demo.daily_orders" %}
	Else If Content
{% /else_if %}
````

## Attributes

<ResponseField name="data" type="string" required>
  Table or view to query
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="condition" type="string" default="has_rows">
  Set to "no_rows" to render children only if the query returns no rows. Set to "has_rows" (or omit) to render if query returns rows.

**Allowed values:**
- `no_rows`
- `has_rows`
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

---

### Components Fence (`docs/components/fence.mdx`)

---
title: Fence
description: Display a code block
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
```language query_name
  content
```
````

## Examples

### Basic Usage

````liquid
```language query_name
  content
```
````

### Define a SQL query

````liquid
```sql electronics_orders
  SELECT * FROM demo.daily_orders WHERE category = 'Electronics'
```


{% table data="electronics_orders" /%}
````

## Attributes

<ResponseField name="language" type="string">
  The language of the code block
</ResponseField>

<ResponseField name="content" type="string">
  The content of the code block
</ResponseField>

<ResponseField name="meta" type="string">
  Optional name for the code block. If provided and language is "sql", this will register the query as an inline query that can be used by other components. Inline queries must be defined at the top level of the page, not inside other components (e.g. tabs, accordion, details).
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

---

### Components File (`docs/components/file.mdx`)

---
title: File
description: Attach a downloadable file to a report as a card showing its icon, name, type, and date. Drop or paste a file into the editor to upload it to your organization and insert a file tag automatically.
keywords: ["attachment","download","document","pdf","excel","csv","upload","asset"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% file
    url="https://files.example.com/reports/q3-board-deck.pdf"
    name="Q3 Board Deck.pdf"
    date="2026-09-29"
/%}
````

## Examples

### Basic Usage

````liquid
{% file
    url="https://files.example.com/reports/q3-board-deck.pdf"
    name="Q3 Board Deck.pdf"
    date="2026-09-29"
/%}
````

### Uploaded File

````liquid
{% file
    url="evd_org_01ABC/k7Xq2mB9.xlsx"
    name="Regional Sales Model.xlsx"
    date="2026-09-29"
/%}
````

## Attributes

<ResponseField name="url" type="string" required>
  The upload alias returned when a file is dropped into the editor (evd_...), or an external URL to link to.
</ResponseField>

<ResponseField name="name" type="string">
  Display name for the file. Defaults to the filename from the URL.
</ResponseField>

<ResponseField name="type" type="string">
  File type label shown on the card (e.g. PDF, Excel). Inferred from the file extension when omitted.
</ResponseField>

<ResponseField name="date" type="string">
  Date shown on the card, e.g. the upload date. Accepts YYYY-MM-DD, an ISO timestamp, or free text.
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

---

### Components Filter Bar (`docs/components/filter_bar.mdx`)

---
title: Filter Bar
description: Renders a floating bar of filters at the top or bottom of your page
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

```liquid
{% filter_bar %}
  ...
{% /filter_bar %}
```

## Attributes

This component has no attributes.

## Allowed Children

- [dropdown](/components/dropdown)
- [table_filter](/components/table_filter)
- [date_grain_selector](/components/date_grain_selector)
- [comparison_selector](/components/comparison_selector)
- [range_calendar](/components/range_calendar)
- [button_group](/components/button_group)
- [period_selector](/components/period_selector)

---

### Components Funnel Chart (`docs/components/funnel_chart.mdx`)

---
title: Funnel Chart
description: Display a funnel chart showing conversion rates through stages
keywords: ["funnel","conversion funnel","pipeline"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% funnel_chart
    data="demo.daily_orders"
    category="category"
    value="sum(transactions)"
/%}
````

## Examples

### Basic Usage



````liquid
{% funnel_chart
    data="demo.daily_orders"
    category="category"
    value="sum(transactions)"
/%}
````

### Funnel Chart with Custom Styling



````liquid
{% funnel_chart
    data="demo.daily_orders"
    category="category"
    value="sum(transactions)"
    align="left"
    label_position="outside"
    gap=5
    title="Styled Funnel"
/%}
````

### Funnel Chart with Custom Colors



````liquid
{% funnel_chart
    data="demo.daily_orders"
    category="category"
    value="sum(transactions)"
    chart_options={
        color_palette = ["#0d0887", "#6300a7", "#a62098", "#d5546e", "#f68d45", "#fcd225", "#f0f921"]
    }
/%}
````

## Attributes

<ResponseField name="data" type="string">
  Name of the table to query. Omit when using `metric`.
</ResponseField>

<ResponseField name="metric" type="string">
  Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes.
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="category" type="string" required>
  Column name for funnel stages/categories
</ResponseField>

<ResponseField name="value" type="string">
  Column name for values. Omit when using `metric`.
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the chart
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text (can only be used with title)
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="value_fmt" type="string" default="num">
  Format for values. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="legend" type="boolean" default="false">
  Show a legend above the chart (stages are labeled directly on the funnel by default)
</ResponseField>

<ResponseField name="legend_location" type="string" default="top">
  Position of the legend (top or bottom)

**Allowed values:**
- `top`
- `bottom`
</ResponseField>

<ResponseField name="label_position" type="string" default="auto">
  Label position: auto places labels inside each stage, moving them beside stages that are too narrow; outside places all labels in a rail beside the chart (left of the chart unless the funnel is right-aligned)

**Allowed values:**
- `auto`
- `inside`
- `outside`
- `center`
</ResponseField>

<ResponseField name="chart_options" type="options group">
  Chart configuration options

**Example:**
```
chart_options={
  color_palette = ["value1", "value2"]
}
```

**Attributes:**
- color_palette: `array of strings`

</ResponseField>

<ResponseField name="align" type="string" default="left">
  Funnel alignment

**Allowed values:**
- `center`
- `left`
- `right`
</ResponseField>

<ResponseField name="show_percent" type="boolean" default="false">
  Show percentages relative to first stage
</ResponseField>

<ResponseField name="min_size" type="string" default="0%">
  Minimum size of funnel stages
</ResponseField>

<ResponseField name="max_size" type="string" default="100%">
  Maximum size of funnel stages
</ResponseField>

<ResponseField name="gap" type="number" default="1">
  Gap between funnel stages in pixels
</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.
</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `graphic`, `visualMap`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For overrides scoped to the data series, use `echarts_series_options`.

**Example:**
```
echarts_options={
    tooltip={ position="top" }
    graphic=[{ type="text" }]
}
```
</ResponseField>

<ResponseField name="echarts_series_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into the chart series. Use for series-level styling the structured props do not expose.

**Example:**
```
echarts_series_options={
    itemStyle={ borderRadius=8 }
}
```
</ResponseField>

---

### Components Heat Grid (`docs/components/heat_grid.mdx`)

---
title: Heat Grid
description: Display a grid of color-coded cells based on metric thresholds
keywords: ["metric grid","color grid","conditional formatting"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% heat_grid
  data="appointments"
  dimension="province"
  value="avg(wait_time)"
  thresholds=[60, 90]
  units="MIN"
  lower_is_better=true
/%}
````

## Examples

### Basic Usage

````liquid
{% heat_grid
  data="appointments"
  dimension="province"
  value="avg(wait_time)"
  thresholds=[60, 90]
  units="MIN"
  lower_is_better=true
/%}
````

## Attributes

<ResponseField name="data" type="string">
  Table or view to query. Omit when using `metric`.
</ResponseField>

<ResponseField name="metric" type="string">
  Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes.
</ResponseField>

<ResponseField name="dimension" type="string" required>
  Column for cell labels (e.g., province)
</ResponseField>

<ResponseField name="value" type="string">
  SQL aggregation expression for the metric (e.g., avg(wait_time)). Omit when using `metric`.
</ResponseField>

<ResponseField name="thresholds" type="array" required>
  Two numeric thresholds creating 3 color zones: [low, high]. Values below low are zone 1, between low and high are zone 2, at or above high are zone 3.
</ResponseField>

<ResponseField name="units" type="string">
  Units label shown below the value in each cell (e.g., "MIN")
</ResponseField>

<ResponseField name="fmt" type="string">
  Format code for the metric value. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="title" type="string">
  Component title
</ResponseField>

<ResponseField name="lower_is_better" type="boolean">
  If true, low values are green and high values are red. Default (false) means high values are green.
</ResponseField>

<ResponseField name="compact" type="boolean">
  If true, removes gaps and borders between cells and applies a single border radius to the outer grid.
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

---

### Components Heatmap (`docs/components/heatmap.mdx`)

---
title: Heatmap
description: Display a heatmap chart with color-coded cells
keywords: ["heat map","matrix chart","color matrix"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% heatmap
    data="demo.daily_orders"
    x="date"
    x_date_grain="year"
    y="category"
    value="sum(total_sales)"
/%}
````

## Examples

### Basic Usage



````liquid
{% heatmap
    data="demo.daily_orders"
    x="date"
    x_date_grain="year"
    y="category"
    value="sum(total_sales)"
/%}
````

### With Custom Colors



````liquid
{% heatmap
    data="demo.daily_orders"
    x="date"
    x_date_grain="year"
    y="category"
    value="sum(total_sales)"
    title="Sales Intensity by Year and Category"
    chart_options={
        color_scale = ["#f7fafc", "#e2e8f0", "#cbd5e0", "#a0aec0", "#718096", "#4a5568", "#2d3748"]
    }
/%}
````

## Attributes

<ResponseField name="data" type="string">
  Name of the table to query. Omit when using `metric`.
</ResponseField>

<ResponseField name="metric" type="string">
  Semantic metric name to display, from metrics/*.yaml. Use instead of the raw data/value/x/y attributes.
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="x_date_grain" type="string">
  Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

**Allowed values:**
- `day`
- `week`
- `month`
- `quarter`
- `year`
- `hour`
- `day of week`
- `day of month`
- `day of year`
- `week of year`
- `month of year`
- `quarter of year`
</ResponseField>

<ResponseField name="y_date_grain" type="string">
  Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

**Allowed values:**
- `day`
- `week`
- `month`
- `quarter`
- `year`
- `hour`
- `day of week`
- `day of month`
- `day of year`
- `week of year`
- `month of year`
- `quarter of year`
</ResponseField>

<ResponseField name="x" type="string" required>
  Column name for x-axis categories
</ResponseField>

<ResponseField name="y" type="string" required>
  Column name for y-axis categories
</ResponseField>

<ResponseField name="x_axis_title" type="string">
  Title to display for the x-axis
</ResponseField>

<ResponseField name="y_axis_title" type="string">
  Title to display for the y-axis
</ResponseField>

<ResponseField name="value" type="string">
  Column name for cell values. Omit when using `metric`.
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the chart
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Info text to display in a tooltip next to the title. Can only be used with the title prop.
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="value_fmt" type="string">
  Format for values (defaults to `num`, or the metric format in metric mode). See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="x_fmt" type="string">
  Format for x axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="y_fmt" type="string">
  Format for y axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="x_sort" type="string">
  Sort order for x axis categories (asc or desc)

**Allowed values:**
- `asc`
- `desc`
</ResponseField>

<ResponseField name="y_sort" type="string">
  Sort order for y axis categories (asc or desc)

**Allowed values:**
- `asc`
- `desc`
</ResponseField>

<ResponseField name="value_sort" type="string">
  Sort categories by total value (asc or desc). Applies to the first axis without explicit sort.

**Allowed values:**
- `asc`
- `desc`
</ResponseField>

<ResponseField name="legend" type="boolean" default="true">
  Show color scale legend
</ResponseField>

<ResponseField name="borders" type="boolean" default="true">
  Show borders around heatmap cells
</ResponseField>

<ResponseField name="chart_options" type="options group">
  Chart configuration options

**Example:**
```
chart_options={
  color_scale = ["value1", "value2"]
  color_palette = ["value1", "value2"]
}
```

**Attributes:**
- color_scale: `array of strings` - Array of hex colors for the heatmap gradient. A single-color array auto-expands to [background, color].
- color_palette: `array of strings` - Deprecated. Use `color_scale`.

</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.
</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `graphic`, `visualMap`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For overrides scoped to the data series, use `echarts_series_options`.

**Example:**
```
echarts_options={
    tooltip={ position="top" }
    graphic=[{ type="text" }]
}
```
</ResponseField>

<ResponseField name="echarts_series_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into the chart series. Use for series-level styling the structured props do not expose.

**Example:**
```
echarts_series_options={
    itemStyle={ borderRadius=8 }
}
```
</ResponseField>

---

### Components Heatmap Layer (`docs/components/heatmap_layer.mdx`)

---
title: Heatmap Layer
description: Add a heatmap layer to a map showing density of lat/lng coordinates
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

````liquid
{% map %}
    {% heatmap_layer
        data="events"
        lat="latitude"
        lng="longitude"
    /%}
{% /map %}
````

## Examples

### Basic Heatmap

````liquid
{% map %}
    {% heatmap_layer
        data="events"
        lat="latitude"
        lng="longitude"
    /%}
{% /map %}
````

### Weighted Heatmap

````liquid
{% map %}
    {% heatmap_layer
        data="sales"
        lat="latitude"
        lng="longitude"
        weight="sum(revenue)"
    /%}
{% /map %}
````

### Custom Color Palette

````liquid
{% map %}
    {% heatmap_layer
        data="incidents"
        lat="latitude"
        lng="longitude"
        color_scale=["#ffffb2", "#fecc5c", "#fd8d3c", "#f03b20", "#bd0026"]
    /%}
{% /map %}
````

### Adjusted Radius and Intensity

````liquid
{% map %}
    {% heatmap_layer
        data="visits"
        lat="latitude"
        lng="longitude"
        weight="visit_count"
        radius=50
        intensity=2
    /%}
{% /map %}
````

## Attributes

<ResponseField name="data" type="string" required>
  Name of the table to query
</ResponseField>

<ResponseField name="filters" type="array">
  Array of filter IDs to apply
</ResponseField>

<ResponseField name="lat" type="string" required>
  Column name for latitude values
</ResponseField>

<ResponseField name="lng" type="string" required>
  Column name for longitude values
</ResponseField>

<ResponseField name="weight" type="string">
  Column or expression for weighting points in the heatmap (e.g., "sum(sales)"). Higher values create more intense heat
</ResponseField>

<ResponseField name="radius" type="number" default="30">
  Base radius of influence for each point in pixels (adjusts with zoom)
</ResponseField>

<ResponseField name="intensity" type="number" default="1">
  Intensity multiplier for the heatmap. Higher values create more pronounced heat
</ResponseField>

<ResponseField name="opacity" type="number" default="0.8">
  Opacity of the heatmap layer (0-1)
</ResponseField>

<ResponseField name="color_scale" type="array">
  Array of colors for the heatmap gradient, from lowest to highest density. A single-color array auto-expands to [background, color]. Defaults to the theme color scale.
</ResponseField>

<ResponseField name="color_palette" type="array">
  Deprecated. Use `color_scale`.
</ResponseField>

<ResponseField name="zoom_threshold" type="array">
  Zoom range [min, max] where this layer is visible (e.g., [0, 8] shows layer from zoom 0 to 8)
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>



## Allowed Parents

- [map](/components/map)

---

### Components Hidden In Print (`docs/components/hidden_in_print.mdx`)

---
title: Hidden In Print
description: Hide content when printing or generating PDFs, without otherwise affecting its layout
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}

## Examples

### Hidden in Print

````liquid
{% hidden_in_print %}
This content is hidden when printed.
{% /hidden_in_print %}
````

## Attributes

This component has no attributes.

---

### Components Histogram (`docs/components/histogram.mdx`)

---
title: Histogram
description: Display a histogram chart showing the distribution of values in a column.
keywords: ["distribution","frequency chart","frequency distribution"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% histogram
    data="demo.daily_orders"
    value="transactions"
    bin_count=30
/%}
````

## Examples

### Basic Usage



````liquid
{% histogram
    data="demo.daily_orders"
    value="transactions"
    bin_count=30
/%}
````

## Attributes

<ResponseField name="data" type="string" required>
  Name of the table to query
</ResponseField>

<ResponseField name="value" type="string" required>
  SQL expression for the values to create histogram for
</ResponseField>

<ResponseField name="series" type="string">
  Column name to group data by series
</ResponseField>

<ResponseField name="chart_options" type="options group">
  Chart configuration options

**Example:**
```
chart_options={
  color_palette = ["value1", "value2"]
}
```

**Attributes:**
- color_palette: `array of strings`

</ResponseField>

<ResponseField name="bin_count" type="number" default="20">
  Number of bins for the histogram (takes precedence over bin_width)
</ResponseField>

<ResponseField name="bin_width" type="number">
  Width of each bin (ignored if bin_count is specified)
</ResponseField>

<ResponseField name="fmt" type="string">
  Format for the column values displayed in bin ranges. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the histogram
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Info text to display in a tooltip next to the title. Can only be used with the title prop.
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="legend" type="boolean" default="true">
  Show legend
</ResponseField>

<ResponseField name="legend_location" type="string" default="top">
  Position of the legend (top or bottom)

**Allowed values:**
- `top`
- `bottom`
</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `graphic`, `visualMap`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For overrides scoped to the data series, use `echarts_series_options`.

**Example:**
```
echarts_options={
    tooltip={ position="top" }
    graphic=[{ type="text" }]
}
```
</ResponseField>

<ResponseField name="echarts_series_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into the chart series. Use for series-level styling the structured props do not expose.

**Example:**
```
echarts_series_options={
    itemStyle={ borderRadius=8 }
}
```
</ResponseField>

---

### Components Horizontal Bar Chart (`docs/components/horizontal_bar_chart.mdx`)

---
title: Horizontal Bar Chart
description: Display a horizontal bar chart
keywords: ["horizontal bar graph","row chart"]
---

{/* THIS FILE IS AUTOMATICALLY GENERATED - DO NOT MODIFY DIRECTLY */}



````liquid
{% horizontal_bar_chart
	data="demo.daily_orders"
	y="category"
	x="sum(total_sales)"
/%}
````

## Examples

### Basic Usage



````liquid
{% horizontal_bar_chart
	data="demo.daily_orders"
	y="category"
	x="sum(total_sales)"
/%}
````

## Attributes

<ResponseField name="data" type="string" required>
  Name of the table to query. Required unless every child series uses `metric="..."` — metric children resolve their own base from the metric view.
</ResponseField>

<ResponseField name="filters" type="array">
  IDs of filters to apply to the query
</ResponseField>

<ResponseField name="date_range" type="options group">
  Filter data to a time period. `date_range` is an OBJECT with `range` (the period) and optionally `date` (which column to filter on when the table has more than one). Shape: `date_range={ range="last 12 months" date="order_date" }`. `range` accepts predefined values (`last 7 days`, `month to date`), dynamic patterns (`Last 90 days`), custom windows (`2020-01-01 to 2023-03-01`), or partial ranges (`from 2020-01-01`, `until 2023-03-01`). Pass a plain string for `range` — the whole object is NOT a string.

**Example:**
```
date_range={
  range = "today"
  date = "string"
}
```

**Attributes:**
- range: `string` - Time period to filter. Use presets like 'last 7 days', dynamic patterns like 'Last 90 days', custom ranges like '2020-01-01 to 2023-03-01', or partial ranges like 'from 2020-01-01'.
  - **Allowed values:**
    - `today`
    - `yesterday`
    - `last 7 days`
    - `last 30 days`
    - `last 3 months`
    - `last 6 months`
    - `last 12 months`
    - `previous week`
    - `previous month`
    - `previous quarter`
    - `previous year`
    - `this week`
    - `this month`
    - `this quarter`
    - `this year`
    - `next week`
    - `next month`
    - `next quarter`
    - `next year`
    - `week to date`
    - `month to date`
    - `quarter to date`
    - `year to date`
    - `all time`
- date: `string` - Date column to filter on. Required when the data has multiple date columns.

</ResponseField>

<ResponseField name="date_grain" type="string">
  Bucket dates into a grain. Pass the raw date column as `x` and the chart truncates and groups for you. Temporal grains (`day`, `week`, `month`, `quarter`, `year`, `hour`) preserve the year — use for time-series. Seasonality grains (`day of week`, `day of month`, `day of year`, `week of year`, `month of year`, `quarter of year`) collapse across years — use for cyclical patterns like "which month sells most regardless of year".

**Allowed values:**
- `day`
- `week`
- `month`
- `quarter`
- `year`
- `hour`
- `day of week`
- `day of month`
- `day of year`
- `week of year`
- `month of year`
- `quarter of year`
</ResponseField>

<ResponseField name="handle_missing" type="string" default="connect">
  How to handle missing data points. "connect" auto-connects points (default), "gaps" shows visual breaks, "zero" fills with zeros.

**Allowed values:**
- `connect`
- `gaps`
- `zero`
</ResponseField>

<ResponseField name="x" type="string" required>
  Column name for x-axis (value, extends horizontally)
</ResponseField>

<ResponseField name="x_fmt" type="string">
  Format for x values. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="y_fmt" type="string">
  Format for y values and axis labels. See [Value Formatting](/core-concepts/value-formatting) for available formats.
</ResponseField>

<ResponseField name="series" type="string">
  Column name for series
</ResponseField>

<ResponseField name="point_title" type="string">
  Column name for individual point labels displayed at the top of the tooltip
</ResponseField>

<ResponseField name="title" type="string">
  Title to display above the component
</ResponseField>

<ResponseField name="subtitle" type="string">
  Subtitle to display below the title
</ResponseField>

<ResponseField name="info" type="string">
  Information tooltip text (can only be used with title). Displays an info icon next to the title.
</ResponseField>

<ResponseField name="info_link" type="string">
  URL to link the info text to (can only be used with info)
</ResponseField>

<ResponseField name="info_link_title" type="string">
  Create a custom link title for the info link, placed after the info text (can only be used with info_link)
</ResponseField>

<ResponseField name="refresh_interval" type="number">
  Time in seconds between automatic data refreshes (minimum 30). Overrides the page-level auto-refresh setting for this component.
</ResponseField>

<ResponseField name="where" type="string">
  Custom SQL WHERE condition to apply to the query. For date filters, use date_range instead.
</ResponseField>

<ResponseField name="having" type="string">
  Custom SQL HAVING condition to apply to the query after GROUP BY
</ResponseField>

<ResponseField name="limit" type="number">
  Maximum number of rows to return from the query. Note: When used with tables, limit will disable subtotals to prevent incomplete subtotal rows.
</ResponseField>

<ResponseField name="order" type="string">
  Column name(s) with optional direction (e.g. "column_name", "column_name desc")
</ResponseField>

<ResponseField name="qualify" type="string">
  Custom SQL QUALIFY condition to filter windowed results
</ResponseField>

<ResponseField name="width" type="number">
  Set the width of this component (in percent) relative to the page width
</ResponseField>

<ResponseField name="height" type="number">
  Set a fixed height for the chart in pixels
</ResponseField>

<ResponseField name="connect_group" type="string">
  Link this chart to others sharing the same id, syncing their tooltips, axis-pointer, and zoom
</ResponseField>

<ResponseField name="y_axis_options" type="options group">
  Configure the y-axis

**Example:**
```
y_axis_options={
  title = "string"
  title_position = "top"
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  interval = 0
}
```

**Attributes:**
- title: `string`
- title_position: `string` - Position of the axis title. "top" places it horizontally at the top, "side" places it vertically along the axis. Defaults to "side" for 100% stacked charts, "top" otherwise.
  - **Allowed values:**
    - `top`
    - `side`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.

</ResponseField>

<ResponseField name="x_axis_options" type="options group">
  Configure the x-axis

**Example:**
```
x_axis_options={
  title = "string"
  show_title = true
  label_wrap = true
  ticks = true
  baseline = true
  labels = true
  gridlines = true
  min = 0
  max = 0
  fit_to_data = true
  min_interval = "year"
  max_interval = "year"
  interval = 0
  label_rotate = 0
  title_arrow = true
  max_label_length = 0
}
```

**Attributes:**
- title: `string`
- show_title: `boolean` - When `true`, renders the auto-derived axis title (the x column name) below the chart. Ignored when `title` is set explicitly. Defaults to `false` — auto-derived column-name titles usually read as visual noise and the axis labels speak for themselves.
- label_wrap: `boolean`
- ticks: `boolean`
- baseline: `boolean`
- labels: `boolean` - Show/hide axis labels
- gridlines: `boolean` - Show/hide gridlines
- min: `number` - Minimum value for this axis (number for numeric axes, date string for date axes)
- max: `number` - Maximum value for this axis (number for numeric axes, date string for date axes)
- fit_to_data: `boolean` - Fit the axis to the data instead of including 0. Defaults to true for numeric x-axes, false otherwise.
- min_interval: `string` - Minimum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
- max_interval: `string` - Maximum interval between axis ticks for time-based axes. This option is a suggestion, the actual interval may differ.
  - **Allowed values:**
    - `year`
    - `quarter`
    - `month`
    - `week`
    - `day`
    - `hour`
- interval: `number` - Interval between axis ticks for numeric axes. This option is a suggestion, the actual interval may differ.
- label_rotate: `number` - Rotation angle of axis label in degrees. Positive values rotate clockwise, negative values rotate counter-clockwise.
- title_arrow: `boolean` - Show/hide the arrow (→) on the axis title
- max_label_length: `number` - Maximum character length for axis labels. Labels exceeding this length will be truncated with an ellipsis. Defaults to 20 characters when labels are rotated.

</ResponseField>

<ResponseField name="legend" type="boolean" default="true">
  Show legend. Studio's built-in legend renders a compact color swatch + series name. For chart-wide style overrides that need the legend to reflect them precisely (line width, custom symbols, richer styling), set `legend=false` and provide `legend={ show=true ... }` inside `echarts_options` to use ECharts' native legend instead.
</ResponseField>

<ResponseField name="legend_location" type="string" default="top">
  Position of the legend (top or bottom)

**Allowed values:**
- `top`
- `bottom`
</ResponseField>

<ResponseField name="series_order" type="array">
  Array of series names to define the order of series in the chart and legend. Series not in the array will appear after the ordered ones.
</ResponseField>

<ResponseField name="chart_options" type="options group">
  Additional chart configuration options

**Example:**
```
chart_options={
  color_palette = ["value1", "value2"]
  series_colors = {
    "key1" = "value1"
    "key2" = "value2"
  }
  top_padding = 0
}
```

**Attributes:**
- color_palette: `array of strings`
- series_colors: `map of key-value pairs`
- top_padding: `number` - Additional padding (in px) above the chart area to prevent labels from being cut off

</ResponseField>

<ResponseField name="echarts_options" type="map">
  Raw [ECharts options](https://echarts.apache.org/en/option.html) deep-merged over the chart's final configuration. Use for anything the structured props do not expose — `dataZoom`, `visualMap`, `graphic`, tooltip styling, and so on. Partial overrides win key-by-key without clobbering Studio's computed siblings. For per-series overrides, use `echarts_series_options` or the per-series `echarts_options` on a `line`/`bar`/etc. child.

**Example:**
```
echarts_options={
    tooltip={ position="top" }
    dataZoom=[{ type="slider" }]
}
```
</ResponseField>

<ResponseField name="echarts_series_options" type="map">
  Raw [ECharts series options](https://echarts.apache.org/en/option.html#series) deep-merged into every data series in the chart. Use when the same override should apply to all series. Skips reference lines/areas/points. For a single series, set `echarts_options` on the series child instead.

**Example:**
```
echarts_series_options={
    itemStyle={ borderRadius=8 }
    markLine={ data=[{ type="average" }] }
}
```
</ResponseField>

<ResponseField name="y" type="string" required>
  Column name for y-axis (category, extends vertically)
</ResponseField>

<ResponseField name="y_sort" type="string">
  Sort order for y-axis categories. Options: `asc` (alphabetical), `desc` (reverse alphabetical), `data` (preserve query order), or an array for custom order like `["A", "B", "C"]`

**Allowed values:**
- `asc`
- `desc`
- `data`
</ResponseField>

<ResponseField name="data_labels" type="options group">
  Label each point in the series with its value

**Example:**
```
data_labels={
  position = "above"
  fmt = "date"
  size = 0
  distance = 0
  rotate = 0
  color = "string"
  border_color = "string"
  show_overlap = true
}
```

**Attributes:**
- position: `string` - Position the label relative to its data point
  - **Allowed values:**
    - `above`
    - `below`
    - `left`
    - `right`
    - `middle`
- fmt: `string` - Format the label value. Defaults to series or axis fmt.
  - **Allowed values:** See [Value Formatting](/core-concepts/value-formatting) for all available formats.
- size: `number` - Font size in px
- distance: `number` - How far the label is from the data point
- rotate: `number` - Rotate each label (degrees)
- color: `string` - Change the text color of the labels
- border_color: `string` - Change the border color surrounding text labels, defaults to chart background
- show_overlap: `boolean` - Show labels for every point even when they overlap

</ResponseField>

<ResponseField name="tooltip_fields" type="array">
  Extra columns to include in the tooltip on hover. Each entry is `{ value, label?, fmt?, color_by_sign?, down_is_good? }`. See the [tooltip fields guide](/components/tooltip-fields) for examples.
</ResponseField>

<ResponseField name="bar_options" type="options group">
  

**Attributes:**
- color: `string`
- opacity: `number` - Between 0 and 1

</ResponseField>

<ResponseField name="stacked" type="boolean" default="true">
  Whether to stack the bars
</ResponseField>

## Allowed Children

- [reference_line](/components/reference_line)
- [reference_area](/components/reference_area)
- [reference_point](/components/reference_point)

---

--- METRICS ---
- Files Extracted: 64
- Estimated Token Budget: ~126505 tokens
- Canonical Reference: https://codewiki.google/github.com/evidence-dev/evidence
