Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Color Picker Type Bundle Laravel Package

oh/color-picker-type-bundle

A Symfony bundle that adds a ready-made color picker form type, letting you drop a color selection field into forms with minimal setup. Configurable options make it easy to control the picker's behavior and appearance.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Framework reality check, first. oh/color-picker-type-bundle is a Symfony2 form type bundle, not a Laravel package. There is no service provider, no config/ to publish, no Blade views, and no facade. composer require oh/color-picker-type-bundle in a Laravel app gets you an autoloaded Symfony AbstractType you cannot render. The realistic day-to-day posture is: read it as a reference implementation, then reimplement the pattern in ~30 lines of Blade + a validation rule.
  • Read these three things and you have read the package. (1) The form type class — typically Form/Type/ColorPickerType.php, extending AbstractType with buildForm() / configureOptions(); (2) the Twig template under Resources/views/Form/ that renders the input and bootstraps the JS widget; (3) Resources/public/js/ + Resources/public/css/ for the vendored picker library. If the type does nothing beyond ->add('color', TextType::class, [...]) plus a template block, it is a thin wrapper — confirmed by reading buildForm().
  • Laravel port, minimal path. One Blade component + one validation rule + one migration column. That is the entire feature surface this bundle actually delivers:
    // app/Rules/HexColor.php
    public function passes($attribute, $value) {
        return is_string($value) && preg_match('/^#([0-9a-f]{3}|[0-9a-f]{6})$/i', $value);
    }
    
    {{-- resources/views/components/color-picker.blade.php --}}
    <div x-data="{ color: @js(old($name, $value ?? '#000000')) }" class="flex items-center gap-2">
        <input type="color" x-model="color" :value="color" class="h-9 w-9 ...">
        <input type="text" name="{{ $name }}" x-model="color" maxlength="7"
               class="..." {{ $attributes->merge(['class' => '']) }}>
    </div>
    
  • First use case: a single optional brand_color hex value on a settings/profile form. Picker opens, user selects, value posts as #RRGGBB, HexColor rule validates it, model stores the canonical lowercase string.
  • Register/see it on the Symfony side if you're in a legacy app: add new Oh\ColorPickerTypeBundle\OhColorPickerTypeBundle() to AppKernel.php, run bin/console assets:install --symlink, then ->add('color', ColorPickerType::class) in a form. If that produces no visible widget, the asset step is the culprit — see Gotchas.

Implementation Patterns

  • Mirror the form-type contract with a component + rule pair. The reusable unit in Symfony is the form type; in Laravel it is the <x-color-picker> component plus the HexColor rule. Keep the pair in one place so every form (settings, brand themes, tag labels, category colors) uses the identical markup and the identical server-side check. Never let a form ship the input without the rule.
  • Normalize before you validate, not after. The picker never normalizes — it will happily post #ABC, ABCDEF, or an empty string if untouched. Do it in a FormRequest:
    protected function prepareForValidation(): void
    {
        $c = $this->input('brand_color');
        $this->merge(['brand_color' => $c === '' || $c === null ? null : '#' . ltrim(strtolower($c), '#')]);
    }
    
    Then validate with ['nullable', 'string', new HexColor]. Store canonical #rrggbb — never 3-digit, never uppercase — so later comparisons, contrast checks, and CSS injection don't drift.
  • Canonical storage shape. $table->string('brand_color', 7)->nullable() (or a char(7)), holding #rrggbb. Keeping it a plain string with no alpha and no color-space metadata is the one design decision from this bundle worth copying verbatim: it keeps future HSL/OKLCH or theme-token work a read-time concern rather than a migration.
  • Component props drive the configureOptions analogue. Symfony exposes setDefaultOptions/configureOptions; in Laravel those become props plus attribute merging: :readonly, :required, placeholder, size, :preview="false". Pass through unknown attributes with $attributes->merge() so the component composes like a native input.
  • Livewire / Alpine binding. If the form is Livewire, wire:model on the text input works because the picker dispatches input; pair it with wire:model.blur or a debounce so the picker doesn't fire a request on every drag. On the color swatch, wire:ignore the wrapper if you re-init a third-party library.
  • Progressive enhancement as the default. Start with <input type="color"> (native, zero JS, no CSP inline scripts). Layer a maintained picker (Pickr, Spectrum) on top via a Vite entry if you need presets/swatches/named palettes. The Symfony bundle's Twig template is exactly this layering, written pre-Vite — copy the layering idea, not the asset plumbing.
  • Asset wiring, Laravel-style. resources/js/color-picker.js imported from app.js, CSS in resources/css/app.css, built with Vite. This replaces assets:install entirely; do not attempt to publish the bundle's Resources/public/ into public/.
  • Template-override analogue. Symfony users override app/Resources/OhColorPickerTypeBundle/views/Form/...; Laravel users override by publishing the component view (php artisan vendor:publish style) or by wrapping it — same idea, so downstream apps can theme the swatch without editing your component.
  • Filament / Nova / other admin panels. Skip the bundle entirely; implement a custom field wrapping the same Blade component and rule. Both frameworks have their own form-field contracts that look more like Symfony's than like the bundle's, but the bundle still isn't the integration point.
  • Test it once, at the rule and at the component. A Pest test hitting each of #fff, #FFFFFF, fff (normalized), red, javascript:alert(1), and '' pins the contract far better than clicking a picker in the browser; component tests assert the input name and the current value are rendered.

Gotchas and Tips

  • Do not install it. Symfony2 is EOL, the bundle is unmaintained (4 stars, 0 dependents), and there is no Laravel service provider. Adoption means forking two files and owning them permanently, which is strictly worse than writing the twenty-line replacement.
  • "Blank widget" is almost always assets:install. In the Symfony path, forgetting bin/console assets:install --symlink (or the wrong --symlink flag) leaves the JS/CSS unreferenced and you get a plain text input with no picker. Clear var/cache / app/cache afterwards — Symfony caches Twig hard, so an overridden template that "isn't taking effect" is usually a stale cache, not a path bug. Verify with bin/console debug:twig and debug:container --tag=form.type.
  • Template override paths are case- and subpath-sensitive. The override must live under the exact bundle name and the exact subpath as the vendor template (Resources/views/Form/...). A silent miss falls back to the vendor template with no error.
  • Empty string ≠ null. An untouched picker posts "", which fails a strict regex rule and passes a nullable rule only if you convert it first. Normalize '' → null in prepareForValidation(), and decide explicitly whether the column allows null or enforces a default.
  • Regex traps. #RGB and #RRGGBB are easy; #RRGGBBAA, rgb(), hsl(), CSS named colors, and transparent are not covered by the bundle or by the naive regex — reject them deliberately rather than accepting them into a string(7) column. Also anchor the pattern (^...$) or you'll accept #ff0000-onclick=.
  • No normalization, ever, from the widget. The picker emits whatever the underlying JS library produces (some lowercase and pad, some don't; some emit empty string, some emit the previous value). Lowercase, #-prefix, and 3→6 expansion are yours to write, server-side.
  • Livewire/DOM morphing breaks pickers. Third-party pickers that attach to an element on DOMContentLoaded will silently stop working after a Livewire update or Turbo visit. Either wrap in wire:ignore and re-init on livewire:navigated, or use the native <input type="color"> — it never needs re-init and is the more robust baseline.
  • CSP breaks the vendored picker. Old color-picker libraries inject inline <style>/<script> and eval-adjacent code; under a strict Content-Security-Policy they fail silently in production but work locally. Test under your real headers before assuming the widget works.
  • Accessibility is not bundled. Color alone is not a label: pair the swatch with a text input showing the hex so keyboard and screen-reader users can type a value, and give the swatch aria-label. The bundle does not do this, and any picker you drop in probably won't either.
  • Debug order when porting: (1) does the input have the expected name attribute and appear in the POST payload; (2) does prepareForValidation() see the normalized value; (3) does the rule reject the bad-input test cases; (4) only then look at the JS. Nearly every "the picker doesn't work" bug is a step-1 naming or a step-2 normalization problem, not a JavaScript problem.
  • Extension points are thin, which is the argument for not adopting it. Per-field customization goes through form options + template overrides; there is no config tree. If your roadmap touches theming, contrast checking, or non-hex color spaces, the bundle offers nothing and you would own every extension anyway.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console