Skip to content

Lesson 2 — Kits

The problem

Without Kits, rendering a component requires both render and .new:

1
render Components::Heading.new(text: "Hello", level: 2)

As components are used inside other components this becomes repetitive. Kits give us a cleaner syntax.

Setting up the Kit

Add extend Phlex::Kit to base.rb:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# app/components/base.rb
require "phlex"
require "date"
require "literal"

module Components
  extend Phlex::Kit

  class Base < Phlex::HTML
    extend Literal::Properties

    private

    def class_names(*classes)
      classes.flatten.compact.reject(&:empty?).join(" ")
    end
  end
end

extend Phlex::Kit turns the Components module into a Kit. Every component class defined under Components:: automatically gets a corresponding shorthand method. Instead of:

1
render Components::Heading.new(text: "Hello", level: 2)

You can write:

1
Components::Heading(text: "Hello", level: 2)

And when you include Components inside another component, the namespace disappears entirely:

1
2
3
4
5
6
7
class DemoPage < Phlex::HTML
  include Components

  def view_template
    Heading(text: "Hello", level: 2)
  end
end

One gotcha: when a component takes no arguments and no block, use empty parentheses — Ruby needs them to know you are calling a method rather than looking up a constant:

1
2
Components::Spinner()   # method call — renders the component
Components::Spinner     # constant lookup — returns the class itself

Updating the demo page

Add include Components to DemoPage and replace the render ... .new(...) calls. From now on all demo examples use Kit syntax:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# demo.rb — updated head of class and show_headings

class DemoPage < Phlex::HTML
  include Components              # gives us Kit shorthand

  # ... view_template unchanged ...

  def show_headings
    section_header("Headings")
    Heading(text: "Heading level 1", level: 1)
    Heading(text: "Heading level 2", level: 2)
    Heading(text: "Heading level 3", level: 3)
  end
end

The output is identical — the Kit syntax is purely a call-site improvement.

Exercise

Update demo.rb as shown. Confirm that Heading(text: "Hello", level: 2) produces the same output as render Components::Heading.new(text: "Hello", level: 2) by printing both to the terminal before switching to Kit syntax.