Profile picture Schedule a Meeting
c a n d l a n d . n e t

Subcomponent

Dusty Candland | | opensource, ruby, rails, erb

Components are stored in app/views/components and are named _component.html.erb. They can also be stored in a subdirectory of app/views/components and are named using the component name for the directory and the partial component/_component.html.erb.

Additional subcomponent partials can be included in the component directory allowing to break up the component into smaller pieces.

Subcomponent

When you want to create HTML simple components, using partials.

Usage

Components are stored in app/views/components and are named _component.html.erb. They can also be stored in a subdirectory of app/views/components and are named using the component name for the directory and the partial component/_component.html.erb.

Additional subcomponent partials can be included in the component directory allowing to break up the component into smaller pieces.

Example Simple Component

Create a button component in app/views/components/_button.html.erb:

<button>
  <%= this.text %>
</button>

Use this to access the component instance containing locals and subcomponents.

To use the component in a view:

<%= component :button, text: 'Click Me' %>

Using with the method_missing shorthand:

<%= button text: 'Click Me' %>

Locals can also be set within the component block:

<%= component :button do |c| %>
  <% c.text = 'Click Me' %>
<% end %>

Example Component with Subcomponents

Create a card component in app/views/components/card/_card.html.erb:

<div>
  <%= this.render :title %>
  <%= this.text || this.yield %>
</div>

Create the title subcomponent in app/views/components/card/_title.html.erb:

<h1>
  <%= this.text %>
</h1>

You can use this.render to render a subcomponent. The subcomponent will have access to the locals and subcomponents passed in the view.

You can use this.yield to render the block passed in the view.

To use the component in a view:

<%= component :card do |c| %>
  <%= c.title text: 'Card Title' %>
  <p>Card Text</p>
<% end %>

This will render:

<div>
  <h1>Card Title</h1>
  <p>Card Text</p>
</div>

Example Component with multiple Subcomponents

Create a card component in app/views/components/card/_card.html.erb:

<div>
  <% this.copy_components :links, :mobile_links %>
  <%= this.render :links %>
  <%= this.render :mobile_links %>
  <%= this.text || this.yield %>
</div>

Create the link subcomponent in app/views/components/card/_link.html.erb:

<a class="desktop" href="<%= this.url %>">
  <%= this.index %>: <%= this.text %>
</a>

Create the mobile_link subcomponent in app/views/components/card/_mobile_link.html.erb:

<a class="mobile" href="<%= this.url %>">
  <%= this.index %>: <%= this.text %>
</a>

You can use this.render_all to render multiple subcomponent. The subcomponent will have access to the locals and subcomponents passed in the view. The components index method will be set.

To use the component in a view:

<%= component :card do |c| %>
  <%= c.link text: 'Card Link 1', url: '#" %>
  <%= c.link text: 'Card Link 2', url: '#" %>
  <p>Card Text</p>
<% end %>

This will render:

<div>
  <a class="desktop" href="#">
    0: Card Link 1
  </a>
  <a class="desktop" href="#">
    1: Card Link 2
  </a>
  <a class="mobile" href="#">
    0: Card Link 1
  </a>
  <a class="mobile" href="#">
    1: Card Link 2
  </a>
  <p>Card Text</p>
</div>

Example Using Locals without method_missing.

In some cases you may want to use a local variable that clashes with existing methods on Object. In these cases you can access the locals hash directly.

<h1>
  <%= this.local(:method) %>
</h1>

Example Using Subcomponents without method_missing.

In some cases you may want to use a subcomponent that clashes with existing methods on Object. In these cases you can access the subcomponents hash directly.

<%= this.components(:method) %>

This returns and Array of subcomponents. You can render the first subcomponent with a given key using, this.render(:header).

<%= this.render(:header) %>

If you have multiple subcomponents with the same key, you can render them all using this.render_all(:header).

<%= this.render_all(:header) %>

If you want to render all subcomponents, but with HTML between them, you can use this.components(:actions).

<ul>
<% this.components(:actions).each do |sub| %>
  <li><%= sub.render %></li>
<% end %>
</ul>

Installation

Add this line to your application's Gemfile:

$ bundle add subcomponent

Or install it yourself as:

$ gem install subcomponent

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/candland/subcomponent.

License

The gem is available as open source under the terms of the MIT License.

Webmentions

1 Like

dusti

These are webmentions via the IndieWeb and webmention.io. Mention this post from your site: