Custom Product Attribute with Its Own Frontend Widget in Magento 2
AI generated
Magento 2 · Product Data

Custom Product Attribute
with Its Own Frontend Widget

A product attribute in Magento 2 is quick to create. It only becomes truly valuable once admin maintenance, EAV setup, frontend output and a clean widget in the theme all fit together. That is exactly what this tutorial is about.

16 min read EAV Magento 2.4.8

1. What the attribute should achieve in the store

A custom product attribute in Magento 2 is the right starting point in many projects once product data is no longer just name, price and description. Typical examples are care instructions, shipping peculiarities, technical specifications, sustainability features, product seals or interactive data blocks that should appear in the frontend not just as a line of text, but as their own widget.

This is exactly where a quick data field parts ways with a good store implementation. If the attribute only exists in the backend but ends up unstructured in a long data block on the frontend, its usefulness stays limited. A good custom product attribute in Magento 2 combines EAV maintenance with a clear output form. The attribute needs to be easy to maintain in the admin and needs to appear in the frontend in a way that gives users a real benefit.

For this tutorial we use an attribute called delivery_badge. Per product it should control a small hint such as "Cold Shipping", "24h Shipping" or "Preorder" and appear in the frontend as a visual widget above the product details. The example is deliberately tangible: it shows how an EAV field becomes a real frontend component.

2. Creating a clean product attribute

A custom product attribute in Magento 2 is typically created via a data patch. That is the clean approach today because it keeps the module reproducible and upgrade safe. It is important not to define the attribute only minimally, but to deliberately decide on data type, input type, scope, visibility, usability in grids, searchability, filterability and frontend relevance.

For a badge attribute, a select attribute is often more sensible than free text. It lets the admin choose only defined values, and the frontend widget gets more stable states. Free text sounds more flexible at first, but it makes CSS states, translations and UI consistency harder to manage. This is exactly where a good custom product attribute in Magento 2 proves to be more than just an extra field.


<?php
declare(strict_types=1);

namespace Mironsoft\ProductBadge\Setup\Patch\Data;

use Magento\Catalog\Model\Product;
use Magento\Eav\Model\Entity\Attribute\ScopedAttributeInterface;
use Magento\Eav\Setup\EavSetupFactory;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Magento\Framework\Setup\Patch\DataPatchInterface;

/**
 * Adds the delivery badge product attribute.
 */
final class AddDeliveryBadgeAttribute implements DataPatchInterface
{
    public function __construct(
        private readonly ModuleDataSetupInterface $moduleDataSetup,
        private readonly EavSetupFactory $eavSetupFactory
    ) {}

    public function apply(): self
    {
        $eavSetup = $this->eavSetupFactory->create(['setup' => $this->moduleDataSetup]);

        $eavSetup->addAttribute(
            Product::ENTITY,
            'delivery_badge',
            [
                'type' => 'int',
                'label' => 'Delivery Badge',
                'input' => 'select',
                'source' => \Mironsoft\ProductBadge\Model\Config\Source\DeliveryBadge::class,
                'required' => false,
                'visible' => true,
                'user_defined' => true,
                'global' => ScopedAttributeInterface::SCOPE_STORE,
                'group' => 'General',
                'used_in_product_listing' => true,
                'visible_on_front' => false
            ]
        );

        return $this;
    }

    public static function getDependencies(): array
    {
        return [];
    }

    public function getAliases(): array
    {
        return [];
    }
}

The used_in_product_listing option matters if the attribute is later needed in product listings or teasers. Without thinking through such decisions early, you end up with an attribute that works only on PDPs but is not available on category pages or in headless listings. A good custom product attribute in Magento 2 is therefore planned not just for the first screen, but for its entire data path.

3. Admin maintenance and EAV classification

For the attribute to be genuinely usable day to day, admin maintenance needs to be clear. Anyone creating a custom product attribute in Magento 2 should think not only about its technical existence, but about the editorial workflow. Is the field name unambiguous? Does the attribute group fit? Is it clear which selection triggers which frontend effect? Are store views relevant? These questions decide whether the field stays cleanly maintained later or becomes a source of errors.

Especially for select attributes, a clean source model class pays off. That keeps the available states controlled, reusable and easy to read. If new states are added later, the logic in the frontend can be extended in a targeted way. That is far more robust than misusing arbitrary free text values as CSS classes or UI variants.


<?php
declare(strict_types=1);

namespace Mironsoft\ProductBadge\Model\Config\Source;

use Magento\Eav\Model\Entity\Attribute\Source\AbstractSource;

/**
 * Provides delivery badge options for the product attribute.
 */
final class DeliveryBadge extends AbstractSource
{
    public function getAllOptions(): array
    {
        return [
            ['label' => __('-- Please Select --'), 'value' => ''],
            ['label' => __('24h Shipping'), 'value' => 1],
            ['label' => __('Preorder'), 'value' => 2],
            ['label' => __('Cold Shipping'), 'value' => 3]
        ];
    }
}

From an EAV point of view this attribute is still just a piece of product information. The difference only emerges from what the frontend later does with it. That is exactly why the topic of custom product attribute in Magento 2 is interesting: the attribute model stays close to the standard, while the output becomes project specific.

4. Frontend output with layout XML and ViewModel

In the Hyva context, the output should not happen through unstructured direct access in the template, but through layout XML and a ViewModel. That is the clean way to embed a custom product attribute in Magento 2 stably into the product page. The ViewModel can read the current product context, interpret the attribute value and deliver a clearer data structure to the template.

The big advantage is that the template is not burdened with Magento EAV details. Instead of assembling values and labels directly, the view gets exactly what it needs to render: badge text, badge key, active state and perhaps a help text. That keeps the template layer clean and makes later extension easier.


<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceContainer name="product.info.main">
            <block class="Magento\Framework\View\Element\Template"
                   name="mironsoft.product.delivery.badge"
                   template="Mironsoft_ProductBadge::product/delivery-badge.phtml"
                   before="-">
                <arguments>
                    <argument name="view_model" xsi:type="object">Mironsoft\ProductBadge\ViewModel\DeliveryBadge</argument>
                </arguments>
            </block>
        </referenceContainer>
    </body>
</page>

<?php
declare(strict_types=1);

namespace Mironsoft\ProductBadge\ViewModel;

use Magento\Framework\Registry;
use Magento\Framework\View\Element\Block\ArgumentInterface;

/**
 * Provides delivery badge data for the product page widget.
 */
final class DeliveryBadge implements ArgumentInterface
{
    public function __construct(
        private readonly Registry $registry
    ) {}

    /**
     * Returns normalized badge data for the current product.
     *
     * @return array<string, string>|null
     */
    public function getBadgeData(): ?array
    {
        $product = $this->registry->registry('current_product');

        if (!$product) {
            return null;
        }

        $value = (int) $product->getData('delivery_badge');

        return match ($value) {
            1 => ['key' => 'fast', 'label' => '24h Shipping'],
            2 => ['key' => 'preorder', 'label' => 'Preorder'],
            3 => ['key' => 'cold', 'label' => 'Cold Shipping'],
            default => null,
        };
    }
}

This turns the attribute from something merely displayed into a deliberately interpreted UI data structure. That is often exactly the difference between a field and a real widget. A good custom product attribute in Magento 2 keeps data storage and presentation clearly separated.

5. A custom frontend widget in the Hyva context

Now comes the actual value: the widget output. The template should not look like a generic data dump, but should render a small, self-contained component. In the Hyva context that means lean templates, Tailwind classes directly in the markup and, where needed, Alpine.js for additional interactivity. For our badge, a visual output without extra JavaScript is enough.

It matters that the widget fits the attribute in substance. A delivery hint attribute is not just another bullet point. It is a prominent piece of information that can influence the purchase decision. That is why it belongs in a visible spot on the product page. This is exactly what justifies turning a custom product attribute in Magento 2 into a real frontend widget.


<?php
declare(strict_types=1);

use Magento\Framework\Escaper;
use Magento\Framework\View\Element\Template;
use Mironsoft\ProductBadge\ViewModel\DeliveryBadge;

/**
 * @var Template $block
 * @var Escaper $escaper
 * @var DeliveryBadge $viewModel
 */
$viewModel = $block->getData('view_model');
$badge = $viewModel ? $viewModel->getBadgeData() : null;
?>

<?php if ($badge): ?>
    <div class="mb-4">
        <div class="inline-flex items-center gap-2 rounded-md border border-lime-200 bg-lime-50 px-3 py-2 text-sm font-semibold text-lime-900">
            <span class="inline-block h-2.5 w-2.5 rounded-full bg-lime-500"></span>
            <span><?= $escaper->escapeHtml($badge['label']) ?></span>
        </div>
    </div>
<?php endif; ?>

This example is deliberately kept light, but the structure also carries more complex widgets. You could add colors, icons, tooltip texts or additional state logic. You could reuse the badge in listings, provided the attribute gets loaded in the listing. What matters is that the widget is not just a design element, but grows out of a clearly maintained data point.

This cleanliness pays off twice over, especially in a Hyva environment. A custom product attribute in Magento 2 with a ViewModel and a clear template structure is easier to extend, test and move to other PDP areas than a spontaneous inline output stuck in the middle of an existing PHTML file.

6. Common mistakes

The most common mistake is creating the attribute correctly but building the frontend output without structure. The value then hangs somewhere between other product info, or gets read directly via getData() from multiple places in templates. That stays maintainable only until the attribute needs more than a single presentation form.

Another mistake is the wrong attribute type. Many teams reflexively reach for text fields even though select options would be the better choice. This costs them consistency in data maintenance and frontend variants. Incorrect scope behavior is also a problem: if a badge should vary per store, the attribute must be planned as store specific. If it should be global, an unnecessary store scope only creates editorial confusion.

It is also frequently forgotten that a custom product attribute in Magento 2 has different loading paths in listings or APIs than on the product page. Just because the attribute is available on the PDP does not automatically mean it also comes along cleanly in product listings, REST or GraphQL. Thinking through these paths early saves patchwork later.

7. Attribute text vs. a real widget

Not every attribute needs a widget. Some product information is perfectly sufficient as a plain line or tab content. The decision depends on whether the attribute is purchase relevant, visually prominent or meant to be interactive. That is exactly why a direct comparison makes sense.

Approach Well suited for Limit
Simple attribute text Additional product information without strong emphasis Little visual guidance, barely any UI benefit
Custom frontend widget Highlighted, visual or state dependent product info More architecture and design effort
Complex widget logic Badges, hints, status indicators, interactions Needs a clear maintenance process and a clean data model

So the right path is not automatically "more widget". The right path is an output form that does justice to the attribute. If the attribute has real purchase or usage relevance, a widget is often worthwhile. If it is just supplementary metadata, a simple presentation is often enough.

Mironsoft

Magento 2 product data, EAV and Hyva frontend components

Want to make your product attributes genuinely usable in the frontend?

We develop Magento 2 product attributes with clean EAV setup, clear admin maintenance and Hyva compatible frontend components that don't just store data, but deliver real UI value.

EAV Setup

Clean attributes, options and scope decisions instead of quick fixes

Frontend

Layout XML, ViewModels and widgets that fit Hyva and Magento 2.4.8

Product page

Visible, maintainable product info with real value for customers

9. Summary

A custom product attribute in Magento 2 only unfolds its full value once EAV setup, admin maintenance and frontend output are thought through together. The attribute itself is just the data foundation. The actual value comes from a deliberately designed presentation in the store.

With a data patch, select options, a ViewModel and a custom widget you get a solution that stays editorially maintainable and technically clean. This exact combination turns an extra field into a real store feature, not just another attribute in the backend.

Custom Product Attribute Magento 2: The Essentials at a Glance

Attribute

Define it cleanly via a data patch and deliberately choose type, scope and maintenance form.

Maintenance

Select options are often more robust than free text when UI states need to stay controlled.

Frontend

Structure the output via layout XML, a ViewModel and a custom Hyva compatible widget.

Architecture

Separate data storage and presentation so the attribute stays controllable in PDP, listing and APIs.

10. FAQ: Custom Product Attribute with Frontend Widget in Magento 2

1 What is a custom product attribute in Magento 2?
An additional EAV property for products that can be maintained in the admin and used in the frontend.
2 How do you create it cleanly?
Via a data patch with EAV setup and deliberately chosen attribute options.
3 When is select better than text?
When fixed UI states and consistent values are needed, for example for badges or labels.
4 Why not use getData() directly in the template?
A ViewModel prepares the data cleanly and keeps templates more maintainable.
5 What does a frontend widget give you?
It turns an attribute into a visible, designed store component with real benefit for the customer.
6 Does this fit Hyva?
Yes, via layout XML, ViewModels and Tailwind markup directly in the template.
7 What is a typical mistake?
Wrong attribute type, unclear scope and unstructured frontend output without a ViewModel.
8 Does every attribute need a widget?
No. Widgets pay off mainly for visible or purchase relevant information.
9 How do you make the output reusable?
Via normalized ViewModel data and a small template that can also be embedded elsewhere.
10 How do you test this cleanly?
With different attribute states, store views and product pages, not just one example product.