Developing new Input Block Templates

Form Reform Developer provides a growing suite of resources to assist those developing blocks, handlers and more complex forms for Form Reform.

Inputs as Block Types

Each type of form control in Form Reform is implemented as a block type. By the time you read this you should already have seen the list of Form Reform Blocks.

If you need a specialized template for an existing input element, you can design new templates for form elements as you would any block type.

With that in mind, here we will look at the general structure of a Form Reform block view and provide guidance on new block templates.

For actual custom blocks, read this first then move on to Developing new Input Blocks.

To help focus our discussion, the below code is taken from the Text Input block.

        
if (empty($redact_block)) {
    ?>
    <div class="form-group form-reform-control <?php echo $block_state_classes; ?>">
        <?php
        
        View::element('/form_reform/blocks/view/label_details',
                      [
                          'controller'    => $controller,
                          'label_details' => $label_details,
                          'input_name'    => $input_name
                      ],
                      'jl_form_reform'
        );
        
        $args = [
            'form'  => h($controller->getFormName()),
            'class' => "form-reform-input form-control",
        ];
        if(!empty($validation_classes)){
            $args['class'] .= ' '.$validation_classes;
        }
        if (!empty($required_msg)) {
            $args['required'] = 'required';
            $args['class'] .= '  '.$required_input_classes;
        }
        if (!empty($placeholder)) {
            $args['placeholder'] = h($placeholder);
        }
        if (!empty($minlength)) {
            $args['minlength'] = h($minlength);
        }
        if (!empty($maxlength)) {
            $args['maxlength'] = h($maxlength);
        }
        if (!empty($validation_fail_message)) {
            $args['validationmessage'] = $text_abstractor->getPlainTextForDisplay($validation_fail_message);
        }

        View::element('/form_reform/blocks/view/prefix_suffix_before', ['controller' => $controller], 'jl_form_reform');
        echo $front_end_form->text($input_name, $controller->getStartingValue(), $args);
        View::element('/form_reform/blocks/view/prefix_suffix_after', ['controller' => $controller], 'jl_form_reform');
        ?>
    </div>
    <?php
}    

Adapting to your theme

The most likely reason for developing a new block template is to adapt a Form Reform block to your site theme.

The Form Reform default block templates are designed to work well with the default Atomik and Elemental themes, so should behave reasonably well with other Bootstrap 3,4,5 based themes with minimal if any further styling. They also work well with the Modena theme.

Prefixes and Suffixes

For non-bootstrap themes, one of the issues may be adding prefixes and suffixes to inputs. When installed, Form Reform configures some CSS to add Bootstrap style prefixes and suffixes to input elements for other themes. You can see this in /application/config at jl_form_reform.non_bootstrap_theme.form_prefix_suffix_css.

Form Reform automatically detects if a theme is not Bootstrap based and injects this styling into the page header. So before creating a whole suite of block templates for your theme, if your main issue is prefixes and suffixes, first consider adapting this CSS in the configuration data. You may not need any custom templates at all!

        
'non_bootstrap_theme' => [
    'form_prefix_suffix_css' => '.ccm-page .form-reform-control .input-group {
        display: flex;
        flex-wrap: wrap;
        align-items: stretch;
        width: 100%
    }
    .ccm-page .form-reform-control .input-group>.form-control,.input-group>.form-select {
        flex: 1 1 auto;
        width: 1%;
        min-width: 0
    }
    .ccm-page .form-reform-control .input-group-text {
        align-items: center;
        padding: .375rem .75rem;
        text-align: center;
        white-space: nowrap;
        background-color: #e9ecef;
        border: 1px solid #ced4da;
    }

    .ccm-page .form-reform-control .input-group>.input-group-text:first-child{
        margin-right:-1px;
    }
    .ccm-page .form-reform-control .input-group>.input-group-text:last-child{
        margin-left:-1px;
    }',
]    

Radio and Checkbox lists

Another theme specific styling requirement is for lists of Radio and Checkbox inputs. The default templates are specific to Bootstrap 5.

Bootstrap 5 is very opinionated about checkbox lists, so Form Reform also comes with alternate templates for Bootstrap 3. Bootstrap 3 is considerably more generic in the way it styles lists of inputs and these Bootstrap 3 alternate templates also work reasonably well with other themes such as Modena. If you need to develop a new template for a list of Checkbox or Radio inputs, the Bootstrap 3 alternate template may be a better starting point.

Required inputs

Form Reform also provides configuration strings for the classes associated with required inputs. 

  • jl_form_reform.required_inputs.form_group_classes - classes applied to the overall input group
  • jl_form_reform.required_inputs.label_classes - classes applied to the input label
  • jl_form_reform.required_inputs.input_classes - classes applied to the input element

These input values are provided with defaults, but you can edit those configuration values as suits your theme and design.

        
'required_inputs' => [
    'label_classes' => 'required text-muted small',
    'form_group_classes' => 'required',
    'input_classes' => 'required',
],    

The structure of a Form Reform block template

Most block templates for Form Reform follow a common structure. You can see the view for the Text Input block above and other inputs are similar to this.

We recommend sticking to this structure for your custom templates unless you have good reason to do otherwise.

Edit Mode marker

Very few form controls need an edit mode marker. This is generally for blocks that don't show anything visible like a hidden input, a honeypot or a captcha.

Rather than code an edit mode marker from scratch, we have an element you can use to display a marker. /form_reform/blocks/edit/edit_mode_marker.

In the arguments array, all uses of this marker require the block_name. If the marker has something additional to say, a second alert argument in the argument array will be shown as an alert within the marker.

        
$page = Page::getCurrentPage();
if (!is_object($page) || $page->isEditMode()) {
    View::element('/form_reform/blocks/edit/edit_mode_marker', 
        [
            'block_name' => t('My Block Name')
            'alert'      => t('Something important about this block')
        ], 
        'jl_form_reform'
    );
} elseif (empty($redact_block)) {
 // restof block view
}    

Redact Block test

All form input blocks that implement the Behaviour dialogue should enclose the rest of the form with a test on $redact_block. This is a secondary test for when a block is not rendered.

The main test is in an event handler in FormBlockController that should have already skipped rendering the view if a block is not rendered in a specific state.

The difference between the two mechanisms is that when redacted by the block controller, no theme grid wrapper or styles are output. When redacted by this test in the view.php, an empty theme grid wrapper will already have been generated by the page area.

Form Control wrapper

All form controls are wrapped in a <div> element with some standard classes and $block_state_classes.

These classes implement which form states a control is hidden in or disabled in, so work alongside the Redact options in the Behaviour tab.

Input Label

The label should only be output if a $label is entered in the edit dialogue. Alongside the label is the optional $required message. 

In most cases, the provided /form_reform/blocks/view/label_details element can be used.

$args

Next we set up the $args array of parameters for the form helper. The typical adjustments you may need to make here are to add theme specific classes and maybe some data parameters required by your own JavaScript.

The actual input element

Finally we come to the actual input element(s). Here we use a specially adapted form helper called $front_end_form, which is instantiated from the class JtF\FormReform\FormState\FrontEndForm.

This customized form helper wraps the core form helper with some specialized functionality to:

  • Associate input blocks with the form.
  • Manage the way inputs persist is association with the block Persistence tab.
  • Manage persistence of checkbox lists
  • Remove any ID elements 

If you need to select a form element in JavaScript, you should aim to select on classes and not an id="..." attribute.

If you really need an ID, the FormBlockController class provides and id() method to generate a unique ID that you can either add to the block wrapper or to a form element using the $args.

Prefix and Suffix

Some form elements also have a generic and optional Prefix and/or Suffix.

These are managed through the elements:        

  • /form_reform/blocks/view/prefix_suffix_before
  • /form_reform/blocks/view/prefix_suffix_after

These provide code that adapts conditionally to the settings for a prefix or suffix from the block edit dialogue and cover the conventions for Bootstrap 3,4,5 based themes.

As noted above, Form Reform also provides an injection of some compatible code into the page header for other themes, as set in /application/config at jl_form_reform.non_bootstrap_theme.form_prefix_suffix_css

Rendering Form Controls

In a block view template, always use $front_end_form to render form inputs as described above. If you render form elements any other way, you will loose much of the built in capabilities of Form Reform and will need to provide equivalent functionality in your own code.

Additional Pages

Reform the way you add new input controls

If you need a specialized template or a custom input element, you can design new templates  or new block types for form elements as you would any block type.

Blocks are easy for third party addition or extension. Block templates and are the first thing any Concrete CMS developer learns to code. They are one of the easiest things to code. The underlying mechanisms are well established and reliable.

Reform what you can do with form data

Form handlers are built about the same extensible plugin system as many of my other addons (Universal Content Puller, Omni Gallery, Extreme Clean ...).

The whole system is aimed at easy extension within Form Reform, by third party addons, by agencies and by site building developers.

Handlers can be easily added to do whatever you want with the form data.

Reform where you can save form data

Saving form data with Form Reform is simply a handler in the processing pipeline. You can save to multiple locations or just one location.

If you need to save data elsewhere, such as to a dedicated table, a table provided through another addon, to another database, send it to an API, forward it to another server, or anywhere you can imagine, you can adapt or develop a form handler to do so.

The complexity of the code depends on where you are saving or sending the data, but wrapping that into a form handler plugin for Form Reform is straight forward.

The Form Reform handler plugin system is designed for easy extension.

Form Reform

Reform the way forms are built. Build a form out of blocks. Take control of how form submissions are processed and how the submitted data is stored. Easy to extend. Easy to reconfigure. Tangible data. Easy to add your own integrations.

Form Reform Display

List and display form submissions from Form Reform.

Form Reform UTM

Not just Form Reform and not just UTM! Capture and hold incoming UTM (or other) tags and make the tag values available to Form Reform and/or Conditional Redirect as {{place_holders}}. You don't need Form Reform to use this.

Form Reform Dynamics

Form handlers for querying Microsoft Dynamics, forwarding and updating form data to Microsoft Dynamics.

Snapshot

A suite of advanced image capture and upload tools. Enhanced drag and drop file uploading. Make screengrabs from within Concrete CMS. Capture images directly from device webcams. Edit images before uploading.

Form Reform Attributes, Express and Users

Save submitted forms to Express objects and user attributes. Add and remove users from groups.

Form Reform Image Picker

Form Reform Image Picker provides an image picking input block for Form Reform. The Image Picker Input is preconfigured to connect to most Omni Gallery gallery and slider display widgets, the core gallery block, and thumbnail showing templates for the core page list block. Advanced settings allow the Image Picker Input to be configured to pick images from other galleries and sliders.

Form Reform Data Picker

Form Reform Data Picker provides data picking input blocks for Form Reform. The Table Picker Input is preconfigured to connect to Universal Content Puller table display widgets. Advanced settings allow the Table Picker Input to be configured to pick data from other HTML tables.

Form Reform Developer

A growing suite of resources to assist those developing blocks, handlers and more complex forms for Form Reform.

Learn with a simple form

While you may have plans to implement some much more complex forms using Form Reform, we strongly recommend you start with a simple form such as our contact form example in order to review the basic principles of using Form Reform before you move onto anything bigger.

  1. Start by submitting the form at Getting Started - Your First Form a few times, even making some deliberate mistakes.
  2. Watch our Getting Started with Form Reform video to see how the form is built.
  3. Read through the rest of Getting Started - Your First Form for more details of how this form is built.
  4. Create a test page on your site to build your own version of Getting Started - Your First Form and experiment.
  5. Develop your test page with some of the concepts introduced by our further examples and experiment with some of the other form inputs.