ViewComponent (v4.0.0.rc2)

A framework for creating reusable, testable & encapsulated view components, built to integrate seamlessly with Ruby on Rails.

As of version 4, ViewComponent is in Long-Term Support and considered feature-complete.

What’s a ViewComponent?

ViewComponents are Ruby objects used to build markup. Think of them as an evolution of the presenter pattern, inspired by React.

ViewComponents are objects that encapsulate a template:

# app/components/message_component.rb
class MessageComponent < ViewComponent::Base
  def initialize(name:)
    @name = name
  end
end
<%# app/components/message_component.html.erb %>
<h1>Hello, <%= @name %>!<h1>

Which is rendered by calling:

<%# app/views/demo/index.html.erb %>
<%= render(MessageComponent.new(name: "World")) %>

Returning:

<h1>Hello, World!</h1>

Why use ViewComponents?

TL;DR

ViewComponents work best for templates that are reused or benefit from being tested directly. Partials and templates with significant amounts of embedded Ruby often make good ViewComponents.

Single responsibility

Rails applications often scatter view-related logic across models, controllers, and helpers, diluting their intended responsibilities. ViewComponents consolidate the logic needed for a template into a single class, resulting in a cohesive object that is easy to understand.

ViewComponent methods are implemented within the scope of the template, encapsulating them in proper object-oriented fashion. This cohesion is especially evident when multiple methods are needed for a single view.

Testing

ViewComponent was designed with the intention that all components should be unit tested. In the GitHub codebase, ViewComponent unit tests are over 100x faster than similar controller tests.

With ViewComponent, integration tests can be reserved for end-to-end assertions, with permutations covered at the unit level.

For example, to test the MessageComponent above:

class MessageComponentTest < GitHub::TestCase
  include ViewComponent::TestHelpers

  test "renders message" do
    render_inline(MessageComponent.new(name: "World"))

    assert_selector "h1", text: "Hello, World!"
  end
end

ViewComponent unit tests leverage the Capybara matchers library, allowing for complex assertions traditionally reserved for controller and browser tests.

Data Flow

Traditional Rails templates have an implicit interface, making it hard to reason about their dependencies. This can lead to subtle bugs when rendering the same template in different contexts.

ViewComponents use a standard Ruby initializer that clearly defines what’s needed to render, making reuse easier and safer than partials.

Performance

Based on several benchmarks, ViewComponents are ~2.5x faster than partials:

Comparison:
  component:     6498.1 i/s
    partial:     2676.5 i/s - 2.50x  slower

Code quality

Template code often fails basic Ruby standards: long methods, deep conditional nesting, and mystery guests abound.

ViewComponents are Ruby objects, making it easy to follow (and enforce) code quality standards.

Contributors

Hundreds of people have contributed to ViewComponent, including:

adillari

adrianthedev

aduth

agrobbin

allan-pires

allmarkedup

alvincrespo

amhol

andrewjtait

andrewmcodes

andreyazimov

asgerb

avinoth

ayushn21

bankair

baygeldin

bdewater

being-frank

berniechiu

betogrun

bigbigdoudou

biow0lf

blakewilliams

boardfish

bobermod

bobmaerten

boof

bpo

bradparker

brittanyellich

brushbox

bryanbeshore

btrewern

buraga-dmitrii

caifara

camertron

carpenterjoseph

ceritium

cheshire137

chloe-meister

claudiob

cllns

compostbrain

cover

crookedgrin

cyupa

czj

danceparty

dani-sc

danieldiekmeier

danielnc

danielvdao

dark-panda

davekaro

dbackeus

dependabot[bot]

dixpac

dkniffin

dlinch

donapieppo

dpaola2

drbragg

dukex

dvisockas

dylanatsmith

dylnclrk

edwinthinks

eebs

eelcoj

eileencodes

elalemanyo

elct9620

eleetyson

elia

enriikke

erinnachen

fbraure

foca

franco

franzliedke

fsateler

fugufish

fwolfst

g13ydson

github-actions[bot]

gonzric1

grekko

guillaumebriday

hachi8833

halo

henrikbjorn

hirurg103

hjhart

horacio

horiaradu

hparker

htcarr3

igor-drozdov

ihollander

jacob-carlborg-apoex

janklimo

jaredcwhite

jaredplanter

javierav

javierm

jcoyne

jdelstrother

jdennes

jess

joelhawksley

jogetblock

johannesengl

jonrohan

jonspalmer

jordanbrock

joshmgross

joshuaclayton

jpbalarini

juanmanuelramallo

jwshuff

jyunderwood

kalashnikovisme

kanejamison

kaoru

kaspermeyer

keithamus

kengos

kenyonj

khiga8

konnorrogers

krazylegz

kulturbande

kylefox

kzkn

le0pard

leighhalliday

lfalcao

llenk

luccastera

lxxxvi

lyams

mamhoff

manuelpuyol

marckohlbrugge

marcoroth

matheuspolicamilo

matheusrich

matt-yorkley

mattbearman

mattbrictson

matthewlehner

mattwr18

maxbeizer

mbuckley

mec

meganemura

mellowfish

meneerprins

metade

mhw

michaelem

mikemcquaid

mikepmunroe

milk1000cc

mitchellhenke

mixergtz

mkanakana

mkdynamic

moekiorg

mrjonesbot

mrloop

mrrooijen

mvz

mxriverlynn

myabc

nachiket87

nashby

natashau

ncsmith24

neanias

nickcoyne

nickmalcolm

nicolas-besnard

nicolas-brousse

nielsslot

nitsas

nshki

olleolleolle

ollie-nye

otorain

ozydingo

p8

pacmakaveli

palkan

patrickarnett

paul

paulohenrique-gh

pbstriker38

percyhanna

petergoldstein

peteryates

phacks

phil-janeapp

porbas

positivecontrol

pouretrebelle

progapandist

rainerborene

rdavid1099

rdkulp

reedrolemodel

reeganviljoen

ricardotrindade

richardmarbach

rickychilcott

rmacklin

romaricpascal

rubensmit

rylanb

ryogift

sahglie

salazarjosh

sammyhenningsson

sampart

seanpdoyle

sebastjanprachovskij

sethherr

sfnelson

simonrand

skryukov

smashwilson

sn3p

spdawson

spone

srt32

steveclarke

stiig

sunny

svetlins

swanson

talltorp

talum

tastypi

tclem

tdak

tgaff

thomascchen

thutterer

tkowalewski

tmaier

tmbv93

tmecklem

tomasc

tonkpils

traels

triskweline

tysongach

ultrawebmarketing

varyform

vinistock

vsppedro

wakematta

websebdev

willcosgrove

wooly

xkraty

xronos-i-am

xtr3me

yakschuss

yhirano55

yjukaku

yshmarov

yykamei

zaratan

zeneixe

zspencer

Who uses ViewComponent?

Using ViewComponent? Send a pull request to update this list! You can also check out how various projects use ViewComponent.


Getting started →