An open API service indexing awesome lists of open source software.

https://github.com/seanpdoyle/turbo_stream_button

Harness the power of Turbo Streams to declare click event handlers as a series of HTML mutations.
https://github.com/seanpdoyle/turbo_stream_button

hotwire html rails stimulus turbo

Last synced: about 1 month ago
JSON representation

Harness the power of Turbo Streams to declare click event handlers as a series of HTML mutations.

Awesome Lists containing this project

README

          

# `` + ``

Harness the power of [Turbo Streams][] to declare `click` event handlers as a
series of HTML mutations.

Combine built-in `` elements with `` elements to
declaratively drive client-side interactions with server-generated HTML.

```html

Click me to insert the template's contents after this button!



You clicked the button!



```

[Try it out.](https://jsfiddle.net/toybqx89/)

[Turbo Streams]: https://turbo.hotwired.dev/reference/streams

## Usage

In your JavaScript code, import and register the `turbo-stream-button`
controller with your Stimulus application:

```javascript
import "@hotwired/turbo"
import { Application } from "stimulus"
import { TurboStreamButtonController } from "@seanpdoyle/turbo_stream_button"

const application = Application.start()
application.register("turbo-stream-button", TurboStreamButtonController)
```

In your Rails templates, call the `turbo_stream_button_tag` helper or render the
`turbo_stream_button` view partial to create the `` element. The view
partial renders:

* the block content as the `` element's content
* other keyword arguments as the `` element's attributes
* any content captured by any call to the `#turbo_streams` method invoked on the
block's single argument

When the button is clicked, the `turbo-stream-button` [Stimulus controller][]
invokes the `evaluate` [Action][] to insert the contents of the [``
element][mdn-template], activating any `` elements nested inside.

[Stimulus controller]: https://stimulus.hotwired.dev/handbook/hello-stimulus#controllers-bring-html-to-life
[Action]: https://stimulus.hotwired.dev/handbook/building-something-real#connecting-the-action
[mdn-template]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template

### Introductory: Hello, world

```html+erb
<%= turbo_stream_button_tag id: "the-button" do |button| %>
Click me to say "hello"

<% button.turbo_streams do %>
<%= turbo_stream.after "the-button", "Hello, world!" %>
<% end %>
<% end %>

<%# =>
Click me to say "hello"



Hello, world!


%>
```

### Intermediate: Compose with other Stimulus controller actions

```html+erb

import "@hotwired/turbo"
import { Application, Controller } from "stimulus"
import { TurboStreamButtonController } from "@seanpdoyle/turbo_stream_button"

class ClipboardController extends Controller {
copy({ target: { value } }) {
navigator.clipboard.writeText(value)
}
}

const application = Application.start()
application.register("turbo-stream-button", TurboStreamButtonController)
application.register("clipboard", ClipboardController)

<%= turbo_stream_button_tag value: "invitation-code-abc123",
data: { controller: "clipboard", action: "click->clipboard#copy" } do |button| %>
Copy to clipboard

<% button.turbo_streams do %>


Copied "invitation-code-abc123" to your clipboard!




<% end %>
<% end %>

<%# =>
Copy to clipboard




Copied "invitation-code-abc123" to your clipboard!





%>
```

### Advanced: Nest buttons

```html+erb

<%= turbo_stream_button_tag do |button| %>
Append flash message

<% button.turbo_streams do %>



Hello, world!

<%= turbo_stream_button_tag do |button| %>
Dismiss

<% button.turbo_streams do %>
<%= turbo_stream.remove "a_flash_message" %>
<% end %>
<% end %>




<% end %>
<% end %>

<%# =>
Append flash message





Hello, world!


Dismiss









%>
```

### Advanced: Append form controls

```html+erb

import "@hotwired/turbo"
import { Application } from "stimulus"
import { TurboStreamButtonController } from "@seanpdoyle/turbo_stream_button"
import { TemplateInstance } from "https://cdn.skypack.dev/@github/template-parts"

class CloneController extends Controller {
static targets = [ "template" ]
static values = { count: Number, counter: String }

templateTargetConnected(target) {
const templateInstance = new TemplateInstance(target, {
[this.counterValue]: this.countValue
})

target.content.replaceChildren(templateInstance)

this.countValue++
}
}

const application = Application.start()
application.register("turbo-stream-button", TurboStreamButtonController)
application.register("clone", CloneController)

<%= form_with scope: :applicant do |form| %>

References

    <%= form.fields :reference_attributes, index: "{{counter}}" do |reference_form| %>
    <%= turbo_stream_button_tag do |button| %>
    Add reference

    <% button.turbo_streams do %>



  1. <%= reference_form.label :referrer %>
    <%= reference_form.text_field :referrer %>

    <%= reference_form.label :relationship %>
    <%= reference_form.text_field :relationship %>




  2. <% end %>
    <% end %>
    <% end %>

    <% end %>

    <%# =>
    Add reference





  3. Referrer

    Relationship





  4. %>
    ```

    ## Helpers

    There are two helpers declared by the engine:

    ### `turbo_stream_button_tag`

    The `turbo_stream_button_tag` helper renders a `` element ready to
    evaluate a collection of `` elements:

    ```erb
    <%= turbo_stream_button_tag do |button| %>
    Click to append "Hello!"

    <% button.turbo_streams do %>
    <%= turbo_stream.append_all "body" do %>
    Hello!
    <% end %>
    <% end %>
    <% end %>
    ```

    ### `turbo_stream_button`

    The `turbo_stream_button` helper returns an attributes-aware HTML tag builder.
    Render a `` element with the appropriate `[data-controller]` and
    `[data-action]` attributes by calling `#tag`:

    ```erb
    <%= turbo_stream_button.tag do %>
    Click to append "Hello!"
    <% end %>
    ```

    The return a `Hash` of attributes containing the appropriate `[data-controller]`
    and `[data-action]` attributes, call `#merge`, `#to_h` or splat them into
    keyword arguments (with `**`):

    ```erb
    <%= form_with model: Post.new do |form| %>
    <%= form.button **turbo_stream_button, type: :submit do %>
    Click to append "Hello!"

    <%= tag.template turbo_stream_button.template.merge(data: { a_controller_target: "template" }) do %>
    <%= turbo_stream.append_all "body" do %>
    Hello!
    <% end %>
    <% end %>
    <% end %>
    <% end %>
    ```

    To render the `` element nested within the ``, call
    `#template_tag`:

    ```erb
    <%= turbo_stream_button.tag do %>
    Click to append "Hello!"

    <% turbo_stream_button.template_tag do %>
    <%= turbo_stream.append_all "body" do %>
    Hello!
    <% end %>
    <% end %>
    <% end %>
    ```

    The return a `Hash` of attributes containing the appropriate
    `[data-turbo-stream-button-target]` attribute, call `#merge`, `#to_h`, or splat
    them into keyword arguments (with `**`):

    ```erb
    <%= turbo_stream_button.tag do %>
    Click to append "Hello!"

    <%= tag.template turbo_stream_button.template.merge(data: { a_controller_target: "template" }) do %>
    <%= turbo_stream.append_all "body" do %>
    Hello!
    <% end %>
    <% end %>
    <% end %>
    ```

    ## Exploring examples

    To poke around with some working examples, start the [dummy application][]
    locally:

    ```sh
    cd test/dummy
    bundle exec rails server --port 3000
    ```

    Then, visit .

    [![Run on Repl.it](https://repl.it/badge/github/seanpdoyle/turbo_stream_button)](https://replit.com/@seanpdoyle/turbostreambutton)

    You can also fork the [@seanpdoyle/turbo_stream_button][] sandbox project on
    [replit.com][].

    [dummy application]: ./test/dummy
    [replit.com]: https://replit.com/
    [@seanpdoyle/turbo_stream_button]: https://replit.com/@seanpdoyle/turbostreambutton

    ## Installation

    Add the `turbo_stream_button` dependency to your application's Gemfile:

    ```ruby
    gem "turbo_stream_button", github: "seanpdoyle/turbo_stream_button", branch: "main"
    ```

    And then execute:

    ```bash
    $ bundle
    ```

    ### Installation through [importmap-rails][]

    Once the gem is installed, add the client-side dependency mapping to your
    project's `config/importmap.rb` declaration:

    ```ruby
    # config/importmap.rb

    pin "stimulus", to: "stimulus.min.js", preload: true
    pin "@seanpdoyle/turbo_stream_button", to: "turbo_stream_button.js"
    ```

    [importmap-rails]: https://github.com/rails/importmap-rails

    ### Installation through `npm` or `yarn`

    Once the gem is installed, add the client-side dependency to your project via
    npm or Yarn:

    ```bash
    yarn add https://github.com/seanpdoyle/turbo_stream_button.git
    ```

    ## Contributing

    Please read [CONTRIBUTING.md](./CONTRIBUTING.md).

    ## License
    The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).