**Site index:** [https://2plot.dev/llms.txt](https://2plot.dev/llms.txt) — every page on this site, as Markdown.  
**Network index:** [https://2plot.ai/llms.txt](https://2plot.ai/llms.txt) — The 2plot network; start here to discover sibling sites.  
**Sibling sites:** 11 more in The 2plot network — listed in the site index above.  
**Sitemap:** https://2plot.dev/sitemap.xml  



### Installation
[Visit GitHub Repo](https://github.com/pip-install-python/dash-gauge)
```bash
pip install dash-gauge
```


### Introduction

The `dash-gauge` package provides a suite of interactive and visually appealing components to enhance your Plotly Dash dashboards. Built as wrappers around popular React libraries, this collection includes:

*   **`DashGauge`**: Customizable gauge charts (Grafana, Semicircle, Radial styles).
*   **`DashRotaryKnob`**: Interactive rotary knob controls with various skins.
*   **`DashThermostat`**: A thermostat-like input component.
*   **`DashRCJoystick`**: A virtual joystick component for directional input.
*   **`Dash7SegmentDisplay`**: A classic 7-segment display for numbers and hex values.

This page documents each component included in the suite.



```python
# File: docs/dash_gauge/introduction_example.py

import dash
from dash import html, callback, Input, Output
import dash_gauge as dg
import dash_mantine_components as dmc

# app = dash.Dash(__name__) # Define app in your main docs entry point

component = dmc.Container([
    dmc.Title("Dash Gauge Component Suite Showcase", order=2, ta="center", mb="lg"),

    dmc.SimpleGrid(
        cols={"base": 1, "sm": 2, "lg": 3},
        spacing="lg",
        verticalSpacing="lg",
        children=[
            # 1. DashGauge Example
            dmc.Paper(
                p="md", shadow="sm", withBorder=True, children=[
                    dmc.Stack([
                        dmc.Text("DashGauge (Semicircle)", fw=500, ta="center"),
                        dmc.Center(
                            dg.DashGauge(
                                id="intro-gauge",
                                type="semicircle",
                                value=65,
                                minValue=0,
                                maxValue=100,
                                style={'width': '90%'} # Adjust width as needed
                            )
                        )
                    ])
                ]
            ),

            # 2. DashRotaryKnob Example
            dmc.Paper(
                p="md", shadow="sm", withBorder=True, children=[
                    dmc.Stack([
                        dmc.Text("DashRotaryKnob", fw=500, ta="center"),
                        dmc.Center(
                            dg.DashRotaryKnob(
                                id="intro-knob",
                                skinName="s12", # Choose a visually interesting skin
                                value=30,
                                min=0,
                                max=100,
                                style={"width": "100px", "height": "100px"} # Explicit size
                            )
                        ),
                        dmc.Text("Value: --", id="intro-knob-output", ta="center", size="sm", c="dimmed")
                    ])
                ]
            ),

            # 3. DashThermostat Example
            dmc.Paper(
                p="md", shadow="sm", withBorder=True, children=[
                    dmc.Stack([
                        dmc.Text("DashThermostat", fw=500, ta="center"),
                        dmc.Space(h=20),
                        dmc.Center(
                            dg.DashThermostat(
                                id="intro-thermostat",
                                value=21,
                                min=5,
                                max=35,
                                valueSuffix="°C",
                                style={'width': '200px', 'height': '300px'} # Control size
                            )
                        )
                    ])
                ]
            ),

            # 4. DashRCJoystick Example
            dmc.Paper(
                p="md", shadow="sm", withBorder=True, children=[
                    dmc.Stack([
                        dmc.Text("DashRCJoystick", fw=500, ta="center"),
                        dmc.Center(
                            dg.DashRCJoystick(
                                id='intro-joystick',
                                directionCountMode='Nine',
                                baseRadius=60, # Slightly smaller for grid
                                controllerRadius=30,
                            )
                        ),
                        dmc.Text("Direction: Center", id="intro-joystick-direction", ta="center", size="sm", c="dimmed"),
                        dmc.Text("Angle: N/A", id="intro-joystick-angle", ta="center", size="sm", c="dimmed"),
                        dmc.Text("Distance: 0.00", id="intro-joystick-distance", ta="center", size="sm", c="dimmed"),
                    ])
                ]
            ),
        ]
    )
], fluid=True, pt="xl", pb="xl")


# --- Callbacks ---

@callback(
    Output("intro-knob-output", "children"),
    Input("intro-knob", "value")
)
def update_intro_knob_output(value):
    if value is None:
        return "Value: --"
    return f"Value: {value:.1f}"

@callback(
    Output('intro-joystick-direction', 'children'),
    Output('intro-joystick-angle', 'children'),
    Output('intro-joystick-distance', 'children'),
    Input('intro-joystick', 'direction'),
    Input('intro-joystick', 'angle'),
    Input('intro-joystick', 'distance')
)
def update_intro_joystick_output(direction, angle, distance):
    angle_str = f"Angle: {angle:.1f}°" if angle is not None else "Angle: N/A"
    distance_str = f"Distance: {distance:.2f}" if distance is not None else "Distance: N/A"
    direction_str = f"Direction: {direction}" if direction is not None else "Direction: N/A"
    return direction_str, angle_str, distance_str

# Add this section if running this file standalone for testing
# if __name__ == "__main__":
#     app = dash.Dash(__name__)
#     app.layout = component
#     app.run_server(debug=True)
```


---

### DashGauge

Displays a value on a customizable gauge. Supports different styles, color ranges, sub-arcs, custom labels, and pointers. Ideal for visualizing KPIs, sensor readings, or progress metrics.



```python
# File: docs/dash_gauge/gauge_example.py

import dash
from dash import html, dcc, callback, Input, Output
import dash_gauge as dg
import dash_mantine_components as dmc

# Based on usage_gauge.py

component = dmc.Container([
    dmc.Title("DashGauge Examples", order=3, ta="center", mb="lg"),
    dmc.SimpleGrid(
        cols={"base": 1, "sm": 1, "lg": 3},
        spacing="lg",
        children=[
            dmc.Paper(p="md", shadow="sm", withBorder=True, children=dmc.Stack([
                dmc.Text("Basic Gauge", fw=500, ta="center"),
                dmc.Center(
                    dg.DashGauge(
                        id="basic-gauge-docs",
                        value=50,
                        style={'width': '90%'}
                    )
                )
            ])),
            dmc.Paper(p="md", shadow="sm", withBorder=True, children=dmc.Stack([
                dmc.Text("Temperature Gauge (Semicircle)", fw=500, ta="center"),
                dmc.Center(
                    dg.DashGauge(
                        id="temperature-gauge-docs",
                        type="semicircle",
                        value=22.5,
                        minValue=10,
                        maxValue=35,
                        arc={
                            "width": 0.2, "padding": 0.005, "cornerRadius": 1,
                            "subArcs": [
                                {"limit": 15, "color": "#EA4228", "showTick": True, "tooltip": {"text": "Too low!"}},
                                {"limit": 17, "color": "#F5CD19", "showTick": True, "tooltip": {"text": "Low"}},
                                {"limit": 28, "color": "#5BE12C", "showTick": True, "tooltip": {"text": "OK"}},
                                {"limit": 30, "color": "#F5CD19", "showTick": True, "tooltip": {"text": "High"}},
                                {"color": "#EA4228", "tooltip": {"text": "Too high!"}}
                            ]
                        },
                        pointer={"color": "#345243", "length": 0.80, "width": 15},
                        labels={"valueLabel": {"style": {"fontSize": "30px"}}}, # Simplified labels
                        style={'width': '90%'}
                    )
                )
            ])),
            dmc.Paper(p="md", shadow="sm", withBorder=True, children=dmc.Stack([
                dmc.Text("Bandwidth Gauge (Radial)", fw=500, ta="center"),
                dmc.Center(
                    dg.DashGauge(
                        id="bandwidth-gauge-docs",
                        type="radial", # Changed type for variety
                        value=900,
                        maxValue=3000,
                        arc={
                            "nbSubArcs": 150,
                            "colorArray": ["#5BE12C", "#F5CD19", "#EA4228"],
                            "width": 0.3, # Adjusted width for radial
                            "padding": 0.003
                        },
                         style={'width': '90%'}
                    )
                )
            ])),
        ]
    ),
    dmc.Space(h="xl"),
    dmc.Paper(p="md", shadow="sm", withBorder=True, children=dmc.Stack([
        dmc.Text("Interactive Gauge", fw=500, ta="center"),
        dmc.Text("Use the slider to update the gauge value:", size="sm", ta="center"),
        dmc.Slider(
            id="gauge-slider-docs",
            min=0, max=100, step=1, value=40,
            labelTransitionProps={
                "transition": "skew-down",
                "duration": 150,
                "timingFunction": "linear",
            },
        ),
        dmc.Center(
            dg.DashGauge(
                id="interactive-gauge-docs",
                type="radial",
                value=50, # Initial value linked to slider
                arc={
                    "colorArray": ["#5BE12C", "#EA4228"],
                    "subArcs": [{"limit": 10}, {"limit": 30}, {}, {}, {}],
                    "padding": 0.02,
                    "width": 0.3
                },
                pointer={"elastic": True, "animationDelay": 0},
                labels={
                    "tickLabels": {"type": "inner", "ticks": [{"value": i} for i in range(20, 101, 20)]}
                },
                 style={'width': '300px', 'marginTop': '20px'} # Control size
            )
        )
    ]))
], fluid=True)

@callback(
    Output("interactive-gauge-docs", "value"),
    Input("gauge-slider-docs", "value")
)
def update_gauge_docs(value):
    return value
```



#### DashGauge Props

| Prop              | Type                       | Default      | Description                                                                                                                                  |
|-------------------|----------------------------|--------------|----------------------------------------------------------------------------------------------------------------------------------------------|
| `id`              | string                     | -            | Component ID for Dash callbacks.                                                                                                             |
| `value`           | number                     | `33`         | The value the gauge should indicate.                                                                                                         |
| `type`            | string                     | `'grafana'`  | Style of the gauge. Choices: `'grafana'`, `'semicircle'`, `'radial'`.                                                                         |
| `minValue`        | number                     | `0`          | Minimum value of the gauge scale.                                                                                                            |
| `maxValue`        | number                     | `100`        | Maximum value of the gauge scale.                                                                                                            |
| `className`       | string                     | `dash-gauge` | CSS class name for the component.                                                                                                            |
| `style`           | object                     | `{}`         | Inline CSS styles for the component.                                                                                                         |
| `marginInPercent` | number or object           | `undefined`  | Sets the margin for the chart inside the SVG. Can be a single number or `{top, bottom, left, right}`.                                         |
| `arc`             | object                     | `{}`         | Configuration for the gauge arc (e.g., `width`, `padding`, `cornerRadius`, `colorArray`, `subArcs`, `gradient`). See `usage_gauge.py` for details. |
| `pointer`         | object                     | `{}`         | Configuration for the gauge pointer/needle (e.g., `type`, `color`, `length`, `width`, `animate`, `elastic`). See `usage_gauge.py` for details.   |
| `labels`          | object                     | `{}`         | Configuration for value and tick labels (e.g., `valueLabel`, `tickLabels`, `formatTextValue`, `hideMinMax`). See `usage_gauge.py` for details. |
| `setProps`        | func                       | -            | Dash-assigned callback function.                                                                                                             |

**Note:** For detailed examples of `arc`, `pointer`, and `labels` configurations, please refer to the `usage_gauge.py` file in the GitHub repository.

---

### DashRotaryKnob

An interactive knob component, useful for selecting values within a range (e.g., volume, tuning). Comes with multiple visual skins from the `react-rotary-knob-skin-pack`.



```python
# File: docs/dash_gauge/knob_example.py

import dash
from dash import html, dcc, callback, Input, Output, State
import dash_gauge as dg
import dash_mantine_components as dmc

# Based on usage_rotary_knob.py

component = dmc.Container([
    dmc.Title("DashRotaryKnob Example", order=3, ta="center", mb="lg"),
    dmc.Grid(
        gutter="xl",
        children=[
            dmc.GridCol(span={"md": 5, "sm": 12}, children=dmc.Stack(align="center", children=[
                dmc.Text("Interactive Knob", fw=500),
                dmc.Text(id="knob-value-display-docs", size="lg", mt="sm"),
                dg.DashRotaryKnob(
                    id="interactive-knob-docs",
                    skinName="s10",
                    value=50,
                    min=0,
                    max=100,
                    # format="{value}%", # Formatting might be better handled in display callback
                    style={"width": "150px", "height": "150px"} # Adjust size
                ),
            ])),
            dmc.GridCol(span={"md": 7, "sm": 12}, children=dmc.Stack([
                dmc.Text("Controls", fw=500),
                dmc.Slider(
                    id="knob-slider-docs",
                    label="Adjust with slider",
                    min=0, max=100, step=1, value=50,
                    marks=[{"value": i, "label": str(i)} for i in range(0, 101, 20)],
                    mb="lg"
                ),
                dmc.Select(
                    id="skin-selector-docs",
                    label="Change skin",
                    data=[{"label": f"Skin s{i}", "value": f"s{i}"} for i in range(1, 19)],
                    value="s10",
                    clearable=False,
                     mb="lg"
                ),

            ]))
        ]
    )
], fluid=True)

@callback(
    Output("knob-value-display-docs", "children"),
    Input("interactive-knob-docs", "value")
)
def update_knob_value_display_docs(value):
     if value is None:
        return "Current value: --"
     return f"Current value: {value:.1f}"

@callback(
    Output("interactive-knob-docs", "value"),
    Input("knob-slider-docs", "value"),
)
def update_knob_from_slider_docs(value):
    return value

@callback(
    Output("interactive-knob-docs", "skinName"),
    Input("skin-selector-docs", "value"),
)
def update_knob_skin_docs(skin_name):
    return skin_name

```


#### DashRotaryKnob Props

| Prop            | Type    | Default   | Description                                                                                                |
|-----------------|---------|-----------|------------------------------------------------------------------------------------------------------------|
| `id`            | string  | -         | Component ID for Dash callbacks.                                                                           |
| `value`         | number  | `0`       | The current value of the knob. Updated via interaction or callbacks.                                     |
| `min`           | number  | `0`       | Minimum value of the knob.                                                                                 |
| `max`           | number  | `100`     | Maximum value of the knob.                                                                                 |
| `step`          | number  | `1`       | Increment/decrement step size.                                                                             |
| `skinName`      | string  | `'s1'`    | Selects the visual appearance (e.g., `'s1'`, `'s5'`, `'s10'`, up to `'s18'`). See repository for examples. |
| `preciseMode`   | boolean | `true`    | If true, requires Shift key + drag for fine adjustments.                                                     |
| `unlockDistance`| number  | `0`       | Degrees the mouse must move vertically to "unlock" the knob for rotation.                                    |
| `className`     | string  | `''`      | CSS class name for the component.                                                                          |
| `style`         | object  | `{}`      | Inline CSS styles for the component.                                                                       |
| `setProps`      | func    | -         | Dash-assigned callback function.                                                                           |

**Note:** Explore all 18 skins by changing the `skinName` prop! See `usage_rotary_knob.py` for an interactive example. Only skins 1 & 10-15 look good 🤷‍ "no idea why the other skins don't alin correctly".

---

### DashThermostat

A component mimicking a thermostat interface for setting a target value, typically temperature.



```python
# File: docs/dash_gauge/thermostat_example.py

import dash
from dash import html, dcc, callback, Input, Output, State
import dash_gauge as dg
import dash_mantine_components as dmc

# Based on usage_thermostat.py, but simplified for docs

# Define some example colors
cool_colors = ['#dae8eb', '#2c8e98']
heat_colors = ['#cfac48', '#cd5401']

component = dmc.Container([
    dmc.Title("DashThermostat Example", order=3, ta="center", mb="lg"),
    dmc.Grid(
        gutter="xl",
        children=[
            dmc.GridCol(span={"md": 6, "sm": 12}, children=dmc.Stack(align="center", children=[
                 dmc.Text("Thermostat Control", fw=500),
                 dmc.Space(h=20),
                 dg.DashThermostat(
                    id='thermostat-docs',
                    value=21,
                    min=5,
                    max=35,
                    valueSuffix='°C',
                    track={'colors': cool_colors}, # Start with cool colors
                    style={'width': '250px', 'height': '350px', 'marginBottom': '20px'},
                 )
            ])),
             dmc.GridCol(span={"md": 6, "sm": 12}, children=dmc.Stack([
                 dmc.Text("Controls", fw=500),
                 dmc.Text("Set Temperature:", size="sm"),
                 dmc.Slider(
                     id="thermostat-slider-docs",
                     min=5, max=35, step=0.5, value=21,
                     marks=[{"value": v, "label": f"{v}°"} for v in range(5, 36, 5)],
                     style={"maxWidth": 300},
                     mb="lg"
                 ),
                 dmc.Text("Current Setting:", size="sm"),
                 dmc.Title(id="thermostat-value-display-docs", order=4, ta="center"),
                 dmc.Space(h="lg"),
                 dmc.Text("Toggle Disabled:", size="sm"),
                 dmc.Switch(id="thermostat-disable-switch-docs", label="Disable Thermostat", checked=False),
                 dmc.Space(h="lg"),
                 dmc.Text("Change Track Color:", size="sm"),
                  dmc.SegmentedControl(
                    id="thermostat-color-switch-docs",
                    value="cool",
                    data=[
                        {"label": "Cool Mode", "value": "cool"},
                        {"label": "Heat Mode", "value": "heat"},
                    ],
                    fullWidth=True,
                    mb="md",
                ),
             ]))
        ]
    )
], fluid=True)

@callback(
    Output('thermostat-docs', 'value'),
    Input('thermostat-slider-docs', 'value')
)
def update_thermostat_from_slider(value):
    return value

@callback(
    Output('thermostat-value-display-docs', 'children'),
    Input('thermostat-docs', 'value')
)
def display_thermostat_value(value):
    if value is None:
        return "-- °C"
    return f"{value:.1f} °C"

@callback(
    Output('thermostat-docs', 'disabled'),
    Input('thermostat-disable-switch-docs', 'checked')
)
def toggle_thermostat_disabled(checked):
    return checked

@callback(
    Output('thermostat-docs', 'track'),
    Input('thermostat-color-switch-docs', 'value'),
    State('thermostat-docs', 'track') # Get current track state if needed
)
def update_thermostat_track_color(mode, current_track):
    # Ensure track is a dictionary before modifying
    track_config = current_track if isinstance(current_track, dict) else {}
    if mode == 'cool':
        track_config['colors'] = cool_colors
    elif mode == 'heat':
        track_config['colors'] = heat_colors
    # Add other track properties if they exist, e.g., thickness
    # track_config['thickness'] = current_track.get('thickness', 0.2) # Example
    return track_config
```


#### DashThermostat Props

| Prop         | Type    | Default     | Description                                                                                             |
|--------------|---------|-------------|---------------------------------------------------------------------------------------------------------|
| `id`         | string  | -           | Component ID for Dash callbacks.                                                                        |
| `value`      | number  | Required    | The current set value (e.g., temperature). Updated via interaction or callbacks.                          |
| `min`        | number  | `0`         | Minimum value of the thermostat scale.                                                                    |
| `max`        | number  | `100`       | Maximum value of the thermostat scale.                                                                    |
| `valueSuffix`| string  | `'°'`       | Text to display after the value (e.g., `'°C'`, `'°F'`, `'%`).                                             |
| `disabled`   | boolean | `false`     | If true, disables user interaction with the thermostat.                                                   |
| `handle`     | object  | `undefined` | Configuration object for the draggable handle (e.g., `size`, `colors`). See `react-thermostat` docs.      |
| `track`      | object  | `undefined` | Configuration object for the background track (e.g., `colors`, `thickness`, `markers`). See `react-thermostat` docs. |
| `className`  | string  | `''`        | CSS class name for the component.                                                                       |
| `style`      | object  | `{}`        | Inline CSS styles for the component. Note: Component has min-width/height defaults.                     |
| `setProps`   | func    | -           | Dash-assigned callback function.                                                                        |

**Note:** The `usage_thermostat.py` example demonstrates complex interaction with custom styling and mode switching. It may require CSS files placed in an `assets` folder.

---

### DashRCJoystick

A virtual joystick component that reports direction, angle, and distance based on user interaction. Useful for controlling elements in simulations, games, or robotics dashboards.



```python
# File: docs/dash_gauge/joystick_example.py

import dash
from dash import html, dcc, callback, Input, Output, State
import dash_gauge as dg
import dash_mantine_components as dmc

# Based on usage_rc_joystick.py

component = dmc.Container([
    dmc.Title("DashRCJoystick Example", order=3, ta="center", mb="lg"),
    dmc.Grid(
        gutter="xl",
        children=[
            # Left side: Joystick Component
            dmc.GridCol(span={"md": 5, "sm": 12}, children=dmc.Stack(align="center", children=[
                dmc.Text("Interactive Joystick", fw=500),
                dg.DashRCJoystick(
                    id='my-joystick-docs',
                    directionCountMode='Nine', # Default to Nine for demo
                    baseRadius=75,
                    controllerRadius=35,
                    style={'marginTop': '20px'} # Add some space
                ),
            ])),

            # Right side: Displaying Joystick State & Controls
            dmc.GridCol(span={"md": 7, "sm": 12}, children=dmc.Stack([
                dmc.Text("Joystick State", fw=500),
                dmc.Text(id='joystick-output-direction-docs', size="sm"),
                dmc.Text(id='joystick-output-angle-docs', size="sm"),
                dmc.Text(id='joystick-output-distance-docs', size="sm"),
                dmc.Divider(my="md"),
                dmc.RadioGroup(
                    [dmc.Radio(label, value=value) for label, value in
                     [('5 Directions', 'Five'), ('9 Directions', 'Nine')]],
                    id='direction-mode-selector-docs',
                    value='Nine', # Initial value matches component
                    label="Direction Mode",
                    size="sm",
                    mb="md",
                ),
                dmc.Text("Base Radius:", size="sm", fw=500),
                dmc.Slider(
                    id='base-radius-slider-docs', min=50, max=150, step=5, value=75,
                    marks=[{"value": i, "label": str(i)} for i in range(50, 151, 25)],
                    mb="md"
                ),
                dmc.Text("Controller Radius:", size="sm", fw=500),
                dmc.Slider(
                    id='controller-radius-slider-docs', min=20, max=70, step=5, value=35,
                    marks=[{"value": i, "label": str(i)} for i in range(20, 71, 10)],
                    mb="md"
                 ),
            ]))
        ])
], fluid=True)


# Callback to display joystick state changes
@callback(
    Output('joystick-output-direction-docs', 'children'),
    Output('joystick-output-angle-docs', 'children'),
    Output('joystick-output-distance-docs', 'children'),
    Input('my-joystick-docs', 'direction'),
    Input('my-joystick-docs', 'angle'),
    Input('my-joystick-docs', 'distance')
)
def update_joystick_output_docs(direction, angle, distance):
    angle_str = f"Angle: {angle:.1f}°" if angle is not None else "Angle: N/A (Center)"
    distance_str = f"Distance: {distance:.2f}" if distance is not None else "Distance: N/A"
    direction_str = f"Direction: {direction}" if direction is not None else "Direction: N/A"
    return direction_str, angle_str, distance_str

# Callback to update joystick configuration from controls
@callback(
    Output('my-joystick-docs', 'directionCountMode'),
    Output('my-joystick-docs', 'baseRadius'),
    Output('my-joystick-docs', 'controllerRadius'),
    Input('direction-mode-selector-docs', 'value'),
    Input('base-radius-slider-docs', 'value'),
    Input('controller-radius-slider-docs', 'value'),
)
def update_joystick_config_docs(direction_mode, base_radius, controller_radius):
    return direction_mode, base_radius, controller_radius
```


#### DashRCJoystick Props

| Prop                 | Type    | Default      | Description                                                                                                                                 |
|----------------------|---------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------|
| `id`                 | string  | -            | Component ID for Dash callbacks.                                                                                                            |
| `baseRadius`         | number  | `75`         | Radius of the joystick's static base circle.                                                                                                  |
| `controllerRadius`   | number  | `35`         | Radius of the movable controller knob.                                                                                                      |
| `directionCountMode` | string  | `'Five'`     | Determines the reported directions. Choices: `'Five'` (Center, Top, Bottom, Left, Right), `'Nine'` (includes diagonals).                      |
| `insideMode`         | boolean | `false`      | If true, the controller knob stays within the base radius.                                                                                  |
| `throttle`           | number  | `0`          | Throttle time in milliseconds for `onChange` events. `0` means no throttle.                                                                   |
| `className`          | string  | `''`         | CSS class name for the container.                                                                                                           |
| `style`              | object  | `{}`         | Inline CSS styles for the container.                                                                                                        |
| `controllerClassName`| string  | `undefined`  | Additional CSS class for the controller knob.                                                                                               |
| **Read-only Props**  |         |              | *(These props are updated by the component and read in callbacks)*                                                                          |
| `angle`              | number  | `undefined`  | [Readonly] Current angle of the joystick (degrees). `undefined` when centered.                                                              |
| `direction`          | string  | `'Center'`   | [Readonly] Current direction string (e.g., 'Top', 'BottomLeft', 'Center'). Possible values depend on `directionCountMode`.                   |
| `distance`           | number  | `0`          | [Readonly] Current distance of the controller from the center (normalized 0-1 based on `baseRadius`).                                       |
| `setProps`           | func    | -            | Dash-assigned callback function.                                                                                                            |

**Note:** See `usage_rc_joystick.py` for an example controlling the joystick's appearance and reading its state.

---
