docs/developer/storefront/rails/blocks.mdx
Blocks are the lowest level of components in Spree Storefront. They are nested inside sections and represent individual content elements like headings, text, buttons, and images.
Each section can contain multiple blocks that store staff can manage through the Page Builder:
Not all sections support blocks. A section must explicitly enable block support by implementing blocks_available? and available_blocks_to_add methods.
Spree comes with several built-in block types:
| Block | Description | Class |
|---|---|---|
| Heading | Large text headings | Spree::PageBlocks::Heading |
| Subheading | Smaller secondary headings | Spree::PageBlocks::Subheading |
| Text | Rich text content | Spree::PageBlocks::Text |
| Buttons | Call-to-action buttons with links | Spree::PageBlocks::Buttons |
| Image | Image with optional link | Spree::PageBlocks::Image |
| Block | Description | Class |
|---|---|---|
| Nav | Simple navigation links | Spree::PageBlocks::Nav |
| Mega Nav | Mega menu navigation | Spree::PageBlocks::MegaNav |
| Link | Single link item | Spree::PageBlocks::Link |
These blocks are used in the Product Details section:
| Block | Description | Class |
|---|---|---|
| Title | Product title | Spree::PageBlocks::Products::Title |
| Price | Product price display | Spree::PageBlocks::Products::Price |
| Description | Product description | Spree::PageBlocks::Products::Description |
| Variant Picker | Size/color selector | Spree::PageBlocks::Products::VariantPicker |
| Quantity Selector | Quantity input | Spree::PageBlocks::Products::QuantitySelector |
| Buy Buttons | Add to cart button | Spree::PageBlocks::Products::BuyButtons |
| Share | Social sharing buttons | Spree::PageBlocks::Products::Share |
All blocks inherit from Spree::PageBlock:
module Spree
class PageBlock < Spree.base_class
include Spree::HasPageLinks
belongs_to :section, class_name: 'Spree::PageSection'
has_rich_text :text
has_one_attached :asset
# Default preferences
preference :text_alignment, :string, default: 'left'
preference :container_alignment, :string, default: 'left'
preference :size, :string, default: 'medium'
preference :width_desktop, :integer, default: 100
preference :top_padding, :integer, default: 0
preference :bottom_padding, :integer, default: 0
end
end
Every block has these default preferences:
| Preference | Type | Default | Description |
|---|---|---|---|
text_alignment | String | left | Text alignment (left, center, right) |
container_alignment | String | left | Container alignment |
size | String | medium | Block size (small, medium, large) |
width_desktop | Integer | 100 | Width percentage on desktop |
top_padding | Integer | 0 | Top padding in pixels |
bottom_padding | Integer | 0 | Bottom padding in pixels |
section)links) via Spree::HasPageLinksasset)text)# Get all blocks for a section
section.blocks
# Get blocks with eager loading
section.blocks.includes(:rich_text_text, :links)
# Find specific block type
section.blocks.where(type: 'Spree::PageBlocks::Heading')
In storefront section views, blocks are rendered within their parent section:
<% section.blocks.each do |block| %>
<% case block.type %>
<% when 'Spree::PageBlocks::Heading' %>
<h2 <%= block_attributes(block) %>>
<%= block.text %>
</h2>
<% when 'Spree::PageBlocks::Text' %>
<div <%= block_attributes(block) %>>
<%= block.text %>
</div>
<% when 'Spree::PageBlocks::Buttons' %>
<div <%= block_attributes(block) %>>
<% if block.link %>
<%= page_builder_link_to block.link, class: 'btn-primary' %>
<% end %>
</div>
<% end %>
<% end %>
The block_attributes(block) helper returns data attributes needed for Page Builder editing.
module Spree
module PageBlocks
class Quote < Spree::PageBlock
SIZE_DEFAULT = 'large'
TEXT_ALIGNMENT_DEFAULT = 'center'
preference :author_name, :string
preference :author_title, :string
preference :text_color, :string
preference :background_color, :string
def icon_name
'quote'
end
def display_name
text.to_plain_text.truncate(30)
end
end
end
end
Rails.application.config.after_initialize do
Spree.page_builder.page_blocks += [
Spree::PageBlocks::Quote
]
end
In your section model, add the new block type:
def available_blocks_to_add
[
Spree::PageBlocks::Heading,
Spree::PageBlocks::Text,
Spree::PageBlocks::Quote # Your new block
]
end
<div class="form-group">
<%= f.label :text, Spree.t(:quote_text) %>
<%= f.rich_text_area :text, data: { action: 'auto-submit#submit' } %>
</div>
<div class="form-group">
<%= f.label :preferred_author_name, Spree.t(:author_name) %>
<%= f.text_field :preferred_author_name,
class: 'form-control',
data: { action: 'auto-submit#submit' } %>
</div>
<div class="form-group">
<%= f.label :preferred_author_title, Spree.t(:author_title) %>
<%= f.text_field :preferred_author_title,
class: 'form-control',
data: { action: 'auto-submit#submit' } %>
</div>
Add rendering logic to your section's storefront view:
<% when 'Spree::PageBlocks::Quote' %>
<blockquote <%= block_attributes(block) %> class="text-<%= block.preferred_text_alignment %>">
<p class="text-xl italic"><%= block.text %></p>
<% if block.preferred_author_name.present? %>
<footer class="mt-4">
<cite>
<strong><%= block.preferred_author_name %></strong>
<% if block.preferred_author_title.present? %>
<span class="text-sm text-gray-500"><%= block.preferred_author_title %></span>
<% end %>
</cite>
</footer>
<% end %>
</blockquote>
To add link support to your block, include the Spree::HasOneLink concern:
module Spree
module PageBlocks
class CallToAction < Spree::PageBlock
include Spree::HasOneLink
preference :button_style, :string, default: 'primary'
# Called when the link is destroyed
def link_destroyed(_link)
destroy if page_links_count.zero?
end
end
end
end
Blocks automatically have an asset attachment available:
# Check if image is attached
block.asset.attached?
# Display image in view
<% if block.asset.attached? %>
<%= spree_image_tag block.asset, width: 400, height: 300 %>
<% end %>
| Method | Description |
|---|---|
display_name | Name shown in Page Builder sidebar |
icon_name | Icon from Tabler Icons |
form_partial_name | Name of the admin form partial |