thrace/form-bundle
Thrace Form Bundle integrates the Thrace form library with Symfony, giving PHP developers a streamlined way to build, configure, and render forms using reusable components and bundle-level configuration.
The package is a Symfony bundle that ships form types backed by jQuery widgets — think date pickers, sliders, autocompletes, tag inputs — instead of raw HTML inputs. The bundle's job is usually twofold: register the form type in the DI container, and render markup/attributes that a jQuery plugin picks up client-side. That means you are wiring three things: a PHP form type, an HTML form theme, and a JS initializer.
Minimal steps:
composer require thrace/form-bundle
config/bundles.php; on legacy Symfony (2/3) add it to AppKernel::registerBundles(). Given the package age and low star count, verify the supported Symfony range in composer.json before assuming it installs cleanly.public/:
php bin/console assets:install --symlink
# legacy: php app/console assets:install web --symlink
use Thrace\FormBundle\Form\Type\DatePickerType; // confirm exact FQCN in README
$builder->add('startDate', DatePickerType::class, [
'label' => 'Starts on',
]);
Render the form normally. If the field renders as a plain text input, the type is working and the issue is client-side JS/asset loading. Confirm the type's namespace by browsing src/Form/Type/ in vendor/thrace/form-bundle before trusting any snippet.One type per behaviour. These bundles usually expose a small family of types (selector, slider, spinner, color picker, autocomplete). Treat each as a drop-in replacement for the plain Symfony type it wraps (TextType, ChoiceType, DateType, etc.) and keep using standard Symfony options — required, constraints, data — unchanged. The jQuery concerns live in options prefixed or namespaced by the bundle (e.g. a widget_options array passed straight through to the plugin init).
Pass widget config through form options, not templates. The cleanest pattern is to serialize the plugin config into a data-* attribute on the input from the form type's buildView, then have a single generic initializer read it:
// In a controller or base form, keep options declarative
$builder->add('tags', TagType::class, [
'widget_options' => ['allowNew' => true, 'maxItems' => 10],
]);
Do this instead of hardcoding options in Twig, so multiple instances of the same widget on one page stay independent.
Centralize JS initialization. Put one script in your layout that boots every widget by data attribute ($('[data-thrace-widget]').each(...)). Avoid inline <script> per field — it breaks when forms are rendered dynamically (collections, AJAX modals).
Collections and dynamic rows. For CollectionType, initialize widgets on collection:entry:added (Symfony's collection DOM events) rather than at page load, or the newly inserted row's input stays unwrapped. This is the single most common integration point.
Layout/theme integration. If the bundle provides a form theme, register it once:
twig:
form_themes:
- '@ThraceForm/form.html.twig'
and let the theme own the markup. If you override a block locally, extend the bundle's block rather than replacing it, so the data attributes the JS depends on survive.
Testing. Because these types render the same underlying input, functional tests with WebTestCase work as usual. Assert on the field name/value, not on widget markup; the JS behaviour itself is better covered by a browser test (Panther/Playwright) against one representative page.
assets:install output is not automatically bundled. Either import the bundle's files explicitly in app.js or copy them into assets/. Missing CSS is the usual reason a slider looks like a bare text box.composer.json for the symfony/form and symfony/framework-bundle constraints; on Symfony 6/7 you may need composer require --ignore-platform-reqs or a small shim. If the type's parent classes were renamed (AbstractType::getName() removal, configureOptions signatures), expect to patch or subclass.getName() for the type alias; newer Symfony prefers FQCN. If ->add('foo', 'thrace_datepicker') fails, use the class constant instead.data-locale attribute or a global JS var). Symfony's locale is not automatically forwarded to jQuery UI — set it in your base layout.DateTime constraint. Never trust client-side masking.data-* attribute present? If not, the PHP type/theme is the problem; (2) if present but no widget, run $('selector').data() in the console and confirm the plugin ($.fn.datepicker etc.) is defined; (3) bin/console debug:form lists registered types and their parents — quickest way to confirm the bundle registered.configureOptions/buildView rather than forking vendor code; override individual Twig form blocks in your app-level theme; and wrap initialization in your own JS module so swapping the bundle out later is a one-file change.How can I help you explore Laravel packages today?