Tagixo Docs

Developer Documentation for Laravel, SDK integrations, and extensibility

Extending Tagixo

Custom Props

Build a new atomic widget with its own Vue component, configurable via fluent setters and reused across PropTypes.

Custom Props

A custom Prop is the right tool when you need a new widget type that the built-in Props (TextProp, SelectProp, SliderProp, ColorProp, ToggleProp, NumberProp, SizeProp, MediaProp, IconProp, FontPickerProp, EditorProp, ...) can't express. Typical triggers:

  • A date-range picker
  • A multi-stop gradient builder
  • A typed enum with icons in the dropdown
  • A specialized numeric range with both min and max captured at once

If the built-in Props cover your case, prefer composing them in a Custom PropType instead. Only build a custom Prop when a NEW widget is genuinely needed.

Scaffold

php artisan make:tagixo-prop RangeProp

Default destination: app/Tagixo/Props/RangeProp.php. Relocate via config('tagixo.scaffolding') or per-command flags.

Skeleton

The class extends Ccast\Tagixo\Core\Props\AbstractProp. The base class ships fluent helpers via make($key), setLabel(), default(), helpText(), variablePicker($type), showWhen(...).

<?php

namespace App\Tagixo\Props;

use Ccast\Tagixo\Core\Props\AbstractProp;

class RangeProp extends AbstractProp
{
    public function widget(): string
    {
        return 'range';
    }

    public function widgetConfig(): array
    {
        return $this->baseConfig();
    }
}

Required overrides

widget(): string

The widget identifier the frontend uses to dispatch the right Vue component. For schema-driven PropTypes, DynamicPropType.vue reads this value and renders the matching Vue widget. The string must match a widget registered in your frontend bundle.

Built-in widget identifiers (95% of cases): slider, select, toggle, text, textarea, number, color, size, icon, media, font-picker, editor, repeater, tabs, four-ways, box-shadow, model-select, css-declarations.

widgetConfig(): array

Payload sent to the Vue widget. Call $this->baseConfig() to inherit the standard keys (key, label, default, helpText, variablePicker, showWhen, …) and merge your widget-specific config on top.

Optional overrides

toCss(mixed $value): string

Return a CSS fragment if this Prop generates CSS on its own. Most Props don't — the parent PropType usually consolidates output (see FilterPropType or BoxShadowPropType). When in doubt, return ''.

Custom fluent setters

Add chainable methods that configure your widget. Match the pattern of SliderProp::min(), SliderProp::unit(): store on protected props and emit through widgetConfig().

Concrete example

A RangeProp that captures {min, max} values for a numeric range, configurable via min(0)->max(100)->step(1):

<?php

namespace App\Tagixo\Props;

use Ccast\Tagixo\Core\Props\AbstractProp;

class RangeProp extends AbstractProp
{
    protected float $min = 0;
    protected float $max = 100;
    protected float $step = 1;
    protected ?string $unit = null;

    public function widget(): string
    {
        return 'range';
    }

    public function min(float $min): static
    {
        $this->min = $min;
        return $this;
    }

    public function max(float $max): static
    {
        $this->max = $max;
        return $this;
    }

    public function step(float $step): static
    {
        $this->step = $step;
        return $this;
    }

    public function unit(string $unit): static
    {
        $this->unit = $unit;
        return $this;
    }

    public function widgetConfig(): array
    {
        return array_merge($this->baseConfig(), [
            'min' => $this->min,
            'max' => $this->max,
            'step' => $this->step,
            'unit' => $this->unit,
        ]);
    }
}

Use it inside any PropType schema():

public function schema(): array
{
    return [
        RangeProp::make('opacity_range')
            ->setLabel(__('Opacity range'))
            ->min(0)->max(1)->step(0.05)
            ->default(['min' => 0, 'max' => 1]),
    ];
}

Frontend pairing

The corresponding Vue widget MUST be available in the consumer's frontend bundle. Two options:

  1. Use an existing widget: in 95% of cases one of the built-in widget identifiers fits. Just return its string from widget() and you're done.
  2. Ship a custom Vue widget: build it in your plugin's frontend bundle, register it in the widget dispatcher, ensure the consumer imports your plugin's assets (see Tagixo Plugin for the asset publication flow).

If your Prop reuses the slider widget but with different defaults, you don't need any Vue code — return 'slider' from widget() and configure via widgetConfig().

Registration

Props are NOT separately registered. They're instantiated inside PropType::schema() and travel with the PropType through the bootstrap payload. The make:tagixo-prop command prints a reminder of this on success.

If your Prop is meant to be shared across many PropTypes in a plugin, the plugin's service provider just needs to register the PROPTYPE — the Prop comes along for the ride.

Reusability

The fluent API makes a custom Prop ergonomic across many PropTypes:

RangeProp::make('opacity')->min(0)->max(1)->step(0.01)
RangeProp::make('zoom')->min(0.5)->max(3)->step(0.1)
RangeProp::make('temperature')->min(-20)->max(40)->unit('°C')

Same widget, different configuration each time.

Testing checklist

  • Widget dispatches correctly (DynamicPropType.vue renders the right Vue component)
  • widgetConfig() payload contains all custom keys
  • Defaults persist round-trip (save → reload → render produces identical state)
  • Fluent setters return $this so chains work
  • variablePicker() and showWhen() from the base class still work when set