viewcomponent-coder

ViewComponent Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "viewcomponent-coder" with this command: npx skills add majesticlabs-dev/majestic-marketplace/majesticlabs-dev-majestic-marketplace-viewcomponent-coder

ViewComponent Patterns

Build modern, component-based UIs with ViewComponent using Evil Martians' view_component-contrib patterns.

When to Use This Skill

  • Creating ViewComponent classes

  • Implementing slots and style variants

  • Building Lookbook previews

  • Testing components in isolation

  • Refactoring partials to components

Core Principle: Components Over Partials

Prefer ViewComponents over partials for reusable UI.

Why ViewComponents?

  • Better encapsulation than partials

  • Testable in isolation

  • Object-oriented approach with explicit contracts

  • IDE support and type safety

  • Performance benefits (compiled templates)

Setup

Gemfile

gem "view_component" gem "view_component-contrib" # Evil Martians patterns gem "dry-initializer" # Declarative initialization gem "lookbook" # Component previews gem "inline_svg" # SVG icons

Install with Rails template:

rails app:template LOCATION="https://railsbytes.com/script/zJosO5"

Base Classes

app/components/application_view_component.rb

class ApplicationViewComponent < ViewComponentContrib::Base extend Dry::Initializer end

spec/components/previews/application_view_component_preview.rb

class ApplicationViewComponentPreview < ViewComponentContrib::Preview::Base self.abstract_class = true end

Basic Component with dry-initializer

app/components/button_component.rb

class ButtonComponent < ApplicationViewComponent option :text option :variant, default: -> { :primary } option :size, default: -> { :md } end

<%# app/components/button_component.html.erb %> <button class="btn btn-<%= variant %> btn-<%= size %>"> <%= text %> </button>

Style Variants DSL

Replace manual VARIANTS hashes with the Style Variants DSL:

class ButtonComponent < ApplicationViewComponent include ViewComponentContrib::StyleVariants

option :text option :color, default: -> { :primary } option :size, default: -> { :md }

style do base { %w[font-medium rounded-full] }

variants {
  color {
    primary { %w[bg-blue-500 text-white] }
    secondary { %w[bg-gray-500 text-white] }
    danger { %w[bg-red-500 text-white] }
  }
  size {
    sm { "text-sm px-2 py-1" }
    md { "text-base px-4 py-2" }
    lg { "text-lg px-6 py-3" }
  }
}

# Apply when multiple conditions match
compound(size: :lg, color: :primary) { "uppercase" }

defaults { { color: :primary, size: :md } }

end end

<button class="<%= style(color:, size:) %>"> <%= text %> </button>

Component with Slots

class CardComponent < ApplicationViewComponent renders_one :header renders_one :footer renders_many :actions end

<%= render CardComponent.new do |card| %> <% card.with_header do %> <h3>Title</h3> <% end %>

<p>Body content</p>

<% card.with_action do %> <%= helpers.link_to "Edit", edit_path %> <% end %> <% end %>

Important Rules

  1. Prefix Rails helpers with helpers.

<%# CORRECT %> <%= helpers.link_to "Home", root_path %> <%= helpers.image_tag "logo.png" %> <%= helpers.inline_svg_tag "icons/user.svg" %>

<%# WRONG - will fail in component context %> <%= link_to "Home", root_path %>

Exception: t() i18n helper does NOT need prefix:

<%= t('.title') %>

  1. SVG Icons as Separate Files

Store SVGs in app/assets/images/icons/ and render with inline_svg gem:

<%= helpers.inline_svg_tag "icons/user.svg", class: "w-5 h-5" %>

Don't inline SVG markup in Ruby code - use separate files instead.

Conditional Rendering

class AlertComponent < ApplicationViewComponent option :message option :type, default: -> { :info } option :dismissible, default: -> { true }

Skip rendering if no message

def render? message.present? end end

Lookbook Previews

spec/components/previews/button_component_preview.rb

class ButtonComponentPreview < ApplicationViewComponentPreview def default render ButtonComponent.new(text: "Click me") end

def primary render ButtonComponent.new(text: "Primary", color: :primary) end

def all_sizes render_with(wrapper: :flex_row) do safe_join([ render(ButtonComponent.new(text: "Small", size: :sm)), render(ButtonComponent.new(text: "Medium", size: :md)), render(ButtonComponent.new(text: "Large", size: :lg)) ]) end end end

Access at: http://localhost:3000/lookbook

Testing Components

RSpec.describe ButtonComponent, type: :component do it "renders button text" do render_inline(ButtonComponent.new(text: "Click me")) expect(page).to have_button("Click me") end

it "applies style variant classes" do render_inline(ButtonComponent.new(text: "Save", color: :primary, size: :lg)) expect(page).to have_css("button.bg-blue-500.text-lg") end end

Detailed References

For advanced patterns and examples:

  • references/patterns.md

  • Slots, collections, polymorphic components, Turbo integration

  • references/style-variants.md

  • Full Style Variants DSL, compound variants, TailwindMerge

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

google-ads-strategy

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

viral-content

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

market-research

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

free-tool-arsenal

No summary provided by upstream source.

Repository SourceNeeds Review