20 min read

Source: Roblox Creator Hub · CC BY 4.0 · View source · Code samples: MIT Imported 2026-10-03. Formatting adapted for this site.

Input Action System

The cross-platform Input Action System lets you connect actions and arrange bindings across various hardware inputs at edit time. Combined with contexts, you can easily configure and edit a modular input system that works on any device in any phase of play. Use cases include:

Input contexts

An InputContext is a collection of actions which holds related input actions, for example PlayContext for in‑game character controls and NavContext for controls to navigate around UI menus. You can enable/disable contexts (and their corresponding actions) through their Enabled property, such as to enable the NavContext when an inventory menu is open and then change to the PlayContext when the player closes the menu and returns to primary gameplay.

Even if a game may not use multiple input contexts initially, it's recommended to create a primary context at the top level of any input system, for example the PlayContext instance for input that occurs during gameplay.

Create a Folder named Inputs inside ReplicatedStorage to hold various input contexts.

New Folder inside ReplicatedStorage, renamed to Inputs
  1. Insert a new InputContext into the folder and rename it to PlayContext.

    New InputContext instance inside ReplicatedStorage, renamed to PlayContext

In the Properties window, set Priority to 2000 and enable Sink. A context with Sink enabled consumes input events for its bound KeyCodes at its priority level, blocking those inputs from reaching lower-priority contexts. This is practical for use cases like an inventory screen that should suppress specific gameplay inputs while open. In this example, PlayContext is given a high enough Priority to sink its bound inputs before the default PlayerScripts contexts process them.

InputContext with Priority set to 2000 and Sink enabled

Input actions

An InputAction defines a gameplay action mechanic such as "Jump," "Sprint," or "Shoot." These actions are then mapped to hardware inputs using input bindings.

An InputAction can be of several variations depending on its Type property (InputActionType). The default is Bool, designed to receive true/false values from press/release of inputs such as ButtonA, E, or MouseLeftButton.

Note

InputAction also exposes a read-only PreferredBinding property that returns the child InputBinding best matching the player's current input device (keyboard/mouse, gamepad, or touch). It updates dynamically as the player's device configuration changes and is the basis for displaying bindings to players.

Input Action Type Example Usage
[`Bool`](/docs/enum-inputactiontype) Triggered actions such as jump, shoot, sprint, etc. with support for pressed/released thresholds on analog inputs.
[`Direction1D`](/docs/enum-inputactiontype) Variable zero-to-full actions such as a car's accelerator pedal or a view scope's zoom level.
[`Direction2D`](/docs/enum-inputactiontype) 2D directional movement such as camera rotation, or the standard Roblox character movement.
[`Direction3D`](/docs/enum-inputactiontype) 3D directional movement like an airborne vehicle that can levitate up/down, accelerate/decelerate, and drift left/right.
[`ViewportPosition`](/docs/enum-inputactiontype) 2D viewport coordinates like mouse input, such as for custom cursors or raycasting to select world objects.

Character Sprint

To test an InputAction for simple character sprinting:

Select the top-level Workspace object in the Explorer and then, in the Properties window, set the PlayerScriptsUseInputActionSystem property to Enabled.

  1. Create a new InputAction inside the PlayContext context within ReplicatedStorage. Rename it to CharacterSprint to indicate its dedicated action.

    New InputAction instance inside an InputContext, renamed to CharacterSprint
  2. In the Properties window, notice that the action's Type is Bool (default). This is a logical type for simple character sprinting as a boolean true/false action (character is either sprinting or not sprinting).

    Type property of an InputAction set to Bool

Camera Rotation

To test an InputAction for camera rotation:

  1. Create a new InputAction inside the PlayContext context within ReplicatedStorage. Rename it to CameraRotate to indicate its dedicated action.

    New InputAction instance inside an InputContext, renamed to CameraRotate
  2. In the Properties window, set the action's Type to Direction2D. This reflects that camera rotation is a continuous 2D analog input rather than a discrete press/release.

    Type property of an InputAction set to Direction2D

Input bindings

An InputBinding defines which hardware binding should trigger the parent InputAction, for example a key press, gamepad button, or tap on a touch‑enabled device. For cross‑platform compatibility, each InputAction should have an InputBinding for gamepad, keyboard/mouse, and touch as illustrated here.

Default Bindings

Roblox provides default input bindings for movement, camera control, and basic environment interaction — Roblox players are familiar with these controls, so you should only override them in specific cases. Also note that the reserved inputs cannot be overridden and will always operate with their intended purpose.

Roblox Reserved

Action Mouse/Keyboard Gamepad Touch
Open Roblox menu Esc Start button ([`ButtonStart`](/docs/enum-keycode)) N/A
[Developer Console](/docs/roblox-studio-developer-console) F9 N/A N/A
Fullscreen mode (Windows)
Show desktop (Mac)
F11 N/A N/A
Record video (Windows) F12 N/A N/A
Take screenshot PrintScreen N/A N/A

Character

Action Mouse/Keyboard Gamepad Touch
Move forward W ↑ Press up on primary thumbstick Press up on virtual thumbstick
Move backward S ↓ Press down on primary thumbstick Press down on virtual thumbstick
Move left A Press left on primary thumbstick Press left on virtual thumbstick
Move right D Press right on primary thumbstick Press right on virtual thumbstick
Jump Space   Tap virtual jump button

Interface / Inventory

Note

The following action inputs are reserved unless you disable the respective feature.

Action Mouse/Keyboard Gamepad Touch
Open text chat / N/A N/A
Show/hide players list Tab N/A N/A
Toggle backpack ` N/A N/A
Equip/unequip tools 0-9 Swap between tools using front‑left and front‑right triggers ([`ButtonL1`](/docs/enum-keycode#buttonl1) and [`ButtonR1`](/docs/enum-keycode#buttonr1)) Tap on-screen tool icons
Use equipped tool Click left mouse button Back‑right trigger ([`ButtonR2`](/docs/enum-keycode#buttonr2)) Tap on screen
Drop equipped tool Backspace N/A N/A
Toggle **UI selection** mode¹ \ Select button ([`ButtonSelect`](/docs/enum-keycode#buttonselect)) N/A
Navigate among interactive UI elements while in **UI selection** mode ↑ ↓ ← →
W S A D
Primary thumbstick ([`Thumbstick1`](/docs/enum-keycode#thumbstick1)) or D‑pad ([`DPadUp`](/docs/enum-keycode#dpadup); [`DPadDown`](/docs/enum-keycode#dpaddown); [`DPadLeft`](/docs/enum-keycode#dpadleft); [`DPadRight`](/docs/enum-keycode#dpadright))
Activate an interactive UI element while in **UI selection** mode Enter Back‑right trigger ([`ButtonR2`](/docs/enum-keycode#buttonr2))
Scroll up/down/left/right in selected [`ScrollingFrame`](/docs/scrollingframe) while in **UI selection** mode PageUp
PageDown
Home
End
Secondary thumbstick ([`Thumbstick2`](/docs/enum-keycode#thumbstick2))

¹ If GuiNavigationEnabled is enabled (default)

Camera

Action Mouse/Keyboard Gamepad Touch
Move camera view around While holding right mouse button Move secondary thumbstick Touch-drag around screen
Zoom camera in/out Mouse scroll wheel
I/O
Press secondary thumbstick Pinch in/out on screen
Rotate camera left or right ← → N/A N/A
Toggle mouse lock² Shift N/A N/A

² If EnableMouseLockOption is enabled (default)


The Type assigned to the parent InputAction directly affects which general input types (key/button/tap, analog trigger, thumbstick, etc.) are valid for child InputBinding instances. In turn, values sent to the parent action's connected events depend on a binding's chosen input type. See input events for details on the correlation between action types, bindings, and return values.

Character Sprint

To hook up bindings for simple character sprinting:

  1. Insert a new InputBinding into the CharacterSprint action and rename it to KeyboardBinding. Then set the binding's KeyCode property to LeftShift.

  2. Insert a second InputBinding into the CharacterSprint action and rename it to GamepadBinding. Then set the binding's KeyCode property to ButtonY.

  3. Inside a ScreenGui container inside StarterGui, create an on-screen button, rename it to SprintButton, and position/resize it as desired.

  4. Insert a third InputBinding into the CharacterSprint action and rename it to TouchBinding. Then, in the Properties window, link the binding's UIButton property to the SprintButton button you created previously inside StarterGui.

Camera Rotation

To hook up bindings for camera rotation:

  1. Insert a new InputBinding into the CameraRotate action and rename it to KeyboardBinding. Leave KeyCode empty and instead set the four composite directional properties — Left, Right, Up, and Down — to Left, Right, Up, and Down respectively.

  2. Insert a second InputBinding and rename it to GamepadBinding. Then set the binding's KeyCode property to Thumbstick2 (right thumbstick).

  3. Insert a third InputBinding and rename it to MouseBinding. Set the binding's KeyCode property to MouseDelta and its Scale to 0.01. MouseDelta reports values in pixels, so the scale converts them to a reasonable rotation range.

  4. Insert a fourth InputBinding and rename it to TouchBinding. Set the binding's KeyCode property to TouchDelta and its Scale to 0.01. Like MouseDelta, TouchDelta reports values in pixels.

Input events

The InputAction instance has three built-in events to handle player input coming from InputBindings.

Depending on the input action's Type (Bool, Direction1D, Direction2D, Direction3D, or ViewportPosition) and the general input type coming from a child InputBinding (key/button/tap, analog trigger, thumbstick, etc.), different values are returned to the Pressed, Released, and StateChanged event handlers. Examine the following tables to better understand the correlation.

Bool

The Bool type is best for triggered actions such as jump, shoot, sprint, etc. with support for pressed/released thresholds on analog inputs.

Valid Input Types on [`InputBindings`](/docs/inputbinding) Returned to the [`InputAction`](/docs/inputaction) Event(s)
Boolean inputs from keyboard keys or basic mouse/gamepad buttons through the binding's [`KeyCode`](/docs/inputbinding#inputbinding-keycode) property, or a [`GuiButton`](/docs/guibutton) press/release through the binding's [`UIButton`](/docs/inputbinding#inputbinding-uibutton) property.
  • [`Pressed`](/docs/inputaction#inputaction-pressed) event:
    • `true` when pressed
  • [`Released`](/docs/inputaction#inputaction-released) event:
    • `true` when released
  • [`StateChanged`](/docs/inputaction#inputaction-statechanged) event:
    • `true` (pressed) or `false` (released)
Variable input amounts from analog inputs like gamepad triggers ([`ButtonL2`](/docs/enum-keycode#buttonl2)/[`ButtonR2`](/docs/enum-keycode#buttonr2)) through the binding's [`KeyCode`](/docs/inputbinding#inputbinding-keycode) property.
  • [`Pressed`](/docs/inputaction#inputaction-pressed) event:
    • `true` when trigger press is `>=` [`PressedThreshold`](/docs/inputbinding#inputbinding-pressedthreshold)
  • [`Released`](/docs/inputaction#inputaction-released) event:
    • `true` when trigger press is `<=` [`ReleasedThreshold`](/docs/inputbinding#inputbinding-releasedthreshold)
  • [`StateChanged`](/docs/inputaction#inputaction-statechanged) event:
    • `true` when trigger press is `>=` [`PressedThreshold`](/docs/inputbinding#inputbinding-pressedthreshold)
    • `false` when trigger press is `<=` [`ReleasedThreshold`](/docs/inputbinding#inputbinding-releasedthreshold)

Direction1D

The Direction1D type is best for variable zero‑to‑full actions such as a car's accelerator pedal or a view scope's zoom level.

Valid Input Types on [`InputBindings`](/docs/inputbinding) Returned to the [`InputAction`](/docs/inputaction) Event(s)
Variable input amounts from analog inputs like gamepad triggers ([`ButtonL2`](/docs/enum-keycode#buttonl2)/[`ButtonR2`](/docs/enum-keycode#buttonr2)) through the binding's [`KeyCode`](/docs/inputbinding#inputbinding-keycode), [`Up`](/docs/inputbinding#inputbinding-up), and [`Down`](/docs/inputbinding#inputbinding-down) properties.
  • [`StateChanged`](/docs/inputaction#inputaction-statechanged) event:
    • `0` to `1` (fully released to fully pressed) through the [`KeyCode`](/docs/inputbinding#inputbinding-keycode) or [`Up`](/docs/inputbinding#inputbinding-up) properties
    • `0` to `-1` (fully released to fully pressed) through the [`Down`](/docs/inputbinding#inputbinding-down) property
Boolean inputs from keyboard keys or basic mouse/gamepad buttons through the binding's [`KeyCode`](/docs/inputbinding#inputbinding-keycode), [`Up`](/docs/inputbinding#inputbinding-up), and [`Down`](/docs/inputbinding#inputbinding-down) properties.
  • [`StateChanged`](/docs/inputaction#inputaction-statechanged) event:
    • `1` (pressed) or `0` (released) through the [`KeyCode`](/docs/inputbinding#inputbinding-keycode) or [`Up`](/docs/inputbinding#inputbinding-up) properties
    • `-1` (pressed) or `0` (released) through the [`Down`](/docs/inputbinding#inputbinding-down) property

Direction2D

The Direction2D type is best for 2D directional movement such as camera rotation, or the standard Roblox character movement.

Valid Input Types on [`InputBindings`](/docs/inputbinding) Returned to the [`InputAction`](/docs/inputaction) Event(s)
Variable input amounts from 2D analog inputs like gamepad thumbsticks ([`Thumbstick1`](/docs/enum-keycode#thumbstick1)/[`Thumbstick2`](/docs/enum-keycode#thumbstick2)) through the binding's [`KeyCode`](/docs/inputbinding#inputbinding-keycode) property.
  • [`StateChanged`](/docs/inputaction#inputaction-statechanged) event:
    • [`Vector2`](/docs/vector2) between `(-1, -1)` and `(1, 1)`
Variable input amounts from analog inputs like gamepad triggers ([`ButtonL2`](/docs/enum-keycode#buttonl2)/[`ButtonR2`](/docs/enum-keycode#buttonr2)) through the binding's [`Up`](/docs/inputbinding#inputbinding-up), [`Down`](/docs/inputbinding#inputbinding-down), [`Left`](/docs/inputbinding#inputbinding-left), and [`Right`](/docs/inputbinding#inputbinding-right) properties.
  • [`StateChanged`](/docs/inputaction#inputaction-statechanged) event:
    • [`Vector2`](/docs/vector2) with [`Y`](/docs/vector2#vector2-y) component between `0` and `1` (fully released to fully pressed) through the [`Up`](/docs/inputbinding#inputbinding-up) property
    • [`Vector2`](/docs/vector2) with [`Y`](/docs/vector2#vector2-y) component between `0` and `-1` (fully released to fully pressed) through the [`Down`](/docs/inputbinding#inputbinding-down) property
    • [`Vector2`](/docs/vector2) with [`X`](/docs/vector2#vector2-x) component between `0` and `-1` (fully released to fully pressed) through the [`Left`](/docs/inputbinding#inputbinding-left) property
    • [`Vector2`](/docs/vector2) with [`X`](/docs/vector2#vector2-x) component between `0` and `1` (fully released to fully pressed) through the [`Right`](/docs/inputbinding#inputbinding-right) property
Boolean inputs from keyboard keys or basic mouse/gamepad buttons through the binding's [`Up`](/docs/inputbinding#inputbinding-up), [`Down`](/docs/inputbinding#inputbinding-down), [`Left`](/docs/inputbinding#inputbinding-left), and [`Right`](/docs/inputbinding#inputbinding-right) properties.
  • [`StateChanged`](/docs/inputaction#inputaction-statechanged) event:
    • [`Vector2`](/docs/vector2) of `(0, 1)` (pressed) or

      (0, 0) (released) through the Up property

    • Vector2 of (0, -1) (pressed) or

      (0, 0) (released) through the Down property

    • Vector2 of (-1, 0) (pressed) or

      (0, 0) (released) through the Left property

    • Vector2 of (1, 0) (pressed) or

      (0, 0) (released) through the Right property

Direction3D

The Direction3D type is best for 3D directional movement like an airborne vehicle that can levitate up/down, accelerate/decelerate, and drift left/right.

Valid Input Types on [`InputBindings`](/docs/inputbinding) Returned to the [`InputAction`](/docs/inputaction) Event(s)
Variable input amounts from analog inputs like gamepad triggers ([`ButtonL2`](/docs/enum-keycode#buttonl2)/[`ButtonR2`](/docs/enum-keycode#buttonr2)) through the binding's [`Up`](/docs/inputbinding#inputbinding-up), [`Down`](/docs/inputbinding#inputbinding-down), [`Left`](/docs/inputbinding#inputbinding-left), [`Right`](/docs/inputbinding#inputbinding-right), [`Forward`](/docs/inputbinding#inputbinding-forward), and [`Backward`](/docs/inputbinding#inputbinding-backward) properties.
  • [`StateChanged`](/docs/inputaction#inputaction-statechanged) event:
    • [`Vector3`](/docs/vector3) with [`Y`](/docs/vector3#vector3-y) component between `0` and `1` (fully released to fully pressed) through the [`Up`](/docs/inputbinding#inputbinding-up) property
    • [`Vector3`](/docs/vector3) with [`Y`](/docs/vector3#vector3-y) component between `0` and `-1` (fully released to fully pressed) through the [`Down`](/docs/inputbinding#inputbinding-down) property
    • [`Vector3`](/docs/vector3) with [`X`](/docs/vector3#vector3-x) component between `0` and `-1` (fully released to fully pressed) through the [`Left`](/docs/inputbinding#inputbinding-left) property
    • [`Vector3`](/docs/vector3) with [`X`](/docs/vector3#vector3-x) component between `0` and `1` (fully released to fully pressed) through the [`Right`](/docs/inputbinding#inputbinding-right) property
    • [`Vector3`](/docs/vector3) with [`Z`](/docs/vector3#vector3-z) component between `0` and `-1` (fully released to fully pressed) through the [`Forward`](/docs/inputbinding#inputbinding-forward) property
    • [`Vector3`](/docs/vector3) with [`Z`](/docs/vector3#vector3-z) component between `0` and `1` (fully released to fully pressed) through the [`Backward`](/docs/inputbinding#inputbinding-backward) property
Boolean inputs from keyboard keys or basic mouse/gamepad buttons through the binding's [`Up`](/docs/inputbinding#inputbinding-up), [`Down`](/docs/inputbinding#inputbinding-down), [`Left`](/docs/inputbinding#inputbinding-left), [`Right`](/docs/inputbinding#inputbinding-right), [`Forward`](/docs/inputbinding#inputbinding-forward), and [`Backward`](/docs/inputbinding#inputbinding-backward) properties.
  • [`StateChanged`](/docs/inputaction#inputaction-statechanged) event:
    • [`Vector3`](/docs/vector3) of `(0, 1, 0)` (pressed) or `(0, 0, 0)` (released) through the [`Up`](/docs/inputbinding#inputbinding-up) property
    • [`Vector3`](/docs/vector3) of `(0, -1, 0)` (pressed) or `(0, 0, 0)` (released) through the [`Down`](/docs/inputbinding#inputbinding-down) property
    • [`Vector3`](/docs/vector3) of `(-1, 0, 0)` (pressed) or `(0, 0, 0)` (released) through the [`Left`](/docs/inputbinding#inputbinding-left) property
    • [`Vector3`](/docs/vector3) of `(1, 0, 0)` (pressed) or `(0, 0, 0)` (released) through the [`Right`](/docs/inputbinding#inputbinding-right) property
    • [`Vector3`](/docs/vector3) of `(0, 0, -1)` (pressed) or `(0, 0, 0)` (released) through the [`Forward`](/docs/inputbinding#inputbinding-forward) property
    • [`Vector3`](/docs/vector3) of `(0, 0, 1)` (pressed) or `(0, 0, 0)` (released) through the [`Backward`](/docs/inputbinding#inputbinding-backward) property

ViewportPosition

The ViewportPosition type is best for absolute 2D viewport coordinates of an input such as a mouse pointer or touch, which can be used for features like custom cursors or selecting objects.

Valid Input Types on [`InputBindings`](/docs/inputbinding) Returned to the [`InputAction`](/docs/inputaction) Event(s)
Variable input amounts from positional inputs such as a mouse pointer ([`MousePosition`](/docs/enum-keycode#mouseposition)) or touch ([`Touch`](/docs/enum-keycode)).
  • [`StateChanged`](/docs/inputaction#inputaction-statechanged) event:
    • [`Vector2`](/docs/vector2) between `(0, 0)` and the maximum absolute `(X, Y)` pixel size in the viewport.

Character Sprint

To connect events for simple character sprinting:

  1. Insert a new Script into the CharacterSprint tree, alongside the various input bindings. Then set its RunContext to Client and rename it to OnActivate.

  2. Paste the following code into the OnActivate script. Note the Pressed event connection on lines 13‑15 which doubles the character's walk speed when a sprint input binding is pressed, and the corresponding Released event connection on lines 16‑18 which resets the walk speed to default when a sprint input binding is released.

     ```lua title="OnActivate (Client Script)"
     local Players = game:GetService("Players")
    
     local player = Players.LocalPlayer
     local character = player.Character
     if not character or character.Parent == nil then
         character = player.CharacterAdded:Wait()
     end
     local humanoid = character:WaitForChild("Humanoid")
     local defaultWalkSpeed = humanoid.WalkSpeed
    
     local inputAction = script.Parent
    
     inputAction.Pressed:Connect(function()
         humanoid.WalkSpeed = defaultWalkSpeed * 2
     end)
     inputAction.Released:Connect(function()
         humanoid.WalkSpeed = defaultWalkSpeed
     end)
     ```
    
  3. Playtest your game and test the character sprint action with the bindings you chose previously: LeftShift for keyboard, ButtonY for gamepad, and the on‑screen SprintButton for touch‑enabled devices. Remember that you can use the Controller Emulator to test gamepad inputs directly in Roblox Studio.

Camera Rotation

For continuous analog inputs like camera rotation, StateChanged fires once when the state changes and does not signal until the next change, so a thumbstick held at a fixed angle only fires the event once. In these cases, poll GetState() each frame and multiply by delta time for frame-rate-independent behavior.

  1. Insert a new Script into the CameraRotate tree, alongside the various input bindings. Then set its RunContext to Client and rename it to OnInput.

  2. Paste the following code into the OnInput script.

    local RunService = game:GetService("RunService")
    
    local CAMERA_SENSITIVITY = 1.5 -- Radians per second at action state 1
    
    local inputAction = script.Parent
    local camera = workspace.CurrentCamera
    camera.CameraType = Enum.CameraType.Scriptable
    
    RunService:BindToRenderStep("CameraRotation", Enum.RenderPriority.Camera.Value, function(dt)
        local state = inputAction:GetState()
        if state.Magnitude > 0 then
            camera.CFrame = camera.CFrame
                * CFrame.Angles(0, -state.X * CAMERA_SENSITIVITY * dt, 0)
                * CFrame.Angles(-state.Y * CAMERA_SENSITIVITY * dt, 0, 0)
        end
    end)

Context changes

Once you have an input context such as PlayContext, you can enable/disable it during gameplay through scripting, change its Priority to determine which actions take precedence over others, and Sink inputs from being processed within contexts of lower priority.

  1. To make it easier to switch contexts from other scripts, insert a new BindableEvent into your inputs folder within ReplicatedStorage and rename it to ContextEvent.

  2. Create a new Script at the same level, set its RunContext to Client, and rename it to UpdateContext.

  3. Inside the UpdateContext script, paste the following code:

     ```lua title="UpdateContext (Client Script)"
     local ReplicatedStorage = game:GetService("ReplicatedStorage")
    
     local inputsFolder = ReplicatedStorage:WaitForChild("Inputs")
     local contextEvent = inputsFolder:WaitForChild("ContextEvent")
    
     -- Connect bindable event
     contextEvent.Event:Connect(function(targetContext, enabled)
         local context = inputsFolder:FindFirstChild(targetContext)
         if context then
             context.Enabled = enabled
             print(context.Name .. ": " .. tostring(context.Enabled))
         else
             warn("InputContext not found!")
         end
     end)
     ```
    
  4. With the UpdateContext script in place, you can now update a named InputContext by firing the bindable event, for example from a LocalScript that powers a GuiButton inside a ScreenGui container.

     ```lua title="Button Script"
     local ReplicatedStorage = game:GetService("ReplicatedStorage")
    
     local inputsFolder = ReplicatedStorage:WaitForChild("Inputs")
     local contextEvent = inputsFolder:WaitForChild("ContextEvent")
    
     local button = script.Parent
     button.Activated:Connect(function()
         -- Fire bindable event with target input context and enabled state
         contextEvent:Fire("PlayContext", true)
     end)
     ```

Displaying bindings

Once you've set up actions and bindings, you'll typically need to show players, via on‑screen assistive hints, which key or button triggers each action:

Keyboard Input

Gamepad Input


The Input Action System provides two approaches:

InputActionLabel — A no-code, drag-and-drop GuiObject that automatically displays the correct input per platform.

PreferredBinding — A read-only InputAction property for creators who want full control over how bindings are displayed in custom UI.

InputActionLabel

Note

This class/object is currently in beta. Enable it through File ⟩ Beta Features ⟩ InputActionLabel.

InputActionLabel is a GuiObject that you can insert into any ScreenGui or SurfaceGui. Once its InputAction property is set to reference an existing InputAction instance, it automatically resolves and displays the correct keybinding for the player's current input device — no scripting required. When the player switches devices (for example, picking up a gamepad after using a keyboard) or rebinds a control, the label updates instantly.

To add an InputActionLabel:

  1. Inside a ScreenGui container inside StarterGui, insert an InputActionLabel just like any other GuiObject.

  2. In the Properties window, set its InputAction property to the InputAction instance you want to display (for example, your "Sprint" action under ReplicatedStorage) and position/resize it as desired.

  3. When the label resolves what to show, it checks the following in order:

    1. Custom Images — If child InputBindings have their DisplayImage property set, the label renders those images directly.

    2. Platform Key Images — Lacking custom images, the label renders platform-provided images for child InputBindings through UserInputService:GetImageForKeyCode(), if such images are available. Composite bindings with modifiers show multiple icons with + separators.

    3. Custom Names — Lacking available images, if child InputBindings have their DisplayName property set, the label renders that text using the label's style properties.

    4. Platform Key Strings — Lacking all of the above, the label renders platform-provided strings through UserInputService:GetStringForKeyCode().

    5. If no InputAction is assigned or no child InputBinding exists, the label renders a placeholder icon.

PreferredBinding

For customized use cases where you need full control over hint display (custom animations, conditional visibility, composited layouts), you can use InputAction.PreferredBinding to query the current binding and build your own UI. PreferredBinding is a read-only property that returns the child InputBinding which best matches the player's current input device.

The following two InputBinding properties provide the custom display overrides used for PreferredBinding. If neither is set, fall back to platform-provided values via GetStringForKeyCode() and GetImageForKeyCode().

The following examples assume a client Script parented to the InputAction and a hint UI object (TextLabel or ImageLabel) inside a ScreenGui within the player's PlayerGui. Both connect to changes to PreferredBinding so that the hint refreshes whenever the player switches input devices.

local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")

local inputAction = script.Parent
local player = Players.LocalPlayer
local screenGui = player:WaitForChild("PlayerGui"):WaitForChild("ScreenGui")
local label = screenGui:FindFirstChildWhichIsA("TextLabel")

local function updateHintText()
	if not label then
		warn("Label UI object not found!")
		return
	end

	local binding = inputAction.PreferredBinding
	if binding and binding.DisplayName ~= "" then
		label.Text = binding.DisplayName
	elseif binding and binding.KeyCode ~= Enum.KeyCode.None then
		label.Text = UserInputService:GetStringForKeyCode(binding.KeyCode)
	else
		label.Text = ""
	end
end

inputAction:GetPropertyChangedSignal("PreferredBinding"):Connect(updateHintText)
updateHintText()
local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")

local inputAction = script.Parent
local player = Players.LocalPlayer
local screenGui = player:WaitForChild("PlayerGui"):WaitForChild("ScreenGui")
local label = screenGui:FindFirstChildWhichIsA("ImageLabel")

local function updateHintImage()
	if not label then
		warn("Label UI object not found!")
		return
	end

	local binding = inputAction.PreferredBinding
	if binding and binding.DisplayImage.SourceType ~= Enum.ContentSourceType.None then
		label.ImageContent = binding.DisplayImage
	elseif binding and binding.KeyCode ~= Enum.KeyCode.None then
		local keyImage = UserInputService:GetImageForKeyCode(binding.KeyCode)
		label.ImageContent = (keyImage ~= "") and Content.fromUri(keyImage) or Content.none
	else
		label.ImageContent = Content.none
	end
end

inputAction:GetPropertyChangedSignal("PreferredBinding"):Connect(updateHintImage)
updateHintImage()

Input Action Manager

Note

This tool is currently in beta. Enable it through File ⟩ Beta Features ⟩ Input Action Manager.

The Input Action Manager tool is a unified, matrix-style interface to design, audit, and scale your input architecture.

To access it, navigate to the Window menu in Studio and select Input ⟩ Input Action Manager. If your game already uses input contexts, actions, or bindings, the manager will automatically scan the DataModel and extract those existing instances into the editor grid. Any new input‑related instances will automatically populate into an Inputs folder within ReplicatedStorage.

Folder inside ReplicatedStorage named Inputs

To configure an input setup for character sprint as outlined in the sections above:

Select the top-level Workspace object in the Explorer and then, in the Properties window, set the PlayerScriptsUseInputActionSystem property to Enabled.

  1. Inside a ScreenGui container inside StarterGui, create an on-screen button, rename it to SprintButton, and position/resize it as desired.

  2. In the Input Action Manager, hover over the Context column header and click the + button. Enter an appropriate name for the new context such as PlayContext and press Enter. An InputContext of the matching name appears in ReplicatedStorage.

    New InputContext instance inside ReplicatedStorage named PlayContext
  3. Hover over the new context and click the + button. From the popup menu, select Bool, enter CharacterSprint for the action's name, and press Enter. An InputAction of the matching name appears under the context.

    New InputAction instance inside an InputContext named CharacterSprint
  4. In the new CharacterSprint row, assign bindings for each input type:

    1. Keyboard and Mouse — Click the arrow button and select LeftShift from the picker menu.
    2. Touch — Click the cell and then, in the Explorer hierarchy, click the SprintButton object that you previously inserted into the ScreenGui.
    3. Gamepad — Click the arrow button and select ButtonY from the picker menu.

Note

As you assign bindings, watch for warning/error icons in the UI. Yellow warnings (⚠) indicate a missing binding for cross‑platform compatibility, while red warnings (⚠) indicate a duplicate binding for actions within the same context.

  1. Insert a new Script into the CharacterSprint tree, alongside the various input bindings. Then set its RunContext to Client and rename it to OnActivate.

  2. Paste the following code into the OnActivate script. Note the Pressed event connection on lines 13‑15 which doubles the character's walk speed when a sprint input binding is pressed, and the corresponding Released event connection on lines 16‑18 which resets the walk speed to default when a sprint input binding is released.

     ```lua title="OnActivate (Client Script)"
     local Players = game:GetService("Players")
    
     local player = Players.LocalPlayer
     local character = player.Character
     if not character or character.Parent == nil then
         character = player.CharacterAdded:Wait()
     end
     local humanoid = character:WaitForChild("Humanoid")
     local defaultWalkSpeed = humanoid.WalkSpeed
    
     local inputAction = script.Parent
    
     inputAction.Pressed:Connect(function()
         humanoid.WalkSpeed = defaultWalkSpeed * 2
     end)
     inputAction.Released:Connect(function()
         humanoid.WalkSpeed = defaultWalkSpeed
     end)
     ```