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

# Defining a Panel

> Reading and writing panel definitions: structure, layouts, positioning, and lifecycle.

<Frame caption="A panel definition and its live result, side by side in the Dashboard Manager">
  <img src="https://mintcdn.com/coreflux/ry-30sFxFVWzN72U/images/dashboard/manager/code-dashboard.png?fit=max&auto=format&n=ry-30sFxFVWzN72U&q=85&s=29c5b64f6d927ac71385def4b80027bb" alt="The Coreflux HUB Dashboard Manager showing a panel's LoT definition next to the rendered live panel" width="1914" height="930" data-path="images/dashboard/manager/code-dashboard.png" />
</Frame>

Every dashboard is one `DEFINE PANEL` block, written in the Dashboard Manager or generated by the AI Assistant. The block names the panel, sets a few panel-wide attributes, and lists the components it contains — this page walks through each part.

<Tip>
  **Like a recipe card for a screen.** The header says what the dish is and how the table is set (title, layout); each ingredient line below adds one widget and says where its data comes from.
</Tip>

***

Start with the smallest complete panel, then each section below adds one concept: reading the syntax, layouts, positioning, and lifecycle.

## Panel skeleton

A panel opens with `DEFINE PANEL`, four panel-level attributes, then one or more components:

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE PANEL MyPanel
WITH VISIBILITY PUBLIC
WITH STATE PUBLISHED
WITH TITLE "My Panel"
WITH LAYOUT "grid" COLUMNS 3

    ADD COMPONENT "MyComponent" WITH TYPE "gauge"
        SET RANGE FROM 0 TO 100
        BIND VALUE TO TOPIC "sensor/temperature"
```

* The panel **name** (`MyPanel`) identifies the panel in the Dashboard Manager.
* `WITH VISIBILITY` and `WITH STATE` declare the panel's audience and lifecycle — see [Lifecycle and visibility](#lifecycle-and-visibility).
* `WITH TITLE` is the heading people see; `WITH LAYOUT` arranges the components.
* Components are added with `ADD COMPONENT "<name>" WITH TYPE "<type>"`.

<Warning>
  **Always include `WITH VISIBILITY PUBLIC` and `WITH STATE PUBLISHED`.** A panel saved without them may not appear in the Dashboard Manager list.
</Warning>

## Layouts

The layout is declared on the panel header and controls how the panel's top-level components are arranged:

| Layout     | Syntax                                | Use it for                                     |
| ---------- | ------------------------------------- | ---------------------------------------------- |
| Grid       | `WITH LAYOUT "grid" COLUMNS 3 ROWS 2` | Most dashboards — explicit placement and spans |
| Vertical   | `WITH LAYOUT "vertical"`              | Simple stacked mobile/tablet views             |
| Horizontal | `WITH LAYOUT "horizontal"`            | Strips of KPIs on wide screens                 |

Each tab below arranges the same three station readouts with a different layout — only the `WITH LAYOUT` line changes:

<Tabs>
  <Tab title="Grid">
    Components flow into the declared columns, one cell each:

    <Frame caption="Grid: the three readouts fill one row of three columns">
      <img src="https://mintcdn.com/coreflux/ry-30sFxFVWzN72U/images/dashboard/components/layout-grid.png?fit=max&auto=format&n=ry-30sFxFVWzN72U&q=85&s=d71afea1009eb61ecc9cd91d17afd351" alt="A panel with a three-column grid layout showing temperature, humidity, and pressure readouts side by side" width="1665" height="175" data-path="images/dashboard/components/layout-grid.png" />
    </Frame>

    ```lot wrap focus={5} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE PANEL StationGrid
    WITH VISIBILITY PUBLIC
    WITH STATE PUBLISHED
    WITH TITLE "Station — Grid"
    WITH LAYOUT "grid" COLUMNS 3

        ADD COMPONENT "Temperature" WITH TYPE "value"
            BIND VALUE TO TOPIC "station/temperature"
            SET UNIT "°C"

        ADD COMPONENT "Humidity" WITH TYPE "value"
            BIND VALUE TO TOPIC "station/humidity"
            SET UNIT "%"

        ADD COMPONENT "Pressure" WITH TYPE "value"
            BIND VALUE TO TOPIC "station/pressure"
            SET UNIT "bar"
    ```
  </Tab>

  <Tab title="Vertical">
    Components stack top to bottom, each taking the full width:

    <Frame caption="Vertical: the same readouts stacked full-width, top to bottom">
      <img src="https://mintcdn.com/coreflux/ry-30sFxFVWzN72U/images/dashboard/components/layout-vertical.png?fit=max&auto=format&n=ry-30sFxFVWzN72U&q=85&s=258274c4588ef9a57e309ab65e4779b6" alt="A panel with a vertical layout showing temperature, humidity, and pressure readouts stacked full-width" width="1665" height="410" data-path="images/dashboard/components/layout-vertical.png" />
    </Frame>

    ```lot wrap focus={5} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE PANEL StationVertical
    WITH VISIBILITY PUBLIC
    WITH STATE PUBLISHED
    WITH TITLE "Station — Vertical"
    WITH LAYOUT "vertical"

        ADD COMPONENT "Temperature" WITH TYPE "value"
            BIND VALUE TO TOPIC "station/temperature"
            SET UNIT "°C"

        ADD COMPONENT "Humidity" WITH TYPE "value"
            BIND VALUE TO TOPIC "station/humidity"
            SET UNIT "%"

        ADD COMPONENT "Pressure" WITH TYPE "value"
            BIND VALUE TO TOPIC "station/pressure"
            SET UNIT "bar"
    ```
  </Tab>

  <Tab title="Horizontal">
    Components sit side by side in a single row:

    <Frame caption="Horizontal: the readouts laid out as a single row strip">
      <img src="https://mintcdn.com/coreflux/ry-30sFxFVWzN72U/images/dashboard/components/layout-horizontal.png?fit=max&auto=format&n=ry-30sFxFVWzN72U&q=85&s=6203e11369ee496dfc098575222646d9" alt="A panel with a horizontal layout showing temperature, humidity, and pressure readouts in a single row" width="1665" height="175" data-path="images/dashboard/components/layout-horizontal.png" />
    </Frame>

    ```lot wrap focus={5} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
    DEFINE PANEL StationHorizontal
    WITH VISIBILITY PUBLIC
    WITH STATE PUBLISHED
    WITH TITLE "Station — Horizontal"
    WITH LAYOUT "horizontal"

        ADD COMPONENT "Temperature" WITH TYPE "value"
            BIND VALUE TO TOPIC "station/temperature"
            SET UNIT "°C"

        ADD COMPONENT "Humidity" WITH TYPE "value"
            BIND VALUE TO TOPIC "station/humidity"
            SET UNIT "%"

        ADD COMPONENT "Pressure" WITH TYPE "value"
            BIND VALUE TO TOPIC "station/pressure"
            SET UNIT "bar"
    ```
  </Tab>
</Tabs>

### Mixing layouts with cards

The panel layout positions **top-level** components. To group several widgets into one grid slot, wrap them in a [`card`](/hub/dashboards/components/containers#card): the card occupies a cell (and can span columns like any component), while its children stack inside it. This is how you mix a coarse grid with finer-grained grouping:

<Frame caption="The grid sees two cells: the Zone 1 card (stacking a readout and an indicator) and the speed gauge">
  <img src="https://mintcdn.com/coreflux/ry-30sFxFVWzN72U/images/dashboard/components/mixed-layout.png?fit=max&auto=format&n=ry-30sFxFVWzN72U&q=85&s=5f4f0c1b913c1e9d5910f86f2404c861" alt="A two-column dashboard with a Zone 1 card containing a temperature readout and a running indicator on the left, and a speed gauge at 64% on the right" width="1665" height="595" data-path="images/dashboard/components/mixed-layout.png" />
</Frame>

```lot wrap  theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE PANEL MixedLayout
WITH VISIBILITY PUBLIC
WITH STATE PUBLISHED
WITH TITLE "Mixed Layout"
WITH LAYOUT "grid" COLUMNS 2

    ADD COMPONENT "ZoneCard" WITH TYPE "card"
        SET TITLE "Zone 1"

        ADD COMPONENT "ZoneTemp" WITH TYPE "value"
            BIND VALUE TO TOPIC "zone1/temperature"
            SET UNIT "°C"

        ADD COMPONENT "ZoneStatus" WITH TYPE "indicator"
            BIND STATE TO TOPIC "zone1/status"
            SET ON_VALUE "running" WITH COLOR "green"
            SET ON_VALUE "stopped" WITH COLOR "red"

    ADD COMPONENT "SpeedGauge" WITH TYPE "gauge"
        SET RANGE FROM 0 TO 100
        SET UNIT "%"
        BIND VALUE TO TOPIC "zone1/conveyor/speed"
```

The grid sees two components — the card and the gauge — while the card internally stacks a readout and an indicator. Use grid position for independent widgets; use a card when components belong to the same asset and should travel together.

## Positioning components on a grid

Use `AT COLUMN x ROW y` to place a component, and `SPAN n COLUMNS` to stretch it across the grid:

<Frame caption="The resulting layout: a chart spanning the full top row with two gauges placed below it">
  <img src="https://mintcdn.com/coreflux/ry-30sFxFVWzN72U/images/dashboard/components/grid-positioning.png?fit=max&auto=format&n=ry-30sFxFVWzN72U&q=85&s=3ebe8d7cc1b434d02df0ca9f3e2349a9" alt="A dashboard grid with a wide chart across the top row and two gauges in the second row" width="1665" height="763" data-path="images/dashboard/components/grid-positioning.png" />
</Frame>

```lot wrap focus={7,8,12,13,17,18} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE PANEL GridExample
WITH VISIBILITY PUBLIC
WITH STATE PUBLISHED
WITH TITLE "Grid Example"
WITH LAYOUT "grid" COLUMNS 3 ROWS 2

    ADD COMPONENT "FullWidthChart" WITH TYPE "realtime-chart"
        AT COLUMN 1 ROW 1 SPAN 3 COLUMNS
        SET LABEL "Throughput"
        BIND VALUE TO TOPIC "factory/throughput"

    ADD COMPONENT "Gauge1" WITH TYPE "gauge"
        AT COLUMN 1 ROW 2
        SET RANGE FROM 0 TO 100
        BIND VALUE TO TOPIC "sensor/1"

    ADD COMPONENT "Gauge2" WITH TYPE "gauge"
        AT COLUMN 2 ROW 2
        SET RANGE FROM 0 TO 100
        BIND VALUE TO TOPIC "sensor/2"
```

## Navigation

A dashboard doesn't have to fit on one screen. Any component with a click handler can jump to another panel with `NAVIGATE TO PANEL "<name>"`, and the target panel can return with `NAVIGATE BACK` — the classic pattern is an overview panel with a button per zone, each leading to a detail panel.

The overview panel links to the detail panel by name:

<Frame caption="The overview panel: a live readout next to a button that opens the detail panel">
  <img src="https://mintcdn.com/coreflux/ry-30sFxFVWzN72U/images/dashboard/other/nav-overview.png?fit=max&auto=format&n=ry-30sFxFVWzN72U&q=85&s=083fc155bceb1ceba5e81015f02d0ad8" alt="A Zone Overview panel with a temperature readout and a Zone 1 details button" width="1665" height="185" data-path="images/dashboard/other/nav-overview.png" />
</Frame>

```lot wrap focus={11-14} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE PANEL NavOverview
WITH VISIBILITY PUBLIC
WITH STATE PUBLISHED
WITH TITLE "Zone Overview"
WITH LAYOUT "grid" COLUMNS 2

    ADD COMPONENT "Zone1Temp" WITH TYPE "value"
        BIND VALUE TO TOPIC "sensor/temperature"
        SET UNIT "°C"

    ADD COMPONENT "Zone1Details" WITH TYPE "button"
        SET LABEL "Zone 1 details"
        ON CLICK DO
            NAVIGATE TO PANEL "NavDetail"
```

The detail panel offers the way back with `NAVIGATE BACK`:

<Frame caption="The detail panel after clicking the button — its Back button returns to the overview">
  <img src="https://mintcdn.com/coreflux/ry-30sFxFVWzN72U/images/dashboard/other/nav-detail.png?fit=max&auto=format&n=ry-30sFxFVWzN72U&q=85&s=ed8df5ac1b1b092b57c2e005601ca2a2" alt="A Zone 1 Detail panel with a temperature gauge and a Back to overview button" width="1665" height="600" data-path="images/dashboard/other/nav-detail.png" />
</Frame>

```lot wrap focus={12-15} theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE PANEL NavDetail
WITH VISIBILITY PUBLIC
WITH STATE PUBLISHED
WITH TITLE "Zone 1 — Detail"
WITH LAYOUT "grid" COLUMNS 2

    ADD COMPONENT "DetailTemp" WITH TYPE "gauge"
        SET RANGE FROM 0 TO 100
        SET UNIT "°C"
        BIND VALUE TO TOPIC "sensor/temperature"

    ADD COMPONENT "BackButton" WITH TYPE "button"
        SET LABEL "Back to overview"
        ON CLICK DO
            NAVIGATE BACK
```

Navigation is just another action — it works from buttons, cards, or anything else with an `ON CLICK` handler. The full action reference is in [Actions & Events](/latest/lot-language/panels/actions-events#navigate-between-panels).

## Lifecycle and visibility

A panel also carries lifecycle attributes:

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE PANEL Zone1
WITH VISIBILITY PUBLIC
WITH STATE PUBLISHED
WITH TITLE "Zone 1"
```

| Attribute         | Values                             | Meaning                                                                                                 |
| ----------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------- |
| `WITH STATE`      | `DRAFT` · `PUBLISHED` · `ARCHIVED` | **Draft** while building (hidden), **Published** for daily use, **Archived** to retire without deleting |
| `WITH VISIBILITY` | `PUBLIC` · `SHARED` · `PRIVATE`    | Who is allowed to open the panel                                                                        |

* New panels open in **Draft** — switch to `PUBLISHED` when operators should rely on the panel.
* `PUBLIC` panels are open to any connected client; `PRIVATE` restricts to the creator and admins.
* The same lifecycle is surfaced as badges in the Dashboard Manager — see [Dashboards in the HUB](/hub/dashboards/overview).

<Note>
  **Current HUB behaviour.** These attributes are honoured by the renderer but are not yet manageable from the HUB itself: a panel saved without explicit `WITH VISIBILITY` / `WITH STATE` values may not appear in the Dashboard Manager list at all, and the manager offers no way to view or change them outside the source text. Until that integration improves, always write both attributes explicitly in the definition.
</Note>

## Common mistakes

<AccordionGroup>
  <Accordion title="A property set with WITH is silently ignored">
    Properties use `SET`, not `WITH`. `WITH UNIT "°C"`, `WITH RANGE 0, 100`, and `WITH DECIMALS 2` do nothing — write `SET UNIT "°C"`, `SET RANGE FROM 0 TO 100`, `SET DECIMALS 2`.
  </Accordion>

  <Accordion title="WITH TYPE inside a component body does nothing">
    Component **types** are set on the header, not in the body. `WITH TYPE "line"` inside a chart body is silently ignored — use `SET CHART_TYPE "line"` instead.
  </Accordion>

  <Accordion title="The panel saves but does not show up in the Dashboard Manager">
    Check that both `WITH VISIBILITY PUBLIC` and `WITH STATE PUBLISHED` are present — panels saved without them may not appear in the panel list.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Display components" icon="table-cells" href="/hub/dashboards/components/display">
    The widgets you place inside a panel, property by property.
  </Card>

  <Card title="Data binding" icon="plug" href="/latest/lot-language/panels/data-binding">
    Wire each component to a topic, model, or query.
  </Card>
</CardGroup>
