Dials & Touch Strip
Dial actions are a combination of two parts of Stream Deck, the dial itself and a portion of the touch strip.
What are dials?
The dial and touch strip portion that make up a dial action are collectively known as an "Encoder". Combined, they allow for your plugin to receive dial and touch events, as well as provide feedback on the touch strip in the form of layouts.

Layouts
Layouts are the rendering engine used to display information on a Stream Deck + (Classic | XL) touch strip. Layouts on Stream Deck + (Classic | XL) are 200 × 100 px, and are composed of layout items whose values can be updated at runtime to display dynamic information.
There are several built-in layouts available to dial actions. Alternatively dial actions may use custom layouts.
Built-in Layouts
There are several built-in layouts available when rendering information on the Stream Deck + touch strip.
- Icon ($X1)
- Canvas ($A0)
- Value ($A1)
- Indicator ($B1)
- Gradient indicator ($B2)
- Double indicator ($C1)

{
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
"id": "$X1",
"items": [
{
"key": "title",
"type": "text",
"rect": [16, 10, 136, 24],
"font": { "size": 16, "weight": 600 },
"alignment": "left"
},
{
"key": "icon",
"type": "pixmap",
"rect": [76, 40, 48, 48]
}
]
}
Note: The canvas is denoted in yellow, and the full-canvas in gray.
{
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
"id": "$A0",
"items": [
{
"key": "full-canvas",
"type": "pixmap",
"rect": [0, 0, 200, 100]
},
{
"key": "title",
"type": "text",
"rect": [16, 10, 136, 24],
"zOrder": 1,
"font": { "size": 16, "weight": 600 },
"alignment": "left"
},
{
"key": "canvas",
"type": "pixmap",
"rect": [16, 34, 136, 54],
"zOrder": 1
}
]
}
{
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
"id": "$A1",
"items": [
{
"key": "title",
"type": "text",
"rect": [16, 10, 136, 24],
"font": { "size": 16, "weight": 600 },
"alignment": "left"
},
{
"key": "icon",
"type": "pixmap",
"rect": [16, 40, 48, 48]
},
{
"key": "value",
"type": "text",
"rect": [76, 40, 108, 32],
"font": { "size": 24, "weight": 600 },
"alignment": "right"
}
]
}
{
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
"id": "$B1",
"items": [
{
"key": "title",
"type": "text",
"rect": [16, 10, 136, 24],
"font": { "size": 16, "weight": 600 },
"alignment": "left"
},
{
"key": "icon",
"type": "pixmap",
"rect": [16, 40, 48, 48]
},
{
"key": "value",
"type": "text",
"rect": [76, 40, 108, 32],
"font": { "size": 24, "weight": 600 },
"alignment": "right"
},
{
"key": "indicator",
"type": "bar",
"rect": [76, 74, 108, 12],
"value": 0,
"subtype": 4,
"border_w": 0
}
]
}
{
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
"id": "$B2",
"items": [
{
"key": "title",
"type": "text",
"rect": [16, 10, 136, 24],
"font": { "size": 16, "weight": 600 },
"alignment": "left"
},
{
"key": "icon",
"type": "pixmap",
"rect": [16, 40, 48, 48]
},
{
"key": "value",
"type": "text",
"rect": [76, 40, 108, 32],
"font": { "size": 24, "weight": 600 },
"alignment": "right"
},
{
"key": "indicator",
"type": "gbar",
"rect": [76, 74, 108, 20],
"value": 0,
"subtype": 4,
"bar_h": 12,
"border_w": 0,
"bar_bg_c": "0:#ff0000,0.33:#a6d4ec,0.66:#f4b675,1:#00ff00"
}
]
}
{
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
"id": "$C1",
"items": [
{
"key": "title",
"type": "text",
"rect": [16, 10, 136, 24],
"font": { "size": 16, "weight": 600 },
"alignment": "left"
},
{
"key": "icon1",
"type": "pixmap",
"rect": [16, 40, 24, 24]
},
{
"key": "icon2",
"type": "pixmap",
"rect": [16, 68, 24, 24]
},
{
"key": "indicator1",
"type": "bar",
"rect": [48, 46, 136, 12],
"value": 0,
"subtype": 4,
"border_w": 0
},
{
"key": "indicator2",
"type": "bar",
"rect": [48, 74, 136, 12],
"value": 0,
"subtype": 4,
"border_w": 0
}
]
}Custom Layouts
Custom layouts are represented as JSON files, located in the *.sdPlugin folder. Layout files are composed of layout items that define the structure of the layout; the value of these items can then be controlled at runtime to display dynamic information. On Stream Deck + (Classic | XL), layouts are 200 × 100 px.
The following is an example of a custom layout that renders the title, with an image on either side:
{
"$schema": "https://schemas.elgato.com/streamdeck/plugins/layout.json",
"id": "custom-layout",
"controller": "Encoder",
"items": [
{
"type": "pixmap",
"key": "leading",
"rect": [10, 40, 20, 20]
},
{
"key": "title",
"type": "text",
"rect": [40, 40, 120, 20],
"font": {
"size": 20
}
},
{
"key": "trailing",
"type": "pixmap",
"rect": [170, 40, 20, 20]
}
]
}
In summary, layout items within a layout:
- Must have a unique
key. - Must have their
typeandrectdefined. - Must not overlap with other items in the layout, see
zOrder. - Must be within the bounds of the layout.
Layout items can also be assigned a pre-defined key that will enable users to control them—these are:
"title"— as with key actions, users can set a custom title for dial/touch strip actions, which will take precedence over the plugin provided title."icon"— as with key actions, users can set a custom icon for dial/touch strip actions, which will take precedence over the plugin provided icon.
Layouts will not render when:
- A layout item is outside the allotted bounds of the layout.
- Layout items overlap on the same
zOrder.
For assistance with debugging layouts, try using the CLI tool's validate command, or referring to the Stream Deck app logs.
Setting Default Layouts
The default layout of an action is defined within the manifest by specifying the Actions[].Encoder.layout property. This value can be either the name of a built-in layout, or the file path to a custom layout.
{
"$schema": "https://schemas.elgato.com/streamdeck/plugins/manifest.json",
"Actions": [
{
"Icon": "action-icon",
"Name": "Action One",
"Controllers": ["Encoder"],
"Encoder": {
"layout": "$B1"
},
"States": [
{
"Image": "state-image"
}
],
"UUID": "come.elgato.test.one"
}
],
"Author": "Elgato",
"Software": {
"MinimumVersion": "6.6"
}
// ...
}{
"$schema": "https://schemas.elgato.com/streamdeck/plugins/manifest.json",
"Actions": [
{
"Icon": "action-icon",
"Name": "Action One",
"Controllers": ["Encoder"],
"Encoder": {
"layout": "custom-layout.json"
},
"States": [
{
"Image": "state-image"
}
],
"UUID": "come.elgato.test.one"
}
],
"Author": "Elgato",
"Software": {
"MinimumVersion": "6.6"
}
// ...
}Changing Layouts
The layout of a dial action instance can be changed at runtime using the setFeedbackLayout function, for example:
import { action, SingletonAction, WillAppearEvent } from "@elgato/streamdeck";
@action({ UUID: "com.elgato.test.one" })
export class IncrementCounter extends SingletonAction {
/**
* Occurs when the action will appear.
*/
override async onWillAppear(ev: WillAppearEvent): Promise<void> {
if (ev.action.isDial()) {
// Specify built-in layout name (e.g. "$B1"), or path to the custom layout file.
await ev.action.setFeedbackLayout("custom-layout.json");
}
}
}Updating Layout Items
Layout items can be updated at runtime using the setFeedback function, with items referenced by their key. All properties, with the exception of their rect can be updated; in addition, the value of a layout item can be updated implicitly or explicitly.
The following example demonstrates updating the value of the indicator item implicitly:
import { action, DialUpEvent, SingletonAction } from "@elgato/streamdeck";
@action({ UUID: "com.elgato.layout-image-test.increment" })
export class IncrementCounter extends SingletonAction<CounterSettings> {
/**
* Occurs when the user releases a dial.
*/
override async onDialUp(ev: DialUpEvent<CounterSettings>): Promise<void> {
await ev.action.setFeedback({
indicator: 50,
});
}
}
/**
* Settings for {@link IncrementCounter}.
*/
type CounterSettings = {
count?: number;
incrementBy?: number;
};The following example demonstrates updating the value of the indicator item explicitly:
import { action, DialUpEvent, SingletonAction } from "@elgato/streamdeck";
@action({ UUID: "com.elgato.layout-image-test.increment" })
export class IncrementCounter extends SingletonAction<CounterSettings> {
/**
* Occurs when the user releases a dial.
*/
override async onDialUp(ev: DialUpEvent<CounterSettings>): Promise<void> {
await ev.action.setFeedback({
indicator: {
value: 50,
range: {
min: 0,
max: 100,
},
},
});
}
}
/**
* Settings for {@link IncrementCounter}.
*/
type CounterSettings = {
count?: number;
incrementBy?: number;
};
Trigger Descriptions
Trigger descriptions can help the user to understand what the encoder does in a particular dial action. This can be set in the manifest file using the Actions[].Encoder.TriggerDescriptions property.

{
"Actions": [
{
"Icon": "action-icon",
"Name": "Trigger Description Example",
"Controllers": ["Encoder"],
"Encoder": {
"layout": "$A1",
"TriggerDescription": {
"Push": "Play / Pause",
"Rotate": "Adjust Volume",
"Touch": "Play / Pause",
"LongTouch": "Skip Track"
}
}
}
]
// ...
}Update Trigger Descriptions
You can programmatically update the trigger descriptions using the setTriggerDescription function.
import { action, DialUpEvent, SingletonAction } from "@elgato/streamdeck";
@action({ UUID: "com.elgato.trigger-description-example.increment" })
export class IncrementCounter extends SingletonAction<CounterSettings> {
/**
* Occurs when the user releases a dial.
*/
override async onDialUp(ev: DialUpEvent<CounterSettings>): Promise<void> {
await ev.action.setTriggerDescription({
push: "Increment counter",
rotate: "Adjust increment",
touch: "Increment counter",
longTouch: "Reset counter",
});
}
}
/**
* Settings for {@link IncrementCounter}.
*/
type CounterSettings = {
count?: number;
incrementBy?: number;
};Events
Dial actions receive the following events, available as overridable methods on the SingletonAction class.
onDialDown
Occurs when the user presses a dial (Stream Deck +). See also SingletonAction.onDialUp.
NB: For other action types see SingletonAction.onKeyDown.
function onDialDown?(ev: DialDownEvent): void | Promise<void>Parameters
ev: DialDownEventRequired
Information about the event, including the source action and contextual payload information.
onDialRotate
Occurs when the user rotates a dial (Stream Deck +).
function onDialRotate?(ev: DialRotateEvent): void | Promise<void>Parameters
ev: DialRotateEventRequired
Information about the event, including the source action and contextual payload information.
onDialUp
Occurs when the user releases a pressed dial (Stream Deck +). See also SingletonAction.onDialDown.
NB: For other action types see SingletonAction.onKeyUp.
function onDialUp?(ev: DialUpEvent): void | Promise<void>Parameters
ev: DialUpEventRequired
Information about the event, including the source action and contextual payload information.
onDidReceiveResources
Occurs when the resources are updated within the property inspector.
function onDidReceiveResources?(ev: DidReceiveResourcesEvent): void | Promise<void>Parameters
ev: DidReceiveResourcesEventRequired
Function to be invoked when the event occurs.
onDidReceiveSettings
Occurs when the settings are updated within the property inspector.
When streamDeck.settings.useLegacySettingsBehavior is set to true, this also fires after
calling getSettings().
function onDidReceiveSettings?(ev: DidReceiveSettingsEvent): void | Promise<void>Parameters
ev: DidReceiveSettingsEventRequired
Information about the event, including the source action and contextual payload information.
onPropertyInspectorDidAppear
Occurs when the property inspector associated with the action becomes visible, i.e. the user selected an action in the Stream Deck application. See also streamDeck.ui.onDidAppear.
function onPropertyInspectorDidAppear?(ev: PropertyInspectorDidAppearEvent): void | Promise<void>Parameters
ev: PropertyInspectorDidAppearEventRequired
Information about the event, including the source action.
onPropertyInspectorDidDisappear
Occurs when the property inspector associated with the action becomes invisible, i.e. the user unselected the action in the Stream Deck application. See also streamDeck.ui.onDidDisappear.
function onPropertyInspectorDidDisappear?(ev: PropertyInspectorDidDisappearEvent): void | Promise<void>Parameters
ev: PropertyInspectorDidDisappearEventRequired
Information about the event, including the source action.
onSendToPlugin
Occurs when a message was sent to the plugin from the property inspector. The plugin can also send messages to the property inspector using streamDeck.ui.sendToPropertyInspector.
function onSendToPlugin?(ev: SendToPluginEvent): void | Promise<void>Parameters
ev: SendToPluginEventRequired
Information about the event, including the source action and contextual payload information.
onTitleParametersDidChange
Occurs when the user updates an action's title settings in the Stream Deck application.
function onTitleParametersDidChange?(ev: TitleParametersDidChangeEvent): void | Promise<void>Parameters
ev: TitleParametersDidChangeEventRequired
Information about the event, including the source action and contextual payload information.
onTouchTap
Occurs when the user taps the touchscreen (Stream Deck +).
function onTouchTap?(ev: TouchTapEvent): void | Promise<void>Parameters
ev: TouchTapEventRequired
Information about the event, including the source action and contextual payload information.
onWillAppear
Occurs when an action appears on the Stream Deck due to the user navigating to another page, profile, folder, etc. This also occurs during startup if the action is on the "front page". An action refers to all types of actions, e.g. keys, dials,
function onWillAppear?(ev: WillAppearEvent): void | Promise<void>Parameters
ev: WillAppearEventRequired
Information about the event, including the source action and contextual payload information.
onWillDisappear
Occurs when an action disappears from the Stream Deck due to the user navigating to another page, profile, folder, etc. An action refers to all types of actions, e.g. keys, dials, touchscreens, pedals, etc.
function onWillDisappear?(ev: WillDisappearEvent): void | Promise<void>Parameters
ev: WillDisappearEventRequired
Information about the event, including the source action and contextual payload information.
Commands
The following commands are available to dial actions.
Some events, such as onWillAppear, are applicable to all action types. To invoke commands only available to dial actions within these events, you must first assert the action is a dial by calling ev.action.isDial().
getResources
Gets the resources (files) associated with this action; these resources are embedded into the action when it is exported, either individually, or as part of a profile.
Available from Stream Deck 7.1.
function getResources(): Promise<Resources>getSettings
Gets the settings associated this action instance.
function getSettings(): Promise<TSettings>setFeedback
Sets the feedback for the current layout associated with this action instance, allowing for the visual items to be updated. Layouts are a powerful way to provide dynamic information
to users, and can be assigned in the manifest, or dynamically via DialAction.setFeedbackLayout.
The feedback payload defines which items within the layout will be updated, and are identified by their property name (defined as the key in the layout's definition).
The values can either by a complete new definition, a string for layout item types of text and pixmap, or a number for layout item types of bar and gbar.
function setFeedback(feedback: FeedbackPayload): Promise<void>Parameters
feedback: FeedbackPayloadRequired
Object containing information about the layout items to be updated.
setFeedbackLayout
Sets the layout associated with this action instance. The layout must be either a built-in layout identifier, or path to a local layout JSON file within the plugin's folder.
Use in conjunction with DialAction.setFeedback to update the layout's current items' settings.
function setFeedbackLayout(layout: string): Promise<void>Parameters
layout: stringRequired
Name of a pre-defined layout, or relative path to a custom one.
setImage
Sets the image to be display for this action instance within Stream Deck app.
NB: The image can only be set by the plugin when the the user has not specified a custom image.
function setImage(image?: string): Promise<void>Parameters
image: string
Image to display; this can be either a path to a local file within the plugin's folder, a base64 encoded string with the mime type declared (e.g. PNG, JPEG, etc.),
or an SVG string. When undefined, the image from the manifest will be used.
setResources
Sets the resources (files) associated with this action; these resources are embedded into the action when it is exported, either individually, or as part of a profile.
Available from Stream Deck 7.1.
function setResources(resources: Resources): Promise<void>Parameters
resources: ResourcesRequired
The resources as a map of file paths.
setSettings
Sets the settings associated with this action instance.
function setSettings(value: TSettings): Promise<void>Parameters
value: TSettingsRequired
Settings to persist.
setTitle
Sets the title displayed for this action instance.
NB: The title can only be set by the plugin when the the user has not specified a custom title.
function setTitle(title: string): Promise<void>Parameters
title: stringRequired
Title to display.
setTriggerDescription
Sets the trigger (interaction) descriptions associated with this action instance. Descriptions are shown within the Stream Deck application, and informs the user what
will happen when they interact with the action, e.g. rotate, touch, etc. When descriptions is undefined, the descriptions will be reset to the values provided as part
of the manifest.
NB: Applies to encoders (dials / touchscreens) found on Stream Deck + devices.
function setTriggerDescription(descriptions?: TriggerDescriptionOptions): Promise<void>Parameters
descriptions: TriggerDescriptionOptions
Descriptions that detail the action's interaction.
showAlert
Shows a temporary alert (i.e. warning) indicator on the touch strip associated with the action.
function showAlert(): Promise<void>