Custom PropTypes
A custom PropType is the right tool when you need a reusable group of design fields plus consolidated CSS output that no built-in PropType covers. Typical triggers:
- A multi-shadow stack PropType emitting compound
box-shadowvalues - A "Box decoration" PropType bundling background + border + shadow as one ergonomic unit
- A glassmorphism / neumorphism design preset wired into the design tab
- A 3D-transform PropType with origin + perspective controls
If you only need a single field, build a Custom Prop instead.
Scaffold
php artisan make:tagixo-prop-type GlassmorphismPropType
Default destination: app/Tagixo/PropTypes/GlassmorphismPropType.php. Relocate globally via config('tagixo.scaffolding') or per-command with --path=/--namespace=/--package=.
Skeleton
The class extends Ccast\Tagixo\Core\PropTypes\AbstractPropType, which provides defaults and shared helpers like resolveColor().
<?php
namespace App\Tagixo\PropTypes;
use Ccast\Tagixo\Core\PropTypes\AbstractPropType;
class GlassmorphismPropType extends AbstractPropType
{
public function key(): string
{
return 'glassmorphism';
}
public function label(): string
{
return __('Glassmorphism');
}
public function tab(): string
{
return 'design';
}
public function hasCss(): bool
{
return true;
}
public function schema(): array
{
return [];
}
public function toCss(array $values): string
{
return '';
}
}
Concrete example
A GlassmorphismPropType that combines a translucent background, backdrop blur/brightness, and border radius into one design unit:
<?php
namespace App\Tagixo\PropTypes;
use Ccast\Tagixo\Core\PropTypes\AbstractPropType;
use Ccast\Tagixo\Core\Props\ColorProp;
use Ccast\Tagixo\Core\Props\SliderProp;
class GlassmorphismPropType extends AbstractPropType
{
public function key(): string { return 'glassmorphism'; }
public function label(): string { return __('Glassmorphism'); }
public function tab(): string { return 'design'; }
public function hasCss(): bool { return true; }
public function schema(): array
{
return [
ColorProp::make('background_color')
->setLabel(__('Background Color'))
->default('rgba(255, 255, 255, 0.1)')
->variablePicker('color'),
SliderProp::make('backdrop_blur')
->setLabel(__('Backdrop Blur'))
->default(10)->min(0)->max(20)->step(0.5)->unit('px'),
SliderProp::make('backdrop_brightness')
->setLabel(__('Backdrop Brightness'))
->default(100)->min(0)->max(200)->unit('%'),
SliderProp::make('border_radius')
->setLabel(__('Border Radius'))
->default(8)->min(0)->max(50)->step(1)->unit('px'),
];
}
public function features(): array
{
return ['resetAll', 'resetField', 'preview'];
}
public function toCss(array $values): string
{
$rules = [];
$bg = $values['background_color'] ?? null;
if (! empty($bg)) {
$rules[] = "background: {$bg};";
}
$filterParts = [];
$blur = (float) ($values['backdrop_blur'] ?? 0);
if ($blur > 0) $filterParts[] = "blur({$blur}px)";
$brightness = (float) ($values['backdrop_brightness'] ?? 100);
if ($brightness !== 100.0) $filterParts[] = "brightness({$brightness}%)";
if (! empty($filterParts)) {
$rules[] = "backdrop-filter: " . implode(' ', $filterParts) . ';';
}
$radius = (float) ($values['border_radius'] ?? 0);
if ($radius > 0) {
$rules[] = "border-radius: {$radius}px;";
}
return implode(' ', $rules);
}
}
Required methods
| Method | Purpose |
|---|---|
key(): string |
Registry key. Used in ModuleDefinition::design(...) to enable the PropType on a module. |
label(): string |
Human-readable name shown in the drawer. |
tab(): string |
One of 'content', 'design', 'advanced'. Controls which drawer tab the PropType appears in. |
hasCss(): bool |
Return true for CSS-generating PropTypes โ the renderer collects only PropTypes that opt in. |
schema(): array |
List of AbstractProp instances. The drawer renders one input per Prop. |
toCss(array $values): string |
Return CSS declarations (no selector, no braces). The default toCssWithSelectors($values, $selector) wraps this output with the right selector. |
Optional methods
| Method | Purpose |
|---|---|
features(): array |
Toggle UI affordances: ['resetAll', 'resetField', 'preview']. |
defaults(): array |
Auto-computed from schema(). Override if you need custom merging. |
placeholders(): array |
Per-prop placeholder values for the drawer inputs. |
vueComponent(): ?string |
Return a string to use a CUSTOM Vue component instead of the schema-driven renderer. This is the escape hatch when a PropType needs UI you can't express via Props (gradient builders, color-stop pickers, drag-to-position controls). |
CSS generation idioms
- Skip emission when value equals default to avoid CSS bloat โ see
FilterPropTypefor the canonical pattern. - Compose multiple values into a single CSS property when the underlying spec is one (e.g.
filter: brightness() blur()). - Use
StyleGeneratorhelpers (StyleGenerator::backgroundToCss(),boxShadowToCss(), etc.) for shapes that the core already handles. - No selectors in
toCss(): the wrapping is done bytoCssWithSelectors(). Return just declarations.
Registration
Two ways:
// In config/tagixo.php
'prop_types' => [
\App\Tagixo\PropTypes\GlassmorphismPropType::class,
],
// In any service provider's boot()
\Ccast\Tagixo\Facades\Tagixo::registerPropTypes([
\App\Tagixo\PropTypes\GlassmorphismPropType::class,
]);
The scaffold command prints the right snippet for you when the file is created.
Frontend rendering
Schema-driven PropTypes render through DynamicPropType.vue automatically โ no Vue code needed when vueComponent() returns null. You only build a custom Vue component when the UX cannot be expressed via the built-in Prop widgets (slider, select, toggle, text, number, color, ...).
Testing checklist
- PropType appears in the bootstrap payload (
availableComponents.propTypeRegistry) toCss()produces expected output for sensible value sets- Default values do NOT emit CSS (verify by inspecting render output)
- Reset behaviour works in the drawer
- Adding the PropType to a module via
->design(...)makes the tab section render without console errors