Dial & Encoder Support
Build encoder-aware actions with dial rendering, rotation handlers, and trigger hints.
Stream Deck+ encoder actions combine three capabilities:
- Dial rendering on the encoder display.
- Rotation and press events through the event hooks.
- Touch taps through
useTouchTap().
Dial Rendering
The dial component defined in defineAction renders to the encoder display. The library pushes the image with action.setFeedback().
function VolumeDial() {
const [volume, setVolume] = useState(50);
const [muted, setMuted] = useState(false);
useDialRotate(({ ticks }) => {
if (!muted) {
setVolume((v) => Math.max(0, Math.min(100, v + ticks * 2)));
}
});
useDialDown(() => {
setMuted((m) => !m);
});
useDialHint({
rotate: 'Adjust volume',
press: muted ? 'Unmute' : 'Mute',
});
return (
<div style={{
width: '100%', height: '100%',
flexDirection: 'column',
alignItems: 'center', justifyContent: 'center',
background: muted ? '#4a0000' : '#1a1a1a',
gap: 4,
}}>
<span style={{ color: '#888', fontSize: 12 }}>Volume</span>
<span style={{
color: muted ? '#ff4444' : 'white',
fontSize: 24, fontWeight: 700,
}}>
{muted ? 'MUTE' : `${volume}%`}
</span>
{!muted && (
<ProgressBar value={volume} height={4} color="#4CAF50" background="#333" borderRadius={2} />
)}
</div>
);
}
export const volumeAction = defineAction<VolumeSettings>({
uuid: 'com.example.plugin.volume',
dial: VolumeDial,
defaultSettings: { volume: 50, muted: false },
});Trigger Descriptions
Stream Deck+ shows contextual hints for what each dial action does. Use useDialHint to set these:
useDialHint({
rotate: 'Adjust volume',
press: 'Toggle mute',
touch: 'Open settings',
longTouch: 'Reset to default',
});The hints update automatically when the values change. Under the hood this calls action.setTriggerDescription().
Touch Interaction
Use useTouchTap() when your encoder action needs touch input from the Stream Deck+ touch area:
function VolumeDial() {
useTouchTap(({ tapPos, hold }) => {
console.log('touch', tapPos, hold);
});
return <div style={{ width: '100%', height: '100%' }} />;
}Key + Dial Actions
An action can support both key and encoder placement. Define separate components:
export const volumeAction = defineAction<VolumeSettings>({
uuid: 'com.example.plugin.volume',
key: VolumeKey, // Rendered when placed on a key
dial: VolumeDial, // Rendered when placed on an encoder
defaultSettings: { volume: 50, muted: false },
});If dial is not provided, the key component is used as a fallback for encoder placement.