# Building a (Very) Simple Responsive Search with Rails & Stimulus

DevFeed: [Building a (Very) Simple Responsive Search with Rails & Stimulus](<https://devfeed.tech/articles/building-a-very-simple-responsive-search-with-rails-stimulus-20113.md>)

Original publisher: [Read original article](<https://hashrocket.com/blog/posts/building-a-simple-search-with-rails-stimulus>)

Author: Jack Rosa

Published: 2025-12-09T14:00:00Z

Content type: tutorial

Language: en

Sources: [Hashrocket](<https://devfeed.tech/sources/hashrocket.md>)

Topics: [Rails](<https://devfeed.tech/topics/rails.md>), [Stimulus](<https://devfeed.tech/topics/stimulus.md>), [Framework](<https://devfeed.tech/topics/framework.md>)

Tags: [building](<https://devfeed.tech/tags/building.md>), [hotwire](<https://devfeed.tech/tags/hotwire.md>), [rails](<https://devfeed.tech/tags/rails.md>), [search](<https://devfeed.tech/tags/search.md>), [side-project](<https://devfeed.tech/tags/side-project.md>), [stimulus](<https://devfeed.tech/tags/stimulus.md>), [turbo](<https://devfeed.tech/tags/turbo.md>)

## AI overview

A tutorial for building a responsive search form with Rails and Stimulus. It demonstrates debounced input submission, a clear-input button, and updating search results inside a Turbo Frame without a full-page reload.

## Source excerpt

Here's a simple and responsive search form I put together for a recent side project, using Hotwire's Stimulus framework and Rails with Turbo. The Form Here's how the search input looks. It's a simple search form connected to a Stimulus controller. The input triggers the search function upon every input event. The debounce logic occurs in the Stimulus controller to make sure not too many requests are made to the server: <%= form_with url: items_path, method: :get, data: { controller: "search", turbo_frame: "items_list" } do |f| %> <%= f.text_field :query, placeholder: "Search...", data: { search_target: "input", action: "input->search#search" } %> <button type="button" class="hidden" data-search-target="clearButton" data-action="click->search#clear"> x </button> <% end %> There's an additional feature here: a button which appears in the search field whenever the field has a value. The button has a data-action attribute pointing to the clear action. If the button is clicked, the input value is cleared out. The Stimulus Controller All we need to do here is submit the form with a debounce timer, handle the action for clicking the clear input button, and handle hiding the clear button if the input field has a value or not. export default class extends Controller { static targets = ["input", "clearButton"] connect() { this.toggleClear() } search() { this.toggleClear() clearTimeout(this.timeout) this.timeout = setTimeout(() => { this.element.requestSubmit() }, 300) } clear() { this.inputTarget.value = "" this.toggleClear() this.element.requestSubmit() } toggleClear() { if (this.inputTarget.value.length > 0) { this.clearButtonTarget.classList.remove("hidden") } else { this.clearButtonTarget.classList.add("hidden") } } } The Turbo Frame You'll notice the form targets an items_list turbo frame, which contains your search results in the view. When the Stimulus controller submits the form, the content inside this frame gets replaced with the new search results. This is a pretty