simp / multiform
This is php library for build multi steps forms from assoc array
Requires
None
Requires (Dev)
- phpunit/phpunit: ^13.4
- rector/rector: ^2.8
- symfony/var-dumper: ^8.1
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is not auto-updated.
Last update: 2026-10-30 12:23:32 UTC
README
A PHP library for building and rendering HTML forms, including multi-step form flows with application-controlled state storage and built-in visual presets.
Requirements
- PHP
- Composer
Installation
Install the package with Composer:
composer require simp/multiform
If you are working from a local checkout, install its dependencies and load Composer's autoloader:
composer install
require __DIR__ . '/vendor/autoload.php';
Build a basic form
Create field objects, configure them, add them to a Form, and provide a
renderer when creating the HTML:
use Simp\Multiform\lib\field\Email; use Simp\Multiform\lib\field\Submit; use Simp\Multiform\lib\field\Text; use Simp\Multiform\lib\form\Form; use Simp\Multiform\lib\Helper; $name = new Text(); $name->setLabel('Name'); $name->setHtmlId('name'); $name->setRequired(true); $email = new Email(); $email->setLabel('Email'); $email->setHtmlId('email'); $email->setRequired(true); $submit = new Submit(); $submit->setValue('Send'); $form = new Form(); $form->setMethod('post'); $form->addField($name); $form->addField($email); $form->addField($submit); echo $form->create($_POST, static function ($field): string { return Helper::renderField($field, $_POST); });
Helper::renderField() is the default renderer for built-in fields. Use
Helper::escape() when inserting submitted values or other untrusted text into
your own HTML. The library renders fields; your application remains responsible
for validating submitted data on the server.
Fields and attributes
The Simp\Multiform\lib\field namespace includes classes for the standard HTML
input types:
Button, Checkbox, Color, Date, DateTimeLocal, Email, File,
Hidden, Image, Month, Number, Password, Radio, Range, Reset,
Search, Submit, Tel, Text, Time, Url, and Week.
Additional element fields include Textarea, Select, MultiSelect, Option,
Fieldset, Datalist, Output, Progress, and Meter.
Fields share configuration methods such as setLabel(), setValue(),
setDefault(), setRequired(), setHtmlId(), setHtmlClass(),
setPlaceholder(), setDisabled(), setReadonly(), and setAttribute().
Use setList() for select choices and datalist suggestions. For example:
use Simp\Multiform\lib\field\Select; $country = new Select(); $country->setLabel('Country'); $country->setList([ 'mw' => 'Malawi', 'zm' => 'Zambia', ]);
See examples/input-types.php and
examples/selection-controls.php for more
field examples.
Form state
FormState can keep submitted values, validation errors, a submitted flag, and
application-specific state together. It does not impose validation rules:
use Simp\Multiform\lib\form\FormState; $state = new FormState(); if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') { $state->setSubmittedValues($_POST); $email = $state->getValue('email'); if (!is_string($email) || filter_var($email, FILTER_VALIDATE_EMAIL) === false) { $state->addError('email', 'Enter a valid email address.'); } }
Read values with getValue()/getValues() and errors with getErrors() or
getAllErrors(). Validate according to your application's requirements.
Multi-step forms
MultiStepFormWrapper needs a FormStateSessionStore. Implement the interface
using the storage mechanism appropriate for your application. This example
uses the PHP session:
use Simp\Multiform\lib\field\Email; use Simp\Multiform\lib\field\Text; use Simp\Multiform\lib\wrapper\FormStateSessionStore; use Simp\Multiform\lib\wrapper\MultiStepFormStyles; use Simp\Multiform\lib\wrapper\MultiStepFormWrapper; if (session_status() !== PHP_SESSION_ACTIVE && !session_start()) { throw new RuntimeException('Unable to start the PHP session.'); } $store = new class implements FormStateSessionStore { public function load(string $key): array { return $_SESSION['multiform'][$key] ?? []; } public function save(string $key, array $values): void { $_SESSION['multiform'][$key] = $values; } public function clear(string $key): void { unset($_SESSION['multiform'][$key]); } }; $name = new Text(); $name->setLabel('Name'); $email = new Email(); $email->setLabel('Email'); $wizard = new MultiStepFormWrapper( $store, new MultiStepFormStyles('numbered-stepper') ); $wizard->addStep('About you', [$name]); $wizard->addStep('Contact', [$email]); $flowKey = 'registration'; $completedValues = null; if (($_SERVER['REQUEST_METHOD'] ?? 'GET') === 'POST') { $wizard->processSubmission($flowKey, $_POST); if ($wizard->isComplete($flowKey)) { $completedValues = $wizard->getValues($flowKey); $wizard->clear($flowKey); } } if ($completedValues !== null) { // Validate and process $completedValues for your application. echo 'Thank you, ' . \Simp\Multiform\lib\Helper::escape($completedValues['text'] ?? '') . '.'; } else { echo $wizard->render($flowKey, $wizard->getCurrentStep($flowKey)); }
Call processSubmission() for each POST request. It saves submitted values and
updates the active step. The final step's Submit button marks the flow complete;
read values with getValues() and clear saved state with clear() when
appropriate. The wrapper's internal state keys are excluded from getValues().
The wrapper supports back, next, finish, and goto:N navigation actions.
Jump navigation is limited to previously visited steps. Browser-side required
field checks are not a substitute for server-side validation.
Style presets
Pass one of these names to MultiStepFormStyles:
| Preset | Description |
|---|---|
plain |
Basic layout with library class names |
bootstrap |
Bootstrap-oriented utility classes; load Bootstrap CSS in your page |
tailwind |
Tailwind utility classes; load Tailwind CSS in your page |
numbered-stepper |
Horizontal numbered progress stepper |
one-thing-at-a-time |
Focused, conversational presentation |
vertical-sidebar |
Vertical progress sidebar |
icon-grid-cards |
Icon-based step cards |
The four visual presets include responsive CSS in the rendered form. The
Bootstrap and Tailwind presets rely on the corresponding framework CSS being
loaded by your application. Customize class slots with set():
$styles = (new MultiStepFormStyles('plain')) ->set('form', 'contact-wizard') ->set('next', 'button button--primary');
Examples
Runnable examples are in examples/:
basic-form.php— form fields, state, and application-level validationinput-types.php— input controlsselection-controls.php— options, selects, and datalistsgrouped-elements.php— grouped fieldscustom-renderer.php— custom field markupfile-upload.php— file input configurationmulti-step-form.php— multi-step form flowmulti-step-style-plain.phpand the othermulti-step-style-*.phpfiles — one style preset per example
Run an example through a PHP-enabled web server. The multi-step examples use PHP session storage and must be requested through a server that preserves the session cookie between requests.
Development
Run the PHPUnit suite:
./vendor/bin/phpunit
Run Rector in dry-run mode or apply its configured refactors:
composer rector:check composer rector
Rector is configured in rector.php. PHPUnit discovers tests in
tests/ using phpunit.xml.