Your First Component
Let’s build a simple HTML component to understand Phlex’s core concepts.
Create a component class
Every Phlex component inherits from Phlex::HTML and defines a view_template method: class GreetingComponent < Phlex::HTML
def view_template
h1 { "Hello, World!" }
end
end
The view_template method is where you define your HTML structure using Phlex’s DSL.
Render the component
Call your component to generate HTML: html = GreetingComponent . call
puts html
# => <h1>Hello, World!</h1>
Use .call on the class to instantiate and render in one step.
Adding Dynamic Content
Components accept data through their initializer:
class GreetingComponent < Phlex::HTML
def initialize ( name: )
@name = name
end
def view_template
h1 { "Hello, #{ @name } !" }
end
end
GreetingComponent . call ( name: "Ruby" )
# => <h1>Hello, Ruby!</h1>
Phlex automatically escapes text content to prevent XSS attacks. Raw HTML requires explicit opt-in using raw(safe("<html>")).
Working with Attributes
Phlex provides a clean syntax for HTML attributes:
Basic Attributes
Data Attributes
Array Classes
class ButtonComponent < Phlex::HTML
def view_template
button (
class: "btn btn-primary" ,
id: "submit-button" ,
disabled: true
) { "Submit" }
end
end
# => <button class="btn btn-primary" id="submit-button" disabled>Submit</button>
Attribute Type Reference
Use true to include the attribute, false or nil to omit it: input ( disabled: true , checked: false )
# => <input disabled>
Both strings and symbols work. Symbols with underscores convert to dashes: div ( class: :text_center ) # => <div class="text-center"></div>
div ( class: "text-center" ) # => <div class="text-center"></div>
Integers and floats are automatically converted to strings: input ( type: "number" , value: 42 , step: 0.5 )
# => <input type="number" value="42" step="0.5">
Hash values (nested attributes)
Hashes create nested attributes joined with dashes: div ( data: { user_id: 123 , role: "admin" })
# => <div data-user-id="123" data-role="admin"></div>
Composing Components
Build complex UIs by composing components together:
class LayoutComponent < Phlex::HTML
def initialize ( title: )
@title = title
end
def view_template ( & block )
html do
head { title { @title } }
body ( & block)
end
end
end
class ArticleComponent < Phlex::HTML
def initialize ( title: , content: )
@title = title
@content = content
end
def view_template
article do
h1 { @title }
p { @content }
end
end
end
class PageComponent < Phlex::HTML
def view_template
render LayoutComponent . new ( title: "My Blog" ) do
render ArticleComponent . new (
title: "Getting Started with Phlex" ,
content: "Phlex makes building views enjoyable!"
)
end
end
end
PageComponent . call
Use render to include one component inside another. Pass blocks to parent components for flexible layouts.
Complete Example: Card Component
Here’s a practical example combining everything we’ve learned:
class CardComponent < Phlex::HTML
def initialize ( title: , description: , image_url: nil , featured: false )
@title = title
@description = description
@image_url = image_url
@featured = featured
end
def view_template
article ( class: card_classes) do
render_image if @image_url
div ( class: "p-6" ) do
h2 ( class: "text-2xl font-bold mb-2" ) { @title }
p ( class: "text-gray-600" ) { @description }
render_badge if @featured
end
end
end
private
def card_classes
classes = [ "rounded-lg" , "shadow-lg" , "overflow-hidden" ]
classes << "border-2 border-yellow-400" if @featured
classes
end
def render_image
img (
src: @image_url ,
alt: @title ,
class: "w-full h-48 object-cover"
)
end
def render_badge
span (
class: "inline-block px-3 py-1 bg-yellow-400 text-sm font-semibold rounded mt-4"
) { "Featured" }
end
end
# Usage
CardComponent . call (
title: "Phlex Basics" ,
description: "Learn the fundamentals of component-based views" ,
image_url: "/images/phlex-basics.jpg" ,
featured: true
)
Break down complex components into private helper methods. This keeps your code organized and testable.
Inline HTML Without Classes
For quick HTML generation, use Phlex.html without creating a class:
html_string = Phlex . html do
div ( class: "container" ) do
h1 { "Quick HTML" }
p { "No class definition needed" }
end
end
puts html_string
# => <div class="container"><h1>Quick HTML</h1><p>No class definition needed</p></div>
This is perfect for scripts, tests, or one-off HTML generation tasks.
Plain Text Output
Use plain to output text content explicitly:
class MessageComponent < Phlex::HTML
def view_template
div do
plain "This is "
strong { "important" }
plain " text."
end
end
end
# => <div>This is <strong>important</strong> text.</div>
Common Patterns
Use standard Ruby conditionals: def view_template
if @user . admin?
button { "Admin Panel" }
else
p { "Welcome, #{ @user . name } " }
end
end
Use Ruby’s enumerable methods: def view_template
ul do
@items . each do | item |
li { item. name }
end
end
end
Set defaults in the initializer: def initialize ( title: , subtitle: nil )
@title = title
@subtitle = subtitle || "No subtitle provided"
end
Use the tag method for dynamic element types: def view_template
@tag_name = :h1
tag ( @tag_name , class: "title" ) { "Dynamic heading" }
end
# => <h1 class="title">Dynamic heading</h1>
Next Steps
You now know the fundamentals of Phlex! Here’s what to explore next:
Advanced Components Learn about component inheritance, mixins, and Kit modules
SVG Support Build scalable vector graphics with the same elegant syntax
Testing Views Write unit tests for your components
Performance Optimize rendering with caching and compilation
Join the Phlex community to see real-world examples and get help from other developers.