nowo-tech/form-kit-bundle

Symfony bundle to reduce repetitive form field options: convention-based labels/placeholder/help (form_snake.field_snake.*), configurable attr/row_attr/translation_domain, and cascading option merge (global → field type → form → field). Symfony 7.4|8.

Maintainers

Package info

github.com/nowo-tech/FormKitBundle

Type:symfony-bundle

pkg:composer/nowo-tech/form-kit-bundle

Transparency log

Fund package maintenance!

HecFranco

Statistics

Installs: 259

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 5

v2.0.19 2026-07-29 10:49 UTC

README

CI Packagist Version Packagist Downloads License PHP Symfony GitHub stars Coverage

Found this useful? Install from Packagist and give the repo a star on GitHub.

Symfony bundle to reduce repetitive form field options: convention-based translation keys (form_snake.field_snake.label, .placeholder, .help), configurable defaults and multiple profiles via YAML, and cascading option merge (global → field type → form → field).

Minimum requirements: PHP 8.2 and Symfony 7.4. Also compatible with Symfony 8.0 and 8.1 (require PHP 8.4+).

FrankenPHP Friendly Worker Mode

This bundle is FrankenPHP worker mode friendly.

Features

  • Usage strategies: Options (FormOptionsTrait + FQCN), Kit (FormKitTrait / FormKitAbstractType + snake_case), Controller (FormKitControllerTrait), Wrapped (AbstractFormKitWrappedType). See Usage — strategies.
  • Convention-based labels, placeholder and help: Default translation keys are {form_snake}.{field_snake}.label, .placeholder, .help. Set any to false in field options to disable.
  • Multiple profiles: Define named profiles (e.g. default, bootstrap) with translation_domain, defaults.attr, defaults.row_attr, by_form, and per-field-type options. Choose the active profile per form via #[FormKitConfig('bootstrap')] or setFormKitConfigName() (named-config technique).
  • Cascading merge: Options are merged in order: profile defaults → field type → by_form → field options. Explicit field options override.
  • Options strategy helpers: addText(), addEmail(), … Prefer withBuilder($builder, …) + addTextField() (bound-builder). Or array-build with buildFormFromArray().
  • Choice presets: addSelect(), addMultiSelect(), addChoiceRadios(), addChoiceCheckboxes(), plus addMultiSelectSelectAll() when nowo-tech/select-all-choice-bundle is installed (optional Composer suggest).
  • FQCN helpers: addAutocompleteField() for Symfony UX Autocomplete types, addCKEditorField() when friendsofsymfony/ckeditor-bundle is installed; addDropzone() / addCropper() when the UX packages are installed.
  • Model transformers: addSwitchType(), addJsonType(), addBoolType(), addMoneyType(), addCsvType() (same helpers on FormKitControllerTrait with *Type suffix).
  • Optional types: FormTypeMap includes core Symfony types plus optional UX (Dropzone, Cropper) and A2lix when installed. Extend via type_map.
  • Form type extensions: InputGroupExtension, RequiredLabelSuffixExtension, HelpModalExtension. See Configuration and Usage.

Installation

composer require nowo-tech/form-kit-bundle

With Flex, the recipe creates config/packages/nowo_form_kit.yaml. Otherwise register the bundle in config/bundles.php and add the config file manually. See docs/INSTALLATION.md.

Quick usage (Options strategy)

  1. Configure (optional) — edit config/packages/nowo_form_kit.yaml: set default_profile, profiles (each with alias, translation_domain, defaults, field_types), and optionally type_map for custom or UX types.
  2. Register your form as a service and inject FormOptionsMerger:
# config/services.yaml
App\Form\UserProfileType:
  tags: ['form.type']
  calls:
    - setFormOptionsMerger: ['@Nowo\FormKitBundle\Form\FormOptionsMerger']
  1. Use FormOptionsTrait (bound-builder or array-build):
use Nowo\FormKitBundle\Form\FormOptionsTrait;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class UserProfileType extends AbstractType
{
  use FormOptionsTrait;

  public function buildForm(FormBuilderInterface $builder, array $options): void
  {
    $this->withBuilder($builder, function (): void {
      $this->addTextField('full_name');
      $this->addEmailField('email_address');
    });
    // Or: $this->buildFormFromArray($builder, ['full_name' => TextType::class, 'email_address' => EmailType::class]);
  }
}
  1. Add translations for keys like user_profile.full_name.label, user_profile.full_name.placeholder, user_profile.full_name.help in your translation domain.

Demos

The bundle includes a Symfony 8 demo that runs with FrankenPHP (Caddy + PHP in Docker). Runtime mode is controlled by FRANKENPHP_MODE in the demo .env (default worker; set classic for per-request PHP / easier hot-reload). Change the value and recreate the container (docker compose up -d) — no image rebuild. See docs/DEMO-FRANKENPHP.md. The demo has:

  • Locale in the URL — routes are under /{locale}/… (en, es, fr, de); / redirects to the default locale.
  • FormType example (contact, buildFormFromArray), help modal sample (help-modal.js + assets:install; include @NowoFormKitBundle/help_modal/shells.html.twig for overridable modal shells).
  • Form built in the controller (FormKitControllerTrait / FormOptionsMerger::resolve()).
  • Search, example, Dropzone, Cropper, translations (A2lix), nested, data transformers, choice fields, conditional fields (incl. Live Component), Kit API patterns (snake_case FormKitAbstractType + named config), Nowo special fields (OTP, phone, password, icon selector, Tiptap, CKEditor 5 — see demo/README.md), CKEditor (FOSCKEditorBundle), UX Autocomplete, multi-step wizard.

Run a demo via Docker/Make from the bundle root; see demo/README.md and docs/CONTRIBUTING.md.

For CSS frameworks, see docs/USAGE.md for ready-to-use configuration examples for Bootstrap 5 and Tailwind CSS.

Documentation

Developer-facing docs and comments (Markdown, PHPDoc, JSDoc) are English only; see Contributing — Language policy.

Additional documentation

Tests and coverage

  • Tests: PHPUnit (PHP), Vitest (TypeScript)
  • PHP: 99.4%
  • TS/JS: 100%
  • Python: N/A

License

MIT. See LICENSE.