nowo-tech/tag-input-bundle
A Symfony bundle that provides a reusable tag input form type for collecting multiple values as interactive tags, with autocomplete, AJAX-loaded suggestions, and Doctrine entity integration for flexible tagging.
composer require nowo-tech/tag-input-bundle. There is no Flex recipe at this adoption level, so check composer.json extra.symfony — if the bundle isn't auto-registered, add Nowo\TagInputBundle\TagInputBundle to config/bundles.php manually.src/Resources/public/build. Run php bin/console assets:install --symlink (or wire the bundle's entrypoint into your own Vite/Encore build) and confirm the JS/CSS actually load in the network tab before debugging anything else. Most "it doesn't work" reports for this class of bundle are 404s on the Tagify assets.prependExtension — check config/packages/twig.yaml → form_themes. Without the theme the field degrades to a plain text input with no chips.Post entity with a tags column. Add the bundle's form type to your form with whitelist and max_tags, render it, type a few tags, submit, and dump the mapped value. That single loop tells you the two things you actually need to know: whether the type maps to an array or a delimited string, and whether the whitelist blocks or merely suggests.Where to look first, in order: README.md (usage snippet and option names), src/Form/ (the type itself and its configureOptions — the authoritative option list), src/DependencyInjection/Configuration.php (bundle-level defaults for whitelist/max tags/asset paths), src/Resources/views/ (the form theme block and its data-* hooks), src/Resources/assets/ (the TS entrypoint that boots Tagify), and tests/ for canonical option names when the README is thin.
Enforce limits on the server, always. whitelist and max_tags are presented to the user as a UI affordance. Add a Count constraint for the tag count and a Choice(multiple: true, choices: ...) (or a small custom constraint) for the whitelist directly on the form field's constraints option. Treat the Tagify config as cosmetic.
Normalize the mapping once. If your column stores CSV and the type emits arrays (or vice versa), wrap it in a tiny app-level form type with a CallbackTransformer in buildForm, rather than repeating addModelTransformer in every form. One TagsType in your App\Form\Type namespace that composes the bundle's type gives you consistent empty_data and null handling for free.
Layer your own defaults. Subclass or wrap the bundle type with your organization's standard max_tags, delimiters, and Tagify settings, and expose the raw pass-through options as an escape hatch. This keeps bundle upgrades from rippling through every form and gives you one place to change behavior.
Dynamic whitelists from the database. Keep the form type stateless: inject a repository into a form-type factory, or populate the option in the controller / a parent-form PRE_SET_DATA listener. Avoid querying inside configureOptions — it runs during container compilation paths you don't want to think about.
Dynamic collections. When rows are added client-side (Symfony CollectionType), Tagify must be re-initialized on the new inputs. Reuse the bundle's existing bootstrap — a MutationObserver or your collection's collection:item-added event — instead of writing a second initializer that races the first one.
Vite integration. Either let the bundle serve its own prebuilt assets (simplest) or import its entrypoint from your host app's Vite config. Check package.json for a peer dependency on @yaireo/tagify and dedupe — two Tagify copies on one page produce confusing, hard-to-trace breakage.
Testing. A TypeTestCase/KernelTestCase submitting ['tags' => ['a', 'b']] covers transformation and validation and is the highest-value test. Add one browser-level check (Panther or Playwright) that the field renders as a Tagify input — assert on the data-* attributes rather than screenshots.
whitelist is a suggestion list by default. Unless enforceWhitelist is set on the Tagify settings, users can type arbitrary tags. This is the single most common source of "validation passed but garbage got stored."max_tags is client-side only. Paste, autofill, and disabled JS all bypass it. Server constraint or it doesn't exist."" rather than [] (or [] where you expected null). Normalize in reverseTransform and set empty_data explicitly, otherwise NOT NULL columns blow up on an empty form.bin/console debug:twig to confirm the theme is picked up. If the input renders as plain text, the theme isn't registered — not a JS bug.asset() calls can resolve against your manifest and 404. Check framework.assets package config and the rendered <script src>. Also: never edit src/Resources/public/build — it's generated output and your changes will vanish on the next release.DOMContentLoaded init leaves chips dead after navigation. Attach initialization to turbo:load (or a mutation observer) and keep exactly one bootstrap path.delimiters (comma by default). If your tags legitimately contain commas, configure delimiters before users discover this in production.templates with raw string interpolation, and cap per-tag length so a single tag can't dominate the layout or a payload.bin/console debug:config <bundle-alias> for option defaults → debug:twig for the form theme → network tab for 404s on bundle assets → browser console for Tagify is not defined → then, and only then, read configureOptions.form_theme if you need layout changes, and treat src/Form/ as the specification rather than blog posts.How can I help you explore Laravel packages today?