Core Concepts
StimulusReflex enables reactive, real-time user interfaces in Rails applications using WebSockets (ActionCable) and CableReady.
Basic Reflex
<!-- view.html.erb -->
<button data-reflex="click->Counter#increment">Increment</button>
# app/reflexes/counter_reflex.rb
class CounterReflex < ApplicationReflex
def increment
@count = element.dataset[:count].to_i + 1
end
end
Morph Modes
Page Morph (Default)
Re-renders the entire page via controller action and morphs differences into the DOM.
Selector Morph
# app/reflexes/example_reflex.rb
class ExampleReflex < ApplicationReflex
def update_metric
morph "#metric-display", render(partial: "metrics/metric", locals: { value: 42 })
end
end
Nothing Morph
Executes server-side logic without updating the client DOM.
class ExampleReflex < ApplicationReflex
def background_task
LongRunningJob.perform_later
morph :nothing
end
end
Lifecycle Methods
Server-side Callbacks
class ExampleReflex < ApplicationReflex
before_reflex :authenticate
around_reflex :measure_time
after_reflex :log_activity
end
Client-side Generic Callbacks
beforeReflex(element, reflex, noop, reflexId): Before sending WebSocket requestreflexSuccess(element, reflex, noop, reflexId): After reflex execution and DOM updatereflexError(element, reflex, error, reflexId): When server raises an unhandled errorreflexHalted(element, reflex, noop, reflexId): When reflex is aborted withthrow :abortafterReflex(element, reflex, noop, reflexId): Executed on both success and failurefinalizeReflex(element, reflex, noop, reflexId): Final cleanup hook
DOM Events
stimulus-reflex:beforestimulus-reflex:successstimulus-reflex:errorstimulus-reflex:haltedstimulus-reflex:afterstimulus-reflex:connectedstimulus-reflex:disconnectedstimulus-reflex:ready
Practical Patterns
Form Handling
Reflexes triggered inside or on form elements automatically serialize and pass inputs into params.
Promise Chaining
this.stimulate('Comments#create')
.then(() => this.showSuccess())
.catch((err) => this.handleError(err))
Permanent Elements
Mark elements with data-reflex-permanent so that full-page morphs leave them untouched.
<div data-reflex-permanent>
<video id="player" src="video.mp4" controls></video>
</div>