Air

Air::Form

This raku module is one of the core libraries of the raku Air distribution.

It provides a Form class that integrates Air with the Cro::WebApp::Form module to provide a simple,yet rich declarative abstraction for web forms.

Air::Form uses Air::Functional for the FormTag role so that Forms can be employed within Air code. Air::Form is an alternative to Air::Component.

SYNOPSIS

An Air::Form is declared as a regular raku Object Oriented (OO) class. Specifically form input fields are set up via public attributes of the class … has Str $.email and so on. Check out the primer on raku OO basics.

Form Declaration

use Air::Form;

class Contact does Form {
    has Str    $.first-names is validated(%va<names>);
    has Str    $.last-name   is validated(%va<name>)   is required;
    has Str    $.email       is validated(%va<email>)  is required is email;
    has Str    $.city        is validated(%va<text>);

    method form-routes {
        self.init;

        self.controller: -> Contact $form {
            if $form.is-valid {
                note "Got form data: $form.form-data()";
                self.finish: 'Contact info received!'
            }
            else {
                self.retry: $form
            }
        }
    }
}

my $contact-form = Contact.empty;

Declaration Class and Attributes:

Form Routes:

Essential Methods:

Several other Air::Form methods are described below.

Form Consumption

Forms can then be used in an Air application like this:

my $contact-form = Contact.empty;  #repeated from above

use Air::Functional :BASE;
use Air::Base;

# define custom page properties
my &index = &page.assuming(
    title       => 'hÅrc',
    description => 'HTMX, Air, Red, Cro',

    nav => nav(
        logo    => safe('<a href="/">h<b>&Aring;</b>rc</a>'),
        widgets => [lightdark],
    ),

    footer      => footer p ['Aloft on ', b 'åir'],
);

# use the $contact-form in an Air website
sub SITE is export {
    site :components[$contact-form],
        index
            main
                content [
                    h2 'Contact Form';
                    $contact-form;
                ];
}

Note:

DESCRIPTION

Air::Forms do the Cro::WebApp::Form role. Therefore many of the features are set out in tne Cro docs.

Form Controls

Re-exported from Cro::WebApp::Form, per the Cro docs

Traits are used to describe the kinds of controls that will be used on a form. The full set of HTML5 control types are available. Remember to check browser support for them is sufficient if needing to cater to older browsers. They mostly follow the HTML 5 control names, however in a few cases alternative names are offered for convenience. Taking care to use is email and is telephone is especially helpful for mobile users.

Labels, help texts, and placeholders

By default, the label for the control is formed by:

Taking the attribute name Replacing each - with a space Calling tclc to title case it

Use the is label('Name') trait in order to explicitly set a label.

For text inputs, one can also set a placeholder using the is placeholder(‘Text’) trait. This text is rendered in the textbox prior to the user filling it.

Finally, one may use the is help('...') trait in order to provide help text. This is displayed beneath the form field.

Validation

our %va = (
text     => ( /^ <[A..Za..z0..9\s.,_#-]>+ $/,
              'In text, only ".,_-#" punctuation characters are allowed' ),
name     => ( /^ <[A..Za..z.'-]>+ $/,
              'In a name, only ".-\'" punctuation characters are allowed' ),
names     => ( /^ <[A..Za..z\s.'-]>+ $/,
               'In names, only ".-\'" punctuation characters are allowed' ),
words    => ( /^ <[A..Za..z\s]>+ $/,
              'In words, only text characters are allowed' ),
notes    => ( /^ <[A..Za..z0..9\s.,:;_#!?()%$£-]>+ $/,
              'In notes, only ".,:;_-#!?()%$£" punctuation characters are allowed' ),
postcode => ( /^ <[A..Za..z0..9\s]>+ $/,
              'In postcode, only alphanumeric characters are allowed' ),
url      => ( /^ <[a..z0..9:/.-]>+ $/,
              'Only valid urls are allowed' ),
tel      => ( /^ <[0..9+()\s#-]>+ $/,
              'Only valid tels are allowed' ),
email    => ( /^ <[a..zA..Z0..9._%+-]>+ '@' <[a..zA..Z0..9.-]>+ '.' <[a..zA..Z]> ** 2..6 $/,
              'Only valid email addresses are allowed' ),
password => ( ( /^ <[A..Za..z0..9!@#$%^&*()\-_=+{}\[\]|:;"'<>,.?/]> ** 8..* $/ & / <[A..Za..z]> / & /<[0..9]> /),
              'Passwords must have minimum 8 characters with at least one letter and one number.' ),
);

role Form does Cro::WebApp::Form does FormTag {}

This role has only private attrs to avoid creating form fields, get/set methods are provided instead.

The %!form-attrs are the same as Cro::WebApp::Form.

Air::Form currently supports these attrs:

Here is an example of customizing the submit button text (ie place this method in your Contact form (or whatever you choose to call it).

method do-form-attrs{
    self.form-attrs: {:submit-button-text('Save Contact Info')}
}

Air::Form code should avoid direct manipulation of the method and class styles detailed at Cro docs - instead override the method styles {}.

has Str $!form-base

optionally specify form url base (with get/set methods)

method form-name

method form-name() returns Mu

get url safe name of class doing Form role

method form-url

method form-url() returns Str

get url (ie base/name)

has Associative %!form-attrs

optional form attrs (with get/set methods)

method HTML

method HTML() returns Air::Functional::Markup(Any)

called when used as a FormTag, returns self.empty

method HTML

method HTML(
    Form $form
) returns Air::Functional::Markup(Any)

when passed a $form field set, returns populated form

method retry

method retry(
    Form $form
) returns Mu

return partially complete form

method finish

method finish(
    Str $msg
) returns Mu

return message (typically used when self.is-valis

method form-styles

method form-styles() returns Mu

get form-styles (may be overridden)

method form-scripts

method form-scripts(
    $suffix = "*"
) returns Mu

get form-scripts, pass in a custom $suffix for required labels (may be overridden)

AUTHOR

Steve Roe librasteve@furnival.net

COPYRIGHT AND LICENSE

Copyright(c) 2025 Henley Cloud Consulting Ltd.

This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.