wandi/color-picker-bundle
A Symfony bundle for adding color picker fields to forms. It provides a ready-to-use form type and frontend assets, making it easy to let users select colors with minimal configuration and integrate color input into existing Symfony applications.
This is a Symfony bundle, not a Laravel package. There is no service provider, no vendor:publish, no Blade views, and no config file in config/ that Laravel would auto-load. If you are working in a Laravel codebase, the practical answer is: do not composer require this — copy the pattern instead (a Blade component + Alpine/Livewire that initialises Pickr). The steps below assume a Symfony host.
Minimal steps in a Symfony app:
composer require wandi/color-picker-bundleconfig/bundles.php:
return [
// ...
Wandi\ColorPickerBundle\WandiColorPickerBundle::class => ['all' => true],
];
bin/console assets:install --symlink
use Wandi\ColorPickerBundle\Form\Type\ColorPickerType;
$builder->add('brandColor', ColorPickerType::class, [
'picker_options' => [
'theme' => 'nano',
'default' => '#3498db',
'components' => [
'preview' => true,
'opacity' => true,
'hue' => true,
],
],
]);
Where to look first in the repo:
Form/Type/ColorPickerType.php — the option keys it actually accepts and how picker_options is passed to the JS constructor. This is the single source of truth for the API.Resources/views/ — the form theme block that renders the hidden input and the inline pickr.create(...) call.DependencyInjection/Configuration.php — whether there are global bundle-level defaults or only per-field options.Resources/public/ (or wherever the JS lives) — whether Pickr is bundled or whether you are expected to supply it.The first realistic use case: an admin CRUD form where a colour is one field among many, and you want a preview chip on the index/show pages. That works out of the box; anything beyond that (collections, modals, SPAs) needs custom wiring.
The standard "form field + preview chip" pattern. The form type is just a Symfony ChoiceType/TextType wrapper with options, so it composes normally into AbstractType classes:
->add('accent', ColorPickerType::class, [
'label' => 'Accent colour',
'picker_options' => ['default' => $entity->getAccent() ?: '#ffffff'],
])
Persist the result as a plain string. Pickr emits #rrggbb or #rrggbbaa depending on whether the opacity component is enabled — size the column accordingly (VARCHAR(7) without alpha, VARCHAR(9) with).
Decoupling from the bundle's assets. For any project already on Encore/Vite, the common pattern is to keep the form type for the server-side option plumbing but replace the widget rendering: import @simonwep/pickr in your own JS entrypoint and register a small Stimulus controller. This gives you full control over CSP, tree-shaking, and initialisation timing, and insulates you from the bundle's Symfony 4-era asset layout.
Multiple pickers / dynamic collections. Symfony's collection prototypes render inputs after page load. Any initialisation the bundle does on DOMContentLoaded will miss them. The reliable pattern is a Stimulus controller attached to each row that runs Pickr.create() in connect() and destroy() in disconnect() — this works identically for prototype rows and Turbo/Livewire re-renders.
Normalising before persistence. Put the trim/#-prepend logic in the entity setter or a small DTO rather than the controller, and pair it with a validation constraint (see Gotchas). This keeps the form type purely presentational.
Theming. Pickr ships classic, monolith, and nano. Pass the theme through picker_options and style the surrounding label/swatch to match your design system; the bundle will not do that for you.
For a Laravel port, the equivalent shape is: a ColorPicker Blade component with <input type="hidden"> + Alpine component initialising Pickr from node_modules, plus a color validation rule (regex:/^#([0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/). Total effort is a few dozen lines — cheaper than adapting a stale Symfony 4 bundle.
composer.json constraints against your Symfony version before installing; the form type API is stable, but the Twig/asset conventions changed in Symfony 5 and 6. Pin the version and review updates rather than floating.assets:install and an explicit <link>/<script> in base.html.twig, or you supply Pickr yourself. If the picker renders as a bare input, this is the first thing to check.value in devtools — it is frequently a disabled element or an input that was never re-synced after a programmatic reset.picker_options must be JSON-serialisable. Do not pass PHP closures for onSave/onChange callbacks; they will be silently dropped or throw during json_encode. Use plain scalars/arrays and attach behaviour in your own JS instead.Regex/Assert constraint such as ^#[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$ and reject anything else — an empty colour is a common accidental submission when the picker is cleared.components.opacity changes the emitted format. Decide up front whether you store RGBA, #rrggbbaa, or plain hex, and keep the default option consistent with the stored value (Pickr wants a leading #).<script> to create the picker. In a strict Content-Security-Policy app this will be blocked; either add a nonce to the theme override or move initialisation entirely to an external module.color_picker_widget in your own templates/form/, (2) decorate the form type or create a thin subclass with your house defaults, (3) global defaults via the bundle configuration if Configuration.php exposes them. Editing vendor code is the wrong answer given how little is likely to be maintained upstream.window.Pickr in the console). A silent ReferenceError in the inline initialiser is the most common failure mode, and it leaves a perfectly functional plain text input that nobody notices until QA.How can I help you explore Laravel packages today?