@fcannizzaro/streamdeck-react

TouchStrip Hooks

React hooks for the Stream Deck+ shared touch strip -- geometry, tap events, dial rotation, and dial press within a touchStrip component.

TouchStrip hooks are available inside a touchStrip component registered via defineAction. They provide geometry info, tap coordinates, and per-dial events with column identification.

These hooks are only available inside a touchStrip component. For per-encoder hooks (one React root per dial), see Event Hooks.

useTouchStrip

Returns the current touch strip geometry and configuration.

function useTouchStrip(): TouchStripInfo;
interface TouchStripInfo {
  /** Full strip width in pixels (e.g. 800 for 4 encoders). */
  width: number;
  /** Strip height in pixels (always 100). */
  height: number;
  /** Sorted list of active encoder columns, e.g. [0, 1, 3]. */
  columns: number[];
  /** Width of each encoder segment in pixels (always 200). */
  segmentWidth: number;
  /** Target FPS from the action definition. */
  fps: number;
}
function MyTouchStrip() {
  const { width, height, fps, columns, segmentWidth } = useTouchStrip();

  return (
    <div style={{ width, height, background: "#1a1a2e" }}>
      <span style={{ color: "white", fontSize: 14 }}>
        {columns.length} dials active — {width}x{height}
      </span>
    </div>
  );
}

useTouchStripTap

Fires when the touch strip is tapped. Coordinates are absolute across the full strip width.

function useTouchStripTap(callback: (payload: TouchStripTapPayload) => void): void;
interface TouchStripTapPayload {
  /** Absolute tap position across the full strip. */
  tapPos: [x: number, y: number];
  /** Whether it was a long press. */
  hold: boolean;
  /** The encoder column that was touched. */
  column: number;
}
function MyTouchStrip() {
  const { width, height } = useTouchStrip();
  const [marker, setMarker] = useState(0);

  useTouchStripTap(({ tapPos }) => {
    setMarker(tapPos[0]);
  });

  return (
    <div style={{ width, height, position: "relative", background: "#1a1a2e" }}>
      <div
        style={{
          position: "absolute",
          left: marker,
          top: 0,
          width: 2,
          height,
          background: "#ff3366",
        }}
      />
    </div>
  );
}

Tap coordinates are translated from per-segment local coordinates to absolute strip coordinates automatically. A tap at local [50, 30] on column 2 becomes [450, 30].

useTouchStripDialRotate

Fires when any dial is rotated. The column field identifies which dial.

function useTouchStripDialRotate(callback: (payload: TouchStripDialRotatePayload) => void): void;
interface TouchStripDialRotatePayload {
  /** Which encoder column was rotated (0-indexed). */
  column: number;
  /** Signed rotation amount. Positive = clockwise. */
  ticks: number;
  /** Whether the dial was pressed while rotating. */
  pressed: boolean;
}
useTouchStripDialRotate(({ column, ticks }) => {
  if (column === 0) {
    // Dial 0: steer
    setDirection((d) => (ticks > 0 ? turnRight(d) : turnLeft(d)));
  } else if (column === 1) {
    // Dial 1: speed
    setSpeed((s) => Math.max(1, s + ticks));
  }
});

useTouchStripDialDown

Fires when a dial is pressed down.

function useTouchStripDialDown(callback: (payload: TouchStripDialPressPayload) => void): void;
interface TouchStripDialPressPayload {
  /** Which encoder column was pressed (0-indexed). */
  column: number;
}

useTouchStripDialUp

Fires when a dial is released.

function useTouchStripDialUp(callback: (payload: TouchStripDialPressPayload) => void): void;

Same payload as useTouchStripDialDown.

TouchStrip vs Per-Encoder Hooks

TouchStrip hooksPer-encoder hooks
ComponenttouchStrip in defineActiondial in defineAction
React rootsOne shared tree for the full stripOne root per encoder slot
Event routingAll events arrive in one component; use column to distinguishEach component only receives its own dial's events
Canvas sizeFull strip (e.g. 800x100)Single segment (200x100)
HooksuseTouchStrip* familyuseDialRotate, useDialDown, useTouchTap, etc.

On this page