Skip to main content
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.

How Blocks Work

Each section can contain multiple blocks that store staff can manage through the Page Builder:
  • Add new blocks
  • Edit block content and settings
  • Reorder blocks via drag-and-drop
  • Remove blocks
Not all sections support blocks. A section must explicitly enable block support by implementing blocks_available? and available_blocks_to_add methods.

Built-in Block Types

Spree comes with several built-in block types:

Content Blocks

BlockDescriptionClass
HeadingLarge text headingsSpree::PageBlocks::Heading
SubheadingSmaller secondary headingsSpree::PageBlocks::Subheading
TextRich text contentSpree::PageBlocks::Text
ButtonsCall-to-action buttons with linksSpree::PageBlocks::Buttons
ImageImage with optional linkSpree::PageBlocks::Image
BlockDescriptionClass
NavSimple navigation linksSpree::PageBlocks::Nav
Mega NavMega menu navigationSpree::PageBlocks::MegaNav
LinkSingle link itemSpree::PageBlocks::Link

Product Blocks

These blocks are used in the Product Details section:
BlockDescriptionClass
TitleProduct titleSpree::PageBlocks::Products::Title
PriceProduct price displaySpree::PageBlocks::Products::Price
DescriptionProduct descriptionSpree::PageBlocks::Products::Description
Variant PickerSize/color selectorSpree::PageBlocks::Products::VariantPicker
Quantity SelectorQuantity inputSpree::PageBlocks::Products::QuantitySelector
Buy ButtonsAdd to cart buttonSpree::PageBlocks::Products::BuyButtons
ShareSocial sharing buttonsSpree::PageBlocks::Products::Share

Architecture

Base Class

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

Default Preferences

Every block has these default preferences:
PreferenceTypeDefaultDescription
text_alignmentStringleftText alignment (left, center, right)
container_alignmentStringleftContainer alignment
sizeStringmediumBlock size (small, medium, large)
width_desktopInteger100Width percentage on desktop
top_paddingInteger0Top padding in pixels
bottom_paddingInteger0Bottom padding in pixels

Associations

  • Section: Each block belongs to a section (section)
  • Links: Blocks can have multiple links (links) via Spree::HasPageLinks
  • Asset: Blocks can have an attached image (asset)
  • Rich Text: Blocks can have rich text content (text)

Accessing Blocks

# 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')

Rendering Blocks

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.

Creating a Custom Block

Step 1: Create the Model

app/models/spree/page_blocks/quote.rb
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

Step 2: Register the Block

config/initializers/spree.rb
Rails.application.config.after_initialize do
  Spree.page_builder.page_blocks += [
    Spree::PageBlocks::Quote
  ]
end

Step 3: Add to Section’s Available Blocks

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

Step 4: Create Admin Form

app/views/spree/admin/page_blocks/forms/_quote.html.erb
<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>

Step 5: Render in Section View

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? %>
            <br><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

Block with Image

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 %>

Key Methods

MethodDescription
display_nameName shown in Page Builder sidebar
icon_nameIcon from Tabler Icons
form_partial_nameName of the admin form partial