Skip to content
Viames Marino edited this page Mar 26, 2026 · 3 revisions

Pair framework: Email

Pair\Html\FormControls\Email renders an <input type="email"> and adds a small server-side email check on top of the shared FormControl behavior.

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() is stricter than Text, but only in one specific case.

Current logic:

  • 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)

Example:

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

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

Important caveat

If the field is not required, the current server-side implementation does not reject an invalid email format by itself.

In practice:

  • required email fields get a real syntax check
  • optional email fields rely mostly on browser behavior unless you add your own server-side rule

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.
    ->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.

Notes

  • The HTML input type is email, but server-side syntax validation is triggered only by the current implementation when the field is required.
  • If an email must always be valid even when optional, add a custom validation step in the model/request/controller layer.
  • 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.

Clone this wiki locally