Skip to content

Creating Custom Component Fields Types

Hyvä Commerce is an 'Early Access' product currently under development.

Early Access means that not all features of Hyvä Commerce are fully completed or released, and many areas are still under heavy development and may change. However, it means you can get your hands on everything currently available and being worked on, with a license. Find out more on our Early Access page.

This is an advanced topic and should only be attempted by experienced developers. Be prepared to debug cases specific to your custom field type implementation.

Hyvä CMS allow you to define custom input fields for your components. These field types control how data is collected in the editor interface to be used in the frontend. This guide will walk you through creating custom field within your project, enabling you to build more sophisticated and tailored content components.

1. Configure the Field Type

First, we need to register our custom field type in the DI configuration and specify its template file that will be used in the editor interface.

<type name="Hyva\CmsLiveviewEditor\Model\CustomField">
    <arguments>
        <argument name="customTypes" xsi:type="array">
            <item name="foobar" xsi:type="string">YourVendor_YourModule::field-types/foobar.phtml</item>
        </argument>
    </arguments>
</type>

2. Implement in Component Configuration

Next, we'll add our new custom field type to a component's configuration in components.json, defining where it should be used within the component.

"your_component": {
  "label": "Your Component",
  "content": {
    "foobar_field": {
      "type": "custom_type",
      "custom_type": "foobar",
      "label": "Foo Bar Field",
      "attributes": {
        "pattern": ".*(foo|bar|Foo|Bar).*"
      }        
    }
  }
}

3. Create the Field Template

Create a new template file in your module's view directory.

<?php

declare(strict_types=1);

use Magento\Backend\Block\Template;
use Magento\Framework\Escaper;
use Hyva\CmsLiveviewEditor\Magewire\LiveviewComposer;
use Hyva\Theme\Model\ViewModelRegistry;
use Hyva\CmsLiveviewEditor\ViewModel\Adminhtml\FieldTypes;

/** @var Template $block */
/** @var Escaper $escaper */
/** @var LiveviewComposer $magewire */
/** @var ViewModelRegistry $viewModels */

/** @var FieldTypes $fieldTypes */
$fieldTypes = $viewModels->require(FieldTypes::class);

$uid = (string) $block->getData('uid');
$fieldName = (string) $block->getData('name');
$fieldValue = (string) $block->getData('value');
$attributes = (array) $block->getData('attributes') ?? [];
$filteredAttributes = $fieldTypes->getDefinedFieldAttributes($attributes);
$hasError = isset($magewire->errors[$uid][$fieldName]);
$errorMessage = $hasError ? $magewire->errors[$uid][$fieldName] : '';

?>
<div class="field-container" id="field-container-<?= $escaper->escapeHtmlAttr("{$uid}_{$fieldName}") ?>" <?= $hasError ? 'data-error' : '' ?>>
    <input type="text"
        name="<?= $escaper->escapeHtmlAttr("{$uid}_{$fieldName}") ?>"
        value="<?= $escaper->escapeHtmlAttr($fieldValue) ?>"
        @keydown.debounce.500="
            updateField(
                '<?= $escaper->escapeHtmlAttr($uid) ?>',
                '<?= $escaper->escapeHtmlAttr($fieldName) ?>',
                $event.target.value
            )
        "
        class="field w-full form-input <?= $hasError ? 'error field-error ' : '' ?> <?= $escaper->escapeHtmlAttr($attributes['class'] ?? '') ?>"
        <?php foreach ($filteredAttributes as $attr => $value): ?>
            <?= $escaper->escapeHtmlAttr($attr) ?>="<?= $escaper->escapeHtmlAttr($value) ?>"
        <?php endforeach; ?>>
    <ul id="validation-messages-<?= $escaper->escapeHtmlAttr("{$uid}_{$fieldName}") ?>" class="validation-messages list-none">
        <?php if ($hasError): ?>
            <li class="error-message text-red-600 text-sm mt-1">
                    <?= $escaper->escapeHtml($errorMessage) ?>
            </li>
        <?php endif; ?>
    </ul>
</div>

Important Markup Requirements

When creating custom field templates, the following markup requirements must be followed to ensure proper functionality:

Field Container

Include to following as your root element.

<div class="field-container" id="field-container-<?= $escaper->escapeHtmlAttr("{$uid}_{$fieldName}") ?>" <?= $hasError ? 'data-error' : '' ?>>

This ID format is required for validation to work correctly.

The data-error attribute set by the magewire component variable $hasError is required for validation highlighting to work.

Input Name

Add name="<?= $escaper->escapeHtmlAttr("{$uid}_{$fieldName}") ?>" to your input field.

Required for frontend validation to work and for the the editor to focus on your field when users select its value in the editor preview.

Validation Messages Container

Include id="validation-messages-<?= $escaper->escapeHtmlAttr("{$uid}_{$fieldName}") ?>" on a container for validation messages.

Required for validation messages to appear.

You can optionally specify a different container using data-validation-messages-selector on the field container.

Field Value Updates

Two methods are available for updating field values:

  • updateField: Bypasses Magewire to update preview directly via AJAX, reading from local state until saved. Ideal for debounced inputs.
  • updateWireField: Updates both preview and server state through Magewire immediately.

If adding your own Alpine components, you cannot set values through these methods within your component. Keep input fields outside your Alpine component and update them with vanilla JavaScript.

Input Attributes

The $inputAttributes handling in the example above provides validation capabilities based on attributes passed in the component declaration. Hyvä CMS' built-in validation will validate the field against these HTML5 validation attributes. See Field Attributes and Validation for more information.

4. Dynamically Set the Field Value

Once you've created your custom field template, you have complete control over how the field value is set. You can:

  • Use Magento's standard data providers (ViewModels, Blocks, Controllers)
  • Fetch data via REST or GraphQL APIs
  • Connect to external systems
  • Implement custom business logic

Updating the Field Value

The field value is set through either the updateField or updateWireField method. If you are adding your own Alpine components, you cannot set the value through these method within your component. The input field should be kept outside of your Alpine component, your component can then update it with vanilla JavaScript.

Tip

For inspiration look at the field handlers in the Hyva_CmsLiveviewEditor::page/js/ adminhtml directory.