Skip to content
Viames Marino edited this page Jun 13, 2026 · 4 revisions

Pair framework: Email

Pair\Html\FormControls\Email renders an <input type="email"> and keeps the classic required-email check when no validation preset is active. For stronger reusable validation, use Form::emailAddress(...) or call preset(FormValidationPreset::EMAIL).

Rendered HTML:

<input type="email" ... />

Main methods

Email defines:

  • render(): string
  • validate(): bool

It also inherits the most useful text-like methods from FormControl:

  • required()
  • value()
  • minLength()
  • maxLength()
  • pattern()
  • placeholder()
  • label()
  • description()
  • class()
  • data()
  • validate()

Rendering behavior

render() simply delegates to the shared text-style renderer:

// Email reuses the generic input renderer with type="email".
return parent::renderInput('email');

So the control automatically supports the standard attributes and helpers already documented in FormControl.

Validation behavior

Email::validate() has two paths.

Without a validation preset:

  • it reads the submitted value with Post::get($this->name)
  • if the field is required, the value must pass FILTER_VALIDATE_EMAIL
  • after that, Pair runs the base FormControl validation (required, minLength, maxLength)

With a validation preset:

  • validation delegates to FormControl::validate()
  • the value is trimmed before validation
  • a non-empty optional email must still be valid
  • preset metadata is available to PairValidation.js

Example:

$email = (new \Pair\Html\FormControls\Email('email'))
    ->required()
    ->maxLength(190);

// Required email fields are checked with FILTER_VALIDATE_EMAIL.
$isValid = $email->validate();

Classic-path caveat

If the field is not required and no preset is configured, the classic server-side implementation does not reject an invalid email format by itself.

In practice:

  • required classic email fields get a real syntax check
  • optional classic email fields rely mostly on browser behavior unless you add your own server-side rule
  • preset-backed email fields reject non-empty invalid values even when optional

This matters for APIs, background imports, and any flow where browser validation can be bypassed.

Practical examples

1. Standard login or account email

$email = (new \Pair\Html\FormControls\Email('email'))
    // Treat this as a canonical account email.
    ->label('Email')
    ->required()
    ->placeholder('name@example.com')
    ->maxLength(190)
    ->class('form-control');

2. Optional backup email

$backup = (new \Pair\Html\FormControls\Email('backupEmail'))
    ->label('Backup email')
    // Keep the field optional in the UI.
    ->preset(\Pair\Html\FormValidationPreset::EMAIL)
    ->placeholder('optional@example.com')
    ->maxLength(190);

3. Domain-restricted email hint

$companyEmail = (new \Pair\Html\FormControls\Email('companyEmail'))
    ->label('Company email')
    // pattern adds an extra browser-side constraint on supported controls.
    ->pattern('^[^\\s@]+@example\\.com$')
    ->placeholder('name@example.com');

4. Edit form with preloaded value

$billingEmail = (new \Pair\Html\FormControls\Email('billingEmail'))
    ->label('Billing email')
    // Pair will render the current value in the input.
    ->value($customer->billingEmail)
    ->class(['form-control', 'js-email-field']);

Secondary methods worth knowing

  • pattern(...) Allowed on Email, useful for narrowing accepted domains or shapes.
  • inputmode(...) Inherited and supported because Email is not in the blocked list.
  • renderLabel() Useful when your form layout separates labels and controls.
  • preset(...) Enables shared email normalization, server-side preset validation, and PairValidation.js metadata.

Notes

  • The HTML input type is email, but the classic server-side syntax check is required-only unless a preset is active.
  • If an optional email must always be valid, prefer Form::emailAddress(...) or preset(FormValidationPreset::EMAIL).
  • Email remains a small extension of FormControl, so the rest of the shared behavior is the same as for Text.

See also: Text, Password, Url, FormControl, FormValidationPreset, PairValidation.js.

Clone this wiki locally