# Range Bar Style

Canonical page: https://www.adaptabletools.com/docs/handbook-styled-column-range-bar

- The Range Bar Style renders a horizontal track between a **Min** and **Max** for each cell of a numeric column
- A marker is drawn at the cell value's position along the track
- An optional **Reference** object (`{ Value, Marker }`) renders a second marker (e.g. previous close, target, midpoint)
- `Min`, `Max` and `Reference.Value` can be numbers, column ids, or column-wide aggregates
- Optional **bands** (`CellRanges`) tint regions of the track for qualitative scales (e.g. red / amber / green SLA)

A Range Bar Style is a [Styled Column](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md) which renders a horizontal (or vertical) track in each cell.

Range Bar Styles can only be applied to Numeric Columns

Each cell renders a (thin) track from `Min` to `Max`.

There is also a marker at the cell value and an optional second marker for a reference value.

- Range Bar is a good fit for these kind of advanced, but common, scenario in AdapTable:
  - Stock price relative to its 52-week low / 52-week high
  - Today's value relative to bid / ask quotes
  - Forecast within an upper / lower confidence interval
  - Measured value within an SLA `[lowerBound, upperBound]`

The Range Bar Style is designed to answer these questions:

- "Where on the scale does this value sit?"
- "How does it compare to a reference?"

### Range Bar vs Bullet Chart vs Percent Bar: Which Styled Column should I use?

There are 3 "bar on a numeric scale" Styled Columns provided by AdapTable: Range Bar, Bullet Chart and Percent Bar.

All 3 overlap, but each has a different focus:

|                          | Range Bar                                                          | Percent Bar                               | Bullet Chart                                                 |
| ------------------------ | ------------------------------------------------------------------ | ----------------------------------------- | ------------------------------------------------------------ |
| Primary question         | "where between Min and Max — and how do I compare to a reference?" | "where does this value sit on the scale?" | "is this value meeting its target, and which band is it in?" |
| `CellRanges` colour the… | track background bands                                             | bar                                       | track background bands                                       |
| Cell-value visual        | marker on a thin track                                             | filled bar                                | filled bar                                                   |
| Comparative marker       | `Reference`                                                        | not supported                             | `Target` (one or many)                                       |
| Multiple bands shown     | yes — all bands visible behind the track                           | no — only the matching one                | yes — all bands always visible                               |

- Use Range Bar when there is a meaningful **interval** in your data (e.g. 52-week range, bid/ask spread)
- And you want to position the value within that range — optionally with a second reference

## Anatomy

A Range Bar cell consists of **three layers**, drawn back-to-front:

1. **Bands** (optional, drawn behind everything else) — coloured regions of the track defined by `CellRanges`

- Unlike Percent Bar (where ranges colour the bar), Range Bar ranges colour the **track background**
- This follows the same convention as [Bullet Chart](https://www.adaptabletools.com/docs/handbook-styled-column-bullet/index.md)

2. **Track** — the thin line representing the `[Min, Max]` interval. Styled via the `Track` group (`Track.Color`, `Track.Height`)
3. **Markers** — one for the cell value (`Marker`) and, optionally, a second marker for the reference value (`Reference.Marker`)

**Example: Range Bar: Showcase**

Three Range Bars side-by-side, each configured differently

- **GitHub Stars** — number bands either side of `Col-Avg` (red / green), **Diamond** value marker (purple), **Line** reference at `Col-Avg`
- **Closed PRs** — percentage bands in a teal palette, **Triangle** value marker (orange), **Dot** reference at `Col-Median` (white)
- **Weekly Issue Change** — no bands, just a thin track with a **Diamond** value marker (cyan) and a **Line** reference at `0`
- Non-range-bar columns (`language`, `has_pages`) sit between the charts as visual separators
- Each of these patterns is broken down in detail in the sections below

Demo project (Vanilla); the files without a marker are shown below:

```text
src/
  adaptableOptions.ts
  agGridModules.ts     [template]
  columnDefs.ts        [template]
  gridOptions.ts       [template]
  index.ts             [template]
  onAdaptableReady.ts  [template]
  rowData.ts           [template]
  styles.css           [template]
index.html             [template]
package.json           [template]
tsconfig.json          [template]
```

Files marked `[template]` are the same in every demo; see the [demo template](https://www.adaptabletools.com/llms/demo-template.md#vanilla).

**`src/adaptableOptions.ts`**

```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from './rowData';

export const adaptableOptions: AdaptableOptions<WebFramework> = {
  primaryKey: 'id',
  adaptableId: 'Range Bar Showcase',
  initialState: {
    Dashboard: {
      ModuleButtons: ['StyledColumn'],
    },
    Theme: {CurrentTheme: 'dark'},
    Layout: {
      CurrentLayout: 'Standard Layout',
      Layouts: [
        {
          Name: 'Standard Layout',
          TableColumns: [
            'name',
            'github_stars',
            'language',
            'closed_pr_count',
            'has_pages',
            'week_issue_change',
            'open_issues_count',
            'closed_issues_count',
            'updated_at',
            'pushed_at',
          ],
          ColumnSorts: [
            {
              ColumnId: 'github_stars',
              SortOrder: 'Desc',
            },
          ],
          AutoSizeColumns: true,
        },
      ],
    },
    StyledColumn: {
      StyledColumns: [
        {
          ColumnId: 'github_stars',
          Name: 'GitHub Stars range',
          RangeBarStyle: {
            Min: 'Col-Min',
            Max: 'Col-Max',
            RangeValueType: 'Number',
            CellRanges: [
              {Min: 'Col-Min', Max: 'Col-Avg', Color: 'rgba(220, 53, 69, 0.3)'},
              {Min: 'Col-Avg', Max: 'Col-Max', Color: 'rgba(40, 167, 69, 0.3)'},
            ],
            Reference: {
              Value: 'Col-Avg',
              Marker: {Shape: 'Line', Color: '#aaa', Size: 2},
            },
            Marker: {Shape: 'Diamond', Color: '#b042ff', Size: 8},
            Track: {Height: 4},
          },
        },
        {
          ColumnId: 'closed_pr_count',
          Name: 'Closed PRs spread bands',
          RangeBarStyle: {
            Min: 'Col-Min',
            Max: 'Col-Max',
            RangeValueType: 'Percentage',
            CellRanges: [
              {Min: 0, Max: 33, Color: 'rgba(56, 189, 248, 0.20)'},
              {Min: 33, Max: 66, Color: 'rgba(20, 184, 166, 0.30)'},
              {Min: 66, Max: 100, Color: 'rgba(13, 148, 136, 0.45)'},
            ],
            Reference: {
              Value: 'Col-Median',
              Marker: {Shape: 'Dot', Color: '#fff', Size: 6},
            },
            Marker: {Shape: 'Triangle', Color: '#fb923c', Size: 10},
            Track: {Height: 4},
          },
        },
        {
          ColumnId: 'week_issue_change',
          Name: 'Weekly Issue Change',
          RangeBarStyle: {
            Min: 'Col-Min',
            Max: 'Col-Max',
            Reference: {
              Value: 0,
              Marker: {
                Shape: 'Line',
                Color: 'var(--ab-color-foreground, #e2e2e2)',
                Size: 2,
              },
            },
            Marker: {Shape: 'Diamond', Color: '#22d3ee', Size: 8},
            Track: {Color: 'rgba(255, 255, 255, 0.35)', Height: 4},
          },
        },
      ],
    },
  },
};
```

## Styling the Bar

There are many elements that can be defined and configured when creating the Range part of the Range Bar.

### Bounds

There are three bound-related properties which drive the geometry of the chart:

| Property          | Required | Description                                                                            |
| ----------------- | -------- | -------------------------------------------------------------------------------------- |
| `Min`             | yes      | Lower bound of the track.                                                              |
| `Max`             | yes      | Upper bound of the track.                                                              |
| `Reference.Value` | no       | Optional reference value rendered as a second marker (sits inside the `Reference` group along with the marker styling). |

Each bound can be any of 3 types of value:

- **A number** — e.g. `0`, `100` — a fixed value shared by every row
- **A column id** — e.g. `'fiftyTwoWeekLow'` — the row's value in that column is used (different bound per row)
- **A dynamic endpoint** — `'Col-Min'`, `'Col-Max'`, `'Col-Avg'`, `'Col-Median'` — a column-wide aggregate computed across the visible rows

- Dynamic endpoints recompute automatically when row data changes
- This ensures the track and bands keep adapting to the live data without you having to wire up the numbers

Use **column ids** when each row carries its own interval (e.g. price between 52-week low and high), and **dynamic endpoints** when the track should span the visible column.

**Example: Range Bar: Column Bounds**

Per-row Min/Max from columns with a reference marker

- **Price** — `Min` / `Max` from **52W Low** and **52W High**; **Prev Close** as the reference line
- Diamond value marker and line reference marker; **Overflow** draws markers outside the track (see **BETA** above its high)
- Cell label shows value and **percentage along that row's scale**; tooltip includes both

Demo project (Vanilla); the files without a marker are shown below:

```text
src/
  adaptableOptions.ts
  agGridModules.ts     [template]
  columnDefs.ts
  gridOptions.ts       [template]
  index.ts             [template]
  onAdaptableReady.ts  [template]
  rowData.ts
  styles.css           [template]
index.html             [template]
package.json           [template]
tsconfig.json          [template]
```

Files marked `[template]` are the same in every demo; see the [demo template](https://www.adaptabletools.com/llms/demo-template.md#vanilla).

**`src/adaptableOptions.ts`**

```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {MarketQuote} from './rowData';

export const adaptableOptions: AdaptableOptions<MarketQuote> = {
  primaryKey: 'id',
  adaptableId: 'Range Bar Column Bounds',
  initialState: {
    Dashboard: {
      ModuleButtons: ['StyledColumn'],
    },
    Theme: {CurrentTheme: 'dark'},
    Layout: {
      CurrentLayout: 'Standard Layout',
      Layouts: [
        {
          Name: 'Standard Layout',
          TableColumns: [
            'symbol',
            'price',
            'weekLow',
            'weekHigh',
            'previousClose',
          ],
          AutoSizeColumns: true,
        },
      ],
    },
    StyledColumn: {
      StyledColumns: [
        {
          ColumnId: 'price',
          Name: 'Price vs 52-week range',
          RangeBarStyle: {
            Min: 'weekLow',
            Max: 'weekHigh',
            Reference: {
              Value: 'previousClose',
              Marker: {
                Shape: 'Line',
                Color: 'var(--ab-color-foreground, #e2e2e2)',
                Size: 2,
              },
            },
            Marker: {
              Shape: 'Diamond',
              Color: 'var(--ab-color-accent, #07c)',
              Size: 8,
            },
            Track: {Color: 'rgba(255, 255, 255, 0.35)', Height: 4},
            CellTextProperties: {
              CellTextLayout: {
                CellValue: {Horizontal: 'Left', Vertical: 'Below'},
                PercentValue: {Horizontal: 'Right', Vertical: 'Below'},
              },
            },
            ToolTipText: ['CellValue', 'PercentageValue'],
            OutOfRange: {Mode: 'Overflow', Color: '#ff6b6b'},
          },
        },
      ],
    },
  },
};
```
**`src/columnDefs.ts`**

```ts
import {ColDef} from 'ag-grid-enterprise';
import {MarketQuote} from './rowData';

export const columnDefs: ColDef<MarketQuote>[] = [
  {field: 'id', hide: true, cellDataType: 'number'},
  {field: 'symbol', headerName: 'Symbol', cellDataType: 'text'},
  {field: 'price', headerName: 'Price', cellDataType: 'number'},
  {field: 'weekLow', headerName: '52W Low', cellDataType: 'number'},
  {field: 'weekHigh', headerName: '52W High', cellDataType: 'number'},
  {field: 'previousClose', headerName: 'Prev Close', cellDataType: 'number'},
];
```
**`src/rowData.ts`**

```ts
export interface MarketQuote {
  id: number;
  symbol: string;
  price: number;
  weekLow: number;
  weekHigh: number;
  previousClose: number;
}

export const rowData: MarketQuote[] = [
  {id: 1, symbol: 'ACME', price: 42.5, weekLow: 38, weekHigh: 48, previousClose: 41.2},
  {id: 2, symbol: 'BETA', price: 105, weekLow: 80, weekHigh: 100, previousClose: 92},
  {id: 3, symbol: 'GAMMA', price: 18.2, weekLow: 22, weekHigh: 30, previousClose: 24},
  {id: 4, symbol: 'DELTA', price: 67, weekLow: 60, weekHigh: 75, previousClose: 71},
  {id: 5, symbol: 'EPSI', price: 9.5, weekLow: 12, weekHigh: 18, previousClose: 14},
  {id: 6, symbol: 'ZETA', price: 51, weekLow: 45, weekHigh: 55, previousClose: 49},
  {id: 7, symbol: 'THETA', price: 88, weekLow: 70, weekHigh: 85, previousClose: 78},
  {id: 8, symbol: 'IOTA', price: 33, weekLow: 30, weekHigh: 40, previousClose: 36},
];
```

### Markers

As noted there are 2 markers:

- one for the cell value, configured by `Marker`
- one (optionally) for the reference value, configured by `Reference.Marker`

Both markers share the same `BarChartMarker` shape (the unified marker type used by Range Bar, Bullet Chart and Percent Bar):

| Property | Type                                   | Description                                                                               |
| -------- | -------------------------------------- | ----------------------------------------------------------------------------------------- |
| `Shape`  | `'Line'\|'Triangle'\|'Dot'\|'Diamond'` | Marker shape; defaults to `'Diamond'` for value marker and `'Line'` for reference marker. |
| `Color`  | `string`                               | Marker colour; defaults follow the Current Theme                                          |
| `Size`   | `number`                               | Line thickness (for `'Line'`) or shape size in px.                                        |

If the `Reference` object is unset, no second marker is drawn (and `Reference.Marker` is ignored).

### Bands

A Range Bar can contain any number of Bands.

Each band has `Min`, `Max` and `Color` and is drawn **behind** the track. Bands can be:

The Range Bar Style uses the same band model as the [Bullet Chart Style](https://www.adaptabletools.com/docs/handbook-styled-column-bullet/index.md)

- **Numeric** — hard-coded numbers, or the dynamic endpoints `Col-Min`, `Col-Max`, `Col-Avg`, `Col-Median`.
- **Percentage** — set `RangeValueType: 'Percentage'` to interpret `Min` / `Max` as 0–100 values that resolve against the column's own min/max.

#### Numeric Bands

Use **Number** bands when thresholds are absolute values — fixed numbers or dynamic endpoints such as `Col-Min`, `Col-Avg` and `Col-Max`.

**Example: Range Bar: Number Bands**

Column-wide scale with numeric bands behind the track

- **GitHub Stars** — `Min` / `Max` are **Col-Min** / **Col-Max**; **Col-Avg** is the reference marker
- Two **Number** bands tint the track below and above the column average (all bands stay visible)

Demo project (Vanilla); the files without a marker are shown below:

```text
src/
  adaptableOptions.ts
  agGridModules.ts     [template]
  columnDefs.ts        [template]
  gridOptions.ts       [template]
  index.ts             [template]
  onAdaptableReady.ts  [template]
  rowData.ts           [template]
  styles.css           [template]
index.html             [template]
package.json           [template]
tsconfig.json          [template]
```

Files marked `[template]` are the same in every demo; see the [demo template](https://www.adaptabletools.com/llms/demo-template.md#vanilla).

**`src/adaptableOptions.ts`**

```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from './rowData';

export const adaptableOptions: AdaptableOptions<WebFramework> = {
  primaryKey: 'id',
  adaptableId: 'Range Bar Aggregate Bands',
  initialState: {
    Dashboard: {
      ModuleButtons: ['StyledColumn'],
    },
    Theme: {CurrentTheme: 'dark'},
    Layout: {
      CurrentLayout: 'Standard Layout',
      Layouts: [
        {
          Name: 'Standard Layout',
          TableColumns: [
            'name',
            'github_stars',
            'language',
            'closed_pr_count',
            'open_issues_count',
          ],
          ColumnSorts: [{ColumnId: 'github_stars', SortOrder: 'Desc'}],
          AutoSizeColumns: true,
        },
      ],
    },
    StyledColumn: {
      StyledColumns: [
        {
          ColumnId: 'github_stars',
          Name: 'GitHub Stars range',
          RangeBarStyle: {
            Min: 'Col-Min',
            Max: 'Col-Max',
            Reference: {
              Value: 'Col-Avg',
              Marker: {Shape: 'Line', Color: '#aaa', Size: 2},
            },
            RangeValueType: 'Number',
            CellRanges: [
              {Min: 'Col-Min', Max: 'Col-Avg', Color: 'rgba(220, 53, 69, 0.3)'},
              {Min: 'Col-Avg', Max: 'Col-Max', Color: 'rgba(40, 167, 69, 0.3)'},
            ],
            Marker: {Shape: 'Diamond', Color: '#b042ff', Size: 8},
            Track: {Height: 4},
          },
        },
      ],
    },
  },
};
```

#### Percentage Bands

Use **Percentage** bands when each band is a slice of the column's value span (`0`–`100`), without hard-coding the underlying numbers.

**Example: Range Bar: Percentage Bands**

Percentage bands on a column-wide track

- **Closed PRs** — three **Percentage** bands (`0`–`33`, `33`–`66`, `66`–`100`) behind the track
- **Col-Median** reference (dot marker); column **Col-Min** / **Col-Max** define the track ends

Demo project (Vanilla); the files without a marker are shown below:

```text
src/
  adaptableOptions.ts
  agGridModules.ts     [template]
  columnDefs.ts        [template]
  gridOptions.ts       [template]
  index.ts             [template]
  onAdaptableReady.ts  [template]
  rowData.ts           [template]
  styles.css           [template]
index.html             [template]
package.json           [template]
tsconfig.json          [template]
```

Files marked `[template]` are the same in every demo; see the [demo template](https://www.adaptabletools.com/llms/demo-template.md#vanilla).

**`src/adaptableOptions.ts`**

```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from './rowData';

export const adaptableOptions: AdaptableOptions<WebFramework> = {
  primaryKey: 'id',
  adaptableId: 'Range Bar Percentage Bands',
  initialState: {
    Dashboard: {
      ModuleButtons: ['StyledColumn'],
    },
    Theme: {CurrentTheme: 'dark'},
    Layout: {
      CurrentLayout: 'Standard Layout',
      Layouts: [
        {
          Name: 'Standard Layout',
          TableColumns: [
            'name',
            'closed_pr_count',
            'language',
            'github_stars',
            'open_issues_count',
          ],
          AutoSizeColumns: true,
        },
      ],
    },
    StyledColumn: {
      StyledColumns: [
        {
          ColumnId: 'closed_pr_count',
          Name: 'Closed PRs spread bands',
          RangeBarStyle: {
            Min: 'Col-Min',
            Max: 'Col-Max',
            Reference: {
              Value: 'Col-Median',
              Marker: {Shape: 'Dot', Color: '#fff', Size: 6},
            },
            RangeValueType: 'Percentage',
            CellRanges: [
              {Min: 0, Max: 33, Color: 'rgba(40, 167, 69, 0.35)'},
              {Min: 33, Max: 66, Color: 'rgba(255, 193, 7, 0.35)'},
              {Min: 66, Max: 100, Color: 'rgba(220, 53, 69, 0.35)'},
            ],
            Marker: {Shape: 'Triangle', Color: '#91cc75', Size: 8},
            Track: {Height: 4},
          },
        },
      ],
    },
  },
};
```

Bands are entirely optional — set `BackColor` instead if you just want a flat tint behind the track.

### Vertical Bars

By default Range Bars are drawn horizontally - low values on the left, high values on the right.

However it is possible to stack the track **vertically** - low values at bottom of cell and high values at the top.

In vertical mode `Track.Height` is interpreted as the track's _short_ axis (its width)

This is done by setting the `Orientation` property to `'Vertical'`.

- As with [Bullet Chart Style](https://www.adaptabletools.com/docs/handbook-styled-column-bullet/index.md), vertical orientation reads best in tall row heights
- Set `gridOptions.rowHeight` (or `getRowHeight`) accordingly to achieve the best visual effect

**Example: Range Bar: Vertical**

Vertical track with tall row height

- **GitHub Watchers** — `Orientation: 'Vertical'` with **Percentage** bands and **Col-Median** reference
- `gridOptions.rowHeight` set to **72** so the vertical track is readable; narrow column width

Demo project (Vanilla); the files without a marker are shown below:

```text
src/
  adaptableOptions.ts
  agGridModules.ts     [template]
  columnDefs.ts        [template]
  gridOptions.ts
  index.ts             [template]
  onAdaptableReady.ts  [template]
  rowData.ts           [template]
  styles.css           [template]
index.html             [template]
package.json           [template]
tsconfig.json          [template]
```

Files marked `[template]` are the same in every demo; see the [demo template](https://www.adaptabletools.com/llms/demo-template.md#vanilla).

**`src/adaptableOptions.ts`**

```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from './rowData';

export const adaptableOptions: AdaptableOptions<WebFramework> = {
  primaryKey: 'id',
  adaptableId: 'Range Bar Vertical',
  initialState: {
    Dashboard: {
      ModuleButtons: ['StyledColumn'],
    },
    Theme: {CurrentTheme: 'dark'},
    Layout: {
      CurrentLayout: 'Standard Layout',
      Layouts: [
        {
          Name: 'Standard Layout',
          TableColumns: [
            'name',
            'github_watchers',
            'language',
            'github_stars',
            'closed_pr_count',
          ],
          ColumnSorts: [{ColumnId: 'github_watchers', SortOrder: 'Desc'}],
          ColumnSizing: {github_watchers: {Width: 72}},
          AutoSizeColumns: true,
        },
      ],
    },
    StyledColumn: {
      StyledColumns: [
        {
          ColumnId: 'github_watchers',
          Name: 'GitHub Watchers vertical',
          RangeBarStyle: {
            Orientation: 'Vertical',
            Min: 'Col-Min',
            Max: 'Col-Max',
            Reference: {
              Value: 'Col-Median',
              Marker: {Shape: 'Line', Color: '#ccc', Size: 2},
            },
            RangeValueType: 'Percentage',
            CellRanges: [
              {Min: 0, Max: 50, Color: 'rgba(220, 53, 69, 0.35)'},
              {Min: 50, Max: 100, Color: 'rgba(40, 167, 69, 0.35)'},
            ],
            Marker: {Shape: 'Diamond', Color: '#5b9bd5', Size: 8},
            Track: {Height: 6},
            CellTextProperties: {
              CellTextLayout: {
                CellValue: {Horizontal: 'Left', Vertical: 'Below'},
              },
            },
          },
        },
      ],
    },
  },
};
```
**`src/gridOptions.ts`**

```ts
import {GridOptions, themeBalham} from 'ag-grid-enterprise';

import {rowData, WebFramework} from './rowData';
import {columnDefs} from './columnDefs';

export const gridOptions: GridOptions<WebFramework> = {
  theme: themeBalham,
  rowHeight: 72,
  defaultColDef: {
    resizable: true,
    sortable: true,
    editable: true,
    filter: true,
    floatingFilter: true,
  },
  columnDefs: columnDefs,
  rowData: rowData,
  sideBar: true,
  suppressMenuHide: true,
  columnMenu: 'new',
  cellSelection: true,
  statusBar: {
    statusPanels: [
      {statusPanel: 'agTotalRowCountComponent', align: 'left'},
      {statusPanel: 'agFilteredRowCountComponent'},
      {
        key: 'Center Panel',
        statusPanel: 'AdaptableStatusPanel',
        align: 'center',
      },
    ],
  },
};
```

## Styling the Cell

As with all Styled Columns there are many options available to style the cell that contains the Range Bar.

### Cell Text

Two text tokens can be drawn around the bar — independently, and each at its own position. They are configured under the `CellTextProperties` group:

| Property                        | Type                       | Description                                            |
| ------------------------------- | -------------------------- | ------------------------------------------------------ |
| `CellTextLayout.CellValue`      | `BarChartCellTextPlacement` | Placement of the formatted cell value.                 |
| `CellTextLayout.PercentValue`   | `BarChartCellTextPlacement` | Placement of the percent value (cell value's position along the `[Min, Max]` scale, as 0–100%). |

A `BarChartCellTextPlacement` is `{ Horizontal, Vertical }` where:

- `Horizontal` — `'Left'` (default), `'Center'` or `'Right'`
- `Vertical` — `'Above'`, `'Below'` (default) or `'Merged'` (overlaid on the track)

- A token is rendered **only when its key is present** in `CellTextLayout`
- When both tokens land on the **same horizontal slot at the same vertical position** they are concatenated with a single space (Cell Value first, then Percent Value)
- This means you can independently place the value above the bar (e.g. `CellValue: { Horizontal: 'Left', Vertical: 'Above' }`) and the percentage below (e.g. `PercentValue: { Horizontal: 'Right', Vertical: 'Below' }`) on the same Range Bar

### Percentage Value

The percent value shows where the cell value sits along **that row's resolved** `[Min, Max]` interval — the same scale used to position the marker.

- It is **not** the column's own min/max percentile (as used by Gradient band percentages)
- It is always relative to the **row's** resolved `Min` and `Max` for that cell

AdapTable computes it as:

```
clamp((value − min) / (max − min), 0, 1) × 100
```

and displays it as a **whole-number percent** (e.g. `67%`).

- The percentage is **always clamped to 0–100%** for display
- This occurs even when `OutOfRange.Mode` is `'Overflow'` and the marker is drawn outside the track

### Tooltip

The `ToolTipText` property sets what is displayed in the Tooltip — cell value, percent value or both. It accepts the tokens `'CellValue'` and/or `'PercentageValue'`.

If both Cell and Percent values are enabled, the percent is appended in parentheses (e.g. `142.50 (67%)`)

## Out Of Range Behaviour

Sometimes a cell value falls outside the `[Min, Max]` range.

When this happens, the `OutOfRange` group decides what the behaviour should be. It has 2 properties:

- `OutOfRange.Mode` — what to do with the marker (one of 3 values, see below)
- `OutOfRange.Color` — optional marker colour override used by `Mode: 'Clamp'`

- This only affects the Cell Marker
- The reference marker is unaffected by this setting

The 3 values available for `OutOfRange.Mode` are:

- **`'Clamp'`** (default) — clamp the marker to the nearest end of the track

In this scenario, use `OutOfRange.Color` to recolour the marker so off-scale rows stand out

- **`'Overflow'`** — draw the marker at its true position, even if that's outside the track
- **`'Hide'`** — omit the cell-value marker entirely

Compare **`Overflow`** and **`Clamp`** on the same values — several repos exceed the fixed `0`–`800` scale.

**Example: Range Bar: Out Of Range**

Overflow vs clamp when values exceed Max

- **Open Issues** — fixed scale `0`–`800`, reference **400**; **`OutOfRange: { Mode: 'Overflow' }`** draws the marker past the track end
- **Open Issues (clamp)** — same numbers; **`OutOfRange: { Mode: 'Clamp', Color: '#fb7185' }`** pins the marker to the edge and highlights off-scale rows

Demo project (Vanilla); the files without a marker are shown below:

```text
src/
  adaptableOptions.ts
  agGridModules.ts     [template]
  columnDefs.ts
  gridOptions.ts       [template]
  index.ts             [template]
  onAdaptableReady.ts  [template]
  rowData.ts           [template]
  styles.css           [template]
index.html             [template]
package.json           [template]
tsconfig.json          [template]
```

Files marked `[template]` are the same in every demo; see the [demo template](https://www.adaptabletools.com/llms/demo-template.md#vanilla).

**`src/adaptableOptions.ts`**

```ts
import {AdaptableOptions} from '@adaptabletools/adaptable';
import {WebFramework} from './rowData';

export const adaptableOptions: AdaptableOptions<WebFramework> = {
  primaryKey: 'id',
  adaptableId: 'Range Bar Out Of Range',
  initialState: {
    Dashboard: {
      ModuleButtons: ['StyledColumn'],
    },
    Theme: {CurrentTheme: 'dark'},
    Layout: {
      CurrentLayout: 'Standard Layout',
      Layouts: [
        {
          Name: 'Standard Layout',
          TableColumns: ['name', 'open_issues_count', 'open_issues_clamp'],
          AutoSizeColumns: true,
        },
      ],
    },
    StyledColumn: {
      StyledColumns: [
        {
          ColumnId: 'open_issues_count',
          Name: 'Open Issues overflow',
          RangeBarStyle: {
            Min: 0,
            Max: 800,
            Reference: {
              Value: 400,
              Marker: {Shape: 'Line', Color: '#fbbf24', Size: 2},
            },
            Marker: {Shape: 'Diamond', Color: '#22d3ee', Size: 10},
            Track: {Color: 'rgba(255, 255, 255, 0.45)', Height: 4},
            OutOfRange: {Mode: 'Overflow'},
            CellTextProperties: {
              CellTextLayout: {
                CellValue: {Horizontal: 'Left', Vertical: 'Below'},
              },
            },
          },
        },
        {
          ColumnId: 'open_issues_clamp',
          Name: 'Open Issues clamp',
          RangeBarStyle: {
            Min: 0,
            Max: 800,
            Reference: {
              Value: 400,
              Marker: {Shape: 'Line', Color: '#fbbf24', Size: 2},
            },
            Marker: {Shape: 'Diamond', Color: '#22d3ee', Size: 10},
            Track: {Color: 'rgba(255, 255, 255, 0.45)', Height: 4},
            OutOfRange: {Mode: 'Clamp', Color: '#fb7185'},
            CellTextProperties: {
              CellTextLayout: {
                CellValue: {Horizontal: 'Left', Vertical: 'Below'},
              },
            },
          },
        },
      ],
    },
  },
};
```
**`src/columnDefs.ts`**

```ts
import {ColDef} from 'ag-grid-enterprise';
import {WebFramework} from './rowData';

export const columnDefs: ColDef<WebFramework>[] = [
  {field: 'id', hide: true, cellDataType: 'number'},
  {field: 'name', headerName: 'Name', cellDataType: 'text'},
  {
    field: 'open_issues_count',
    headerName: 'Open Issues',
    cellDataType: 'number',
  },
  {
    colId: 'open_issues_clamp',
    headerName: 'Open Issues (clamp)',
    cellDataType: 'number',
    valueGetter: params => params.data?.open_issues_count,
  },
];
```

### What happens if AdapTable cannot draw a valid scale in the Cell

The Range Bar renderer is **only** used when a valid scale can be drawn and the row is in scope.

When that is not possible, the cell falls back to plain content.

However what is rendered depends on the reason **why** the Range Bar could not be rendered:

| Situation                                                                                                   | What renders                                                                                |
| ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
| Row kind **excluded** by [Row Scope](#row-scope)                                                            | The formatted **cell value** as plain text (no track or markers)                            |
| Cell value is `null` / `undefined`                                                                          | **Nothing** — an empty cell                                                                 |
| Cell value is **non-numeric**                                                                               | The formatted cell value as **plain text**                                                  |
| `Min` or `Max` cannot be resolved for the row (missing column value, unknown column id, non-numeric source) | The formatted cell value as **plain text**                                                  |
| Resolved `Max` ≤ `Min` for the row                                                                          | The formatted cell value as **plain text**                                                  |
| `Reference` cannot be resolved or is non-numeric                                                            | The track and value marker still render; the **reference marker is omitted**                |
| Styled Column **`IsSuspended`** is `true`                                                                   | AdapTable stops using the Range Bar renderer — the column shows its normal formatted values |

## Row Scope

Users can decide which kinds of Rows will include the Range Bar Style.

See  [Styled Column Row Scope](https://www.adaptabletools.com/docs/handbook-styled-column-overview/index.md#row-scope) for details of the types of Rows which can be included / excluded from a Styled Column

## Defining Range Bars

Range Bar Styles are defined as part of the Styled Column Initial State.

### Providing a Range Bar Style in Styled Column State

- Supply `ColumnId` of the Styled Column
- Give the Styled Column a unique `Name`
- Add a `RangeBarStyle` object

`Min` and `Max` are required; `Reference` is optional. `Min` and `Max` each accept a number, a column id, or a dynamic endpoint (`Col-Min`, `Col-Max`, `Col-Avg`, `Col-Median`). When set, `Reference` is an object `{ Value, Marker }` — `Reference.Value` accepts the same forms as `Min` / `Max`.

Use `CellRanges` to add qualitative bands behind the track (same model as Bullet Chart). Omit them and the track sits on a plain background (optionally tinted via `BackColor`).

- `Marker` — shape / colour / size of the cell-value marker
- `Reference.Marker` — same shape, lives inside the `Reference` object
- `Track` — appearance of the track itself (`Track.Color`, `Track.Height`)

- `CellTextProperties.CellTextLayout` — per-token `CellValue` / `PercentValue` placements (each with its own `Horizontal` + `Vertical`)
- `ToolTipText` — tokens shown in the AG Grid tooltip
- `OutOfRange` — `{ Mode: 'Clamp' | 'Overflow' | 'Hide', Color? }`

```js [[1, 5, "Name"], [1, 6, "ColumnId"], [1, 7, "RangeBarStyle"], [2, 8, "Min"], [2, 9, "Max"], [2, 10, "Reference"], [3, 18, "CellRanges"], [4, 30, "Marker"], [4, 10, "Reference"], [4, 35, "Track"], [5, 39, "CellTextProperties"], [5, 44, "OutOfRange"]]
const initialState: InitialState = {
  StyledColumn: {
    StyledColumns: [
      {
        Name: '52-week Range',
        ColumnId: 'price',
        RangeBarStyle: {
          Min: 'fiftyTwoWeekLow',
          Max: 'fiftyTwoWeekHigh',
          Reference: {
            Value: 'previousClose',
            Marker: {
              Shape: 'Line',
              Color: 'var(--ab-color-foreground)',
              Size: 2,
            },
          },
          CellRanges: [
            {
              Min: 'Col-Min',
              Max: 'Col-Avg',
              Color: 'rgba(220, 53, 69, 0.25)',
            },
            {
              Min: 'Col-Avg',
              Max: 'Col-Max',
              Color: 'rgba(40, 167, 69, 0.25)',
            },
          ],
          Marker: {
            Shape: 'Diamond',
            Color: 'var(--ab-color-accent)',
            Size: 8,
          },
          Track: {
            Color: 'var(--ab-color-foreground)',
            Height: 4,
          },
          CellTextProperties: {
            CellTextLayout: {
              CellValue: { Horizontal: 'Left', Vertical: 'Below' },
            },
          },
          OutOfRange: {
            Mode: 'Clamp',
            Color: 'red',
          },
        },
      },
    ],
  },
};
```

## Using Range Bars

Range Bar Styles can be created at run-time using the Styled Column UI Wizard; this is available from:

- the **Styled Column** section in the [Settings Panel](https://www.adaptabletools.com/docs/ui-settings-panel/index.md)
- **Create Range Bar** / **Edit Range Bar** in the [Column Menu](https://www.adaptabletools.com/docs/ui-column-menu/index.md) on a **numeric** column

### Creating a Range Bar Column Style using the Styled Column Wizard

The Wizard guides you through the following steps:

In the **Settings** step:

- Enter a **Name** for the Styled Column (must be unique within the Grid)
- Pick **Range Bar** from the list of Styled Column Types

The **Scope** step is shared by every Styled Column. Use it to:

- Pick the **numeric Column** whose values should be plotted on the track
- Choose which **row kinds** the Range Bar renders on: **Data**, **Group**, **Summary** and **Total**

By default **Data**, **Summary** and **Total** are included, and **Group** rows are excluded — see [Row Scope](#row-scope)

The first Range Bar–specific step configures the scale and optional qualitative bands.

A **live preview** updates as you edit.

Until a column is chosen in **Scope**, the step prompts you to select a column first.

The step is organised into two cards:

- **Bounds**
  - **Min** and **Max** (required) — each can be a **Fixed Number**, another **numeric column** on the row, or a column-wide aggregate (**Column Min**, **Column Max**, **Column Average**, **Column Median**)
  - **Reference** (optional) — same choices as Min/Max, or **None** to omit the second marker
  - When both Min and Max are fixed numbers, the wizard forces **Max** to be greater than **Min**

- **Ranges** (optional)
  - Add coloured **bands** (`CellRanges`) drawn **behind** the track — same band editor as [Bullet Chart](https://www.adaptabletools.com/docs/handbook-styled-column-bullet/index.md)
  - Choose **Numeric** or **Percentage** range value type; leave empty for a plain track (you can still tint the cell via **Back Colour** on the next step)

- **Create Range Bar** from the Column Menu seeds **Min** / **Max** as **Column Min** and **Column Max**
- This means that Style step opens with a valid, renderable configuration you can refine

The **Display** step configures how the Range Bar is drawn and labelled.

The **live preview** continues to update as you edit.

The step is organised into five cards:

- **Value Marker** — **Shape** (`Diamond`, `Line`, `Triangle`, `Dot`), **Colour** and **Size** for the marker at the cell value

- **Reference Marker** — same fields for the reference value; enabled only when **Reference** is set on the **Style** step (otherwise the card explains how to add one)

- **Track**
  - **Orientation** — **Horizontal** (default) or **Vertical** (reads best with a tall row height; the wizard shows a tip when vertical is selected)
  - **Track Colour** and **Track Height** (horizontal) or **Track Width** (vertical)
  - **Back Colour** — optional flat tint behind the track when you are not using bands

- **Out of Range** — **Behaviour** when the cell value falls outside `[Min, Max]`: **Clamp to edge** (default), **Show outside**, or **Hide marker**; when clamping, an optional **Out-of-range Colour** highlights off-scale values

- **Text & Tooltip**
  - **Cell Display** — **Cell Value** and/or **Percent Value** (position along the scale)
  - **Cell Display Position** — **Above Bar**, **Below Bar** (default), or **Merged** (overlaid on the track)
  - **Tooltip Display** — same **Cell Value** / **Percent Value** choices for the AG Grid tooltip

Two further wizard steps — **Tags** (when the workspace has tags enabled) and **Summary** (a read-only review of every previous step, including the live Range Bar preview) — are shared by all AdapTable modules and not specific to Range Bar Columns.

### FAQ

**Can Min, Max or Reference come from another column?**
Yes. Pass a column id (e.g. `'fiftyTwoWeekLow'`) and the row's value in that column is used.
You can also use dynamic endpoints (`'Col-Min'`, `'Col-Max'`, `'Col-Avg'`, `'Col-Median'`).

**What happens if the cell value is outside `[Min, Max]`?**
That's controlled by `OutOfRange.Mode`. The default is `'Clamp'`, which pins the marker to the nearest end of the track; use `OutOfRange.Color` to highlight those rows. `'Overflow'` draws the marker outside the track at its true position; `'Hide'` omits it entirely.

**Can the bar be drawn vertically?**
Yes — set `Orientation: 'Vertical'`. Lower values appear at the bottom of the cell and higher values at the top.
Use a tall row height (we recommend at least 60px) so the track is readable.

**Do I need both Min and Max to be set?**
Yes — `Min` and `Max` are the only required properties; without them there's no scale to draw a marker on.
`Reference`, on the other hand, is fully optional.

**Why does my chart look the same in light and dark mode?**
By default `Marker.Color` resolves to the theme's accent colour and `Reference.Marker.Color` / `Track.Color` to the foreground colour, so they follow the active theme. Override them with explicit colours if you need pixel-exact control.

**What if a bound column has no value on a row?**
When `Min`, `Max` or `Reference.Value` is a column id, AdapTable reads that column on the same row.
If the value is missing or not numeric, that bound cannot be resolved.
For `Min` or `Max`, the cell falls back to plain formatted text.
For `Reference.Value` only, the track still draws but the reference marker is skipped.

**What happens if the Styled Column is suspended?**
When `IsSuspended` is `true`, AdapTable stops using the Range Bar renderer for that column and shows normal formatted cell values instead.
