Skip to content

End-to-End Component Creation

When to Use

When you need a complete walkthrough of creating a new page-building component from scratch, integrating all Plus Suite features.

Example: Creating a "Testimonial" Component

This walkthrough creates a complete Testimonial block that works with all Plus Suite features.

Step 1: Create Block Content Type

Admin UI: Structure → Block Types → Add custom block type

Field Machine Name Type Settings
Quote field_quote Text (formatted, long) Required, full_html
Author field_author Text (plain) Required
Author Title field_author_title Text (plain) Optional
Author Photo field_author_photo Entity reference (media) Image bundle
Rating field_rating List (integer) 1-5 stars

Step 2: Create View Display

Manage Display for block_content:testimonial:

  • Use "Default" view mode
  • Configure field formatters and label visibility
  • Enable Layout Builder if the testimonial needs internal layout flexibility

Step 3: Configure Sample Values

Per field on Manage Fields → [Field] → Edit:

Field Generator Config
Quote random_text count: 1, format: full_html
Author default Core generates name
Author Title Custom branded_headline Generates job titles
Author Photo entity_reference Selects random image media
Rating default Random 1-5

Step 4: Create Event Subscriber Module

# my_theme_plus.info.yml
name: 'My Theme Plus Suite Integration'
type: module
description: 'Design system integration for Plus Suite.'
core_version_requirement: ^11.3
dependencies:
  - lb_plus:lb_plus
  - edit_plus:edit_plus
  - field_sample_value:field_sample_value
# my_theme_plus.services.yml
services:
  my_theme_plus.testimonial_properties:
    class: Drupal\my_theme_plus\EventSubscriber\TestimonialProperties
    tags:
      - { name: event_subscriber }
// src/EventSubscriber/TestimonialProperties.php
namespace Drupal\my_theme_plus\EventSubscriber;

use Drupal\edit_plus\Event\BlockPropertiesEvent;
use Drupal\lb_plus\Event\PlaceBlockEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class TestimonialProperties implements EventSubscriberInterface {

  public static function getSubscribedEvents(): array {
    return [
      PlaceBlockEvent::class => 'onPlaceBlock',
      BlockPropertiesEvent::class => 'onBlockProperties',
    ];
  }

  public function onPlaceBlock(PlaceBlockEvent $event): void {
    $block = $event->getBlockContent();
    if (!$block || $block->bundle() !== 'testimonial') {
      return;
    }
    // Set default rating to 5 stars.
    $block->set('field_rating', 5);
  }

  public function onBlockProperties(BlockPropertiesEvent $event): void {
    $block = $event->getBlockContent();
    if (!$block || $block->bundle() !== 'testimonial') {
      return;
    }

    $config = $event->getInlineBlockConfiguration();

    $event->addBlockProperty([
      '#type' => 'select',
      '#title' => t('Style'),
      '#options' => [
        'card' => t('Card'),
        'quote' => t('Large Quote'),
        'minimal' => t('Minimal'),
      ],
      '#default_value' => $config['testimonial_style'] ?? 'card',
      '#attributes' => ['data-auto-submit' => 'true'],
    ]);

    $event->addBlockProperty([
      '#type' => 'checkbox',
      '#title' => t('Show star rating'),
      '#default_value' => $config['show_rating'] ?? TRUE,
      '#attributes' => ['data-auto-submit' => 'true'],
    ]);
  }
}

Step 5: Create Promoted Block Icon

Create my_theme/assets/block-icons/testimonial.svg (40x40px):

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" fill="none">
  <rect width="40" height="40" rx="4" fill="#f0f0f0"/>
  <path d="M10 14l4-6h4l-3 6h3v8h-8v-8zm12 0l4-6h4l-3 6h3v8h-8v-8z" fill="#666"/>
</svg>

Step 6: Configure Promoted Blocks

Via admin UI or config export:

# On the entity_view_display for your content type
third_party_settings:
  lb_plus:
    promoted_blocks:
      - 'inline_block:testimonial'
    block_config:
      icon:
        'inline_block:testimonial': '/themes/custom/my_theme/assets/block-icons/testimonial.svg'

Step 7: Configure Edit+ Field Settings

Per field, set third-party settings:

Field Edit+ Disable Edit+ Handle
Quote false form_item (uses inline_textarea/CKEditor)
Author false form_item
Author Title false form_item
Author Photo false wrapper
Rating false form_item

Step 8: Create Block Template

{# block--inline-block--testimonial.html.twig #}
{% set style = configuration.testimonial_style|default('card') %}
{% set show_rating = configuration.show_rating|default(true) %}

<div{{ attributes.addClass('testimonial', 'testimonial--' ~ style) }}>
  {% if content.field_author_photo|render %}
    <div class="testimonial__photo">
      {{ content.field_author_photo }}
    </div>
  {% endif %}

  <blockquote class="testimonial__quote">
    {{ content.field_quote }}
  </blockquote>

  <div class="testimonial__attribution">
    <cite class="testimonial__author">{{ content.field_author }}</cite>
    {% if content.field_author_title|render %}
      <span class="testimonial__title">{{ content.field_author_title }}</span>
    {% endif %}
  </div>

  {% if show_rating and content.field_rating|render %}
    <div class="testimonial__rating">
      {{ content.field_rating }}
    </div>
  {% endif %}
</div>

Step 9: Add Theme CSS

// _testimonial.scss
.testimonial {
  padding: var(--spacing-lg);
  border-radius: var(--border-radius);

  &--card {
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
  }

  &--quote {
    text-align: center;
    font-size: var(--font-size-xl);
  }

  &--minimal {
    border-left: 3px solid var(--color-primary);
    padding-left: var(--spacing-md);
  }
}

Component Checklist

When creating any new Plus Suite component, ensure:

  • [ ] Block content type created with appropriate fields
  • [ ] Sample value generators configured for all fields
  • [ ] Block promoted with custom SVG icon
  • [ ] Event subscriber for PlaceBlockEvent (defaults) and BlockPropertiesEvent (design options)
  • [ ] Edit+ handle types configured per field
  • [ ] Block template created with design variant support
  • [ ] CSS styles cover all design variants
  • [ ] Block appears in correct category in "Other" tab
  • [ ] Inline editing works for all editable fields
  • [ ] Sample content appears on first placement
  • [ ] Design options (block properties) update preview immediately

Decision: Which Features to Implement

Feature Required? Effort
Block content type + fields Yes Low
Sample value generators Yes (for good UX) Low
Promoted block + icon Recommended Low
Block properties Optional Medium
Custom template Recommended Low
Custom sample value plugin Optional (for branded content) Medium
Layout plugin (for sections) Optional Medium
Custom tool plugin Rare High

Common Mistakes

  • Do not skip sample value generators — empty blocks on placement defeat the purpose of Plus Suite.
  • Do not create block properties without data-auto-submit — users expect instant preview.
  • Do not forget to test inline editing on every field before shipping.
  • Do not use complex validation on fields that will be edited inline — use simple constraints.

See Also