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;

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

$uid = (string) $block->getData('uid');
$fieldName = (string) $block->getData('name');
$fieldValue = (string) $block->getData('value');
$inputAttributes = (array) $block->getData('attributes') ?? [];

if ($inputAttributes) {
    $inputAttributes = array_filter([
        'placeholder' => $inputAttributes['placeholder'] ?? '',
        'minlength' => ($inputAttributes['minlength'] ?? '') ? (int) $inputAttributes['minlength'] : null,
        'maxlength' => ($inputAttributes['maxlength'] ?? '') ? (int) $inputAttributes['maxlength'] : null,
        'required' => ($inputAttributes['required'] ?? false) ? true : null,
        'class' => $inputAttributes['class'] ?? '',
    ]);
}

$hasError = isset($magewire->errors[$uid][$fieldName]);
$errorMessage = $hasError ? $magewire->errors[$uid][$fieldName] : '';
?>
<div class="field-container">
    <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 invalid:outline-red-500
            <?= $hasError ? 'error' : '' ?> <?= $escaper->escapeHtmlAttr($inputAttributes['class'] ?? '') ?>"
        <?php foreach ($inputAttributes as $attribute => $value): ?>
            <?= $escaper->escapeHtmlAttr($attribute) ?>="<?= $escaper->escapeHtmlAttr($value) ?>"
        <?php endforeach; ?>>
    <?php if ($hasError): ?>
        <div class="error-message text-red-600 text-sm mt-1">
            <?= $escaper->escapeHtml($errorMessage) ?>
        </div>
    <?php endif; ?>
</div>

Name Attribute

Add name="<?= $escaper->escapeHtmlAttr("{$uid}_{$fieldName}") ?>" to the input field so that the editor can focus on your field when the user selects it's value in the editor preview.

updateField vs updateWireField

In addition to the updateField method, you can also use the updateWireField method to update the field value.

  • 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.

$inputAttributes

In the example above, the $inputAttributes is included to allow for validation attributes which can be passed in the component declaration, to be used to validate your custom field. Hyvä CMS' inbuilt validation will validate the field against the HTML5 validation attributes provided. 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.