phil / forms-autosave
A form's input kept while it is filled, for Symfony: a form option and a Stimulus controller that keep the draft in the browser, restore it with a notice and forget it once the form is sent, and an optional store of drafts on the server, per user, encrypted, with conflicts between devices told
Package info
github.com/parler-haut-interagir-librement/forms-autosave
Type:symfony-bundle
pkg:composer/phil/forms-autosave
Requires
- php: >=8.5
- ext-mbstring: *
- ext-sodium: *
- psr/clock: ^1.0
- symfony/config: ^8.2
- symfony/dependency-injection: ^8.2
- symfony/form: ^8.2
- symfony/http-foundation: ^8.2
- symfony/http-kernel: ^8.2
- symfony/options-resolver: ^8.2
- symfony/service-contracts: ^3.6
- symfony/translation-contracts: ^3.6
Requires (Dev)
- ext-pdo: *
- doctrine/dbal: ^4.5
- doctrine/doctrine-bundle: ^3.3
- doctrine/orm: ^3.7
- doctrine/persistence: ^4.1
- phpunit/phpunit: ^13.4
- psr/log: ^3.0
- symfony/asset-mapper: ^8.2
- symfony/browser-kit: ^8.2
- symfony/clock: ^8.2
- symfony/console: ^8.2
- symfony/css-selector: ^8.2
- symfony/event-dispatcher: ^8.2
- symfony/framework-bundle: ^8.2
- symfony/key-management: ^8.2
- symfony/routing: ^8.2
- symfony/security-core: ^8.2
- symfony/security-csrf: ^8.2
- symfony/translation: ^8.2
- symfony/twig-bridge: ^8.2
- symfony/twig-bundle: ^8.2
- twig/twig: ^3.21
Suggests
- doctrine/dbal: For the server store of drafts, with doctrine/orm for its table
- phil/block-editor-bundle: For UJO (Universal JSON Output) fields kept in drafts, their editor mounted again on restore
- phil/ux-kit: For the AutosaveStatus recipe styled with phil-ux
- phil/ux-kit-shadcn: For the AutosaveStatus recipe styled with Tailwind
- symfony/asset-mapper: To serve the controller and its stylesheet without a build step
- symfony/console: For phil:forms-autosave:purge
- symfony/key-management: To seal the drafts kept on the server under a master key of a KMS
- symfony/routing: For the endpoints of the server store, and their URLs given to the controller
- symfony/security-core: To name the signed-in user of drafts
- symfony/security-csrf: To check the requests of the controller to the server store
- symfony/stimulus-bundle: For the autosave controller
- symfony/twig-bundle: For the status template
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-12 23:53:05 UTC
README
A form's input kept while it is filled: drafts in the browser, restored with a notice, and on the server when asked.
phil/forms-autosave keeps what a person types into a long form, so that a closed tab, a crash, an expired session or a slip of the back button does not lose it. Each change is saved as a draft once the typing stops, in the browser's local storage; when the form is shown again, the draft is put back with a notice that can discard it. Once the form is sent and valid, the draft is forgotten. Passwords, files, CSRF tokens, hidden fields and the fields an application marks sensitive are never kept.
It is for any Symfony application with forms that take time to fill: an application form, a long article, a
character sheet, a survey. One option turns it on, autosave: true. For signed-in users, the application can also
keep drafts on the server, so that a draft follows them to another device; the content is then sealed through
Symfony's KeyManagement component, and a draft saved meanwhile from another device or tab is told with a notice rather than
overwritten.
It is a Symfony bundle on the Form component, with a Stimulus controller served by AssetMapper, with no build step. A draft's key is a keyed hash of the form, its subject and its user: neither the browser's storage, the URLs nor the table tells whose draft it is or what it is about.
Status
| Part | State |
|---|---|
The option autosave: the key, the structure version, the settings and the labels on the form's tag; fields marked in or out |
Implemented and tested |
The autosave controller: drafts in local storage, debounced, restored with a notice, discarded, forgotten once sent |
Implemented; its modules and the controller tested under Node |
The status template, and the AutosaveStatus recipe of both PHIL UX kits |
Implemented and tested |
| The server store: drafts per user, by revision, sealed through Symfony's KeyManagement component, conflicts told, expired drafts purged | Implemented and tested, on SQLite |
| The endpoints: a stateless JSON API behind the controller's header and CSRF token | Implemented and tested |
UJO (Universal JSON Output) fields of phil/block-editor-bundle kept, their editor mounted again on restore |
Implemented and tested |
Documentation
| Document | What it covers |
|---|---|
| Installation | Requirements, enabling the bundle, the controller, the status, the server store. |
| Configuration | Every option of the bundle. |
| Forms | The option autosave, keys and subjects, the structure version, the fields kept and left out, submissions. |
| JavaScript | The controller, its values, its modules, its events, the notices and the live region. |
| The server store | Users, revisions and conflicts, encryption, expiry and the purge command. |
| Endpoints | Each route, its body, its answers, the controller's header and its CSRF token. |
| Exceptions | The bundle's exceptions, and the answers of its endpoints. |
| Extension points | What an application implements, configures, replaces or relies on. |
| Testing | The PHP and Node tests, the fuzz target and the mutation bar. |
| Reference | Every class and module of the bundle, with its role. |
Quick start
composer require phil/forms-autosave
$form = $this->createForm(ApplicationType::class, $application, ['autosave' => true]);
{{ form_start(form) }}
{{ include('@PhilFormsAutosave/status.html.twig') }}
{{ form_widget(form) }}
{{ form_end(form) }}
Requirements
PHP 8.5 or later with ext-mbstring and ext-sodium, Symfony 8.2, and Stimulus 3 in the browser. For the server
store: Doctrine DBAL 4 and ORM 3, the routing and CSRF components, a way to name the signed-in user — SecurityBundle
or a service of the application — and, unless encryption is turned off, symfony/key-management with a client and a
master key.
Contributing
Contributions are welcome on the PHIL monorepo: read the contribution guide and the code of conduct. Report a vulnerability privately, as the security policy explains, never in a public issue.
License
MIT, © Philippe Gamache, doing business as Le Gnome Archiviste; a Parler Haut Interagir Librement project. See LICENSE.