DEV Community 👩‍💻👨‍💻

Cover image for Umbraco Forms - Add additional attributes to existing field types
Andy Boot
Andy Boot

Posted on

Umbraco Forms - Add additional attributes to existing field types

We've all been there; the website designers introduce additional elements or layout which the off the shelf tools simply cannot cater for.

Recently I encountered this issue for building what I originally thought was a simple contact form with a relatively straightforward layout. Here's a similar mock-up of the design I was provided:

Mock-up

The main contact form on the right looks somewhat straightforward enough which Umbraco Forms can easily accommodate for, right?

Let's get started with a first draft of the form configuration:
Umbraco Forms First Draft Form

As you can see, I've managed to create the 2 groups for the 'Your details' and 'Enquiry type' areas. Each area appears to be set within a 2-column grid layout, so I've configured it like so. So far so good, but here's my problem... how on Earth do I allow fields such as 'Company Name' to span across both grid columns?

Well, as far as I can initially tell there's no clear-cut way of doing this, given you can only define the column layout on the group and not on a per row basis. Each column is just a container where each field stacks upon one another. Perhaps in future versions we'll see an expansion of this so groups are able to create rows, and each row creates the columns.

So, plan B. Scrap two columns in our group containers at HTML level, but instead add each field on a single column basis and use CSS to structure the layout (1 or 2 columns). However, we also need a mechanism to tell each field how many columns it should span.

The Umbraco Forms API allows us to extend the original implementation of field types to perform additional duties such as custom field validation, alternative views or more importantly adding our own attributes!

As our 'Company Name' field is basic textbox (AKA 'Short Answer'), we'll focus our efforts on adapting this, and if it works apply it to other related field types afterwards.

First we'll create a new C# class, inherit from Umbraco.Forms.Core.Providers.FieldTypes.Textfield, add a new checkbox attribute named 'Span all columns?' and leave as is.

namespace MyProject.UmbracoForms.CustomFieldTypes
{
    public class Textfield : Umbraco.Forms.Core.Providers.FieldTypes.Textfield
    {
        [Umbraco.Forms.Core.Attributes.Setting("Span all columns?",
        Description = "Allows the field to span across both columns in the layout.",
        View = "Checkbox")]
        public string SpanAllColumns { get; set; } = string.Empty;

        public Textfield()
        {
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

We also need a composer to register this inherited class to tell Umbraco Forms to use our custom field type instead of the default one:

namespace MyProject.UmbracoForms.Composers
{
    public class UmbracoFormsCustomProvidersComposer : IComposer
    {
        public void Compose(IUmbracoBuilder builder)
        {
            builder.FormsFields().Add<Textfield>();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

If we build our project and refresh the browser, we can now see our freshly added checkbox toggle against each of our 'Short Answer' fields:

Newly added attribute

Finally, with our new attribute in place we can now instruct the HTML output to add a CSS class to one of the <div> elements which wraps our field type.

Using the 'default' Umbraco Forms theme as an example, I've modified the Form.cshtml file with the following changes:

@foreach (FieldViewModel f in c.Fields)
{
    bool hidden = f.HasCondition && f.ConditionActionType == FieldConditionActionType.Show;

    // REFERENCE 1
    bool spanAllColumns = f.AdditionalSettings.ContainsKey("SpanAllColumns") ? f.AdditionalSettings["SpanAllColumns"] == "True" : false;
    int fieldTypeCols = spanAllColumns ? 12 : 6;

    // REFERENCE 2
    <div class="col-md-@fieldTypeCols @Html.GetFormFieldWrapperClass(f.FieldTypeName) @f.CssClass" @{ if (hidden) { <text> style="display: none" </text>  } }>

        @if (!f.HideLabel)
        {
            <label for="@f.Id" class="umbraco-forms-label">
                @f.Caption @if (f.ShowIndicator)
                {
                    <span class="umbraco-forms-indicator">@Model.Indicator</span>
                }
            </label>
        }

        @if (!string.IsNullOrEmpty(f.ToolTip))
        {
            <span class="umbraco-forms-tooltip help-block">@f.ToolTip</span>
        }

        <div class="umbraco-forms-field-wrapper">

            @await Html.PartialAsync(FormThemeResolver.GetFieldView(Model, f), f)

            @if (Model.ShowFieldValidaton)
            {
                @Html.ValidationMessage(f.Id)
            }

        </div>

    </div>
}
Enter fullscreen mode Exit fullscreen mode

Please locate REFERENCE 1 and REFERENCE 2 in the code above.

  • REFERENCE 1 - Added a boolean variable named spanAllColumns to retrieve our new field type value (if exists). Also added an integer variable named fieldTypeCols to set the number of columns to either 6 or 12 based on our preference.
  • REFERENCE 2 - Added col-md-@fieldTypeCols to the class property of the <div> element.

The intended output after all this is something like this:
Rendered page with intended layout

The 'Company Name' field now spans both columns thanks to it using all 12 Bootstrap 3 grid columns instead of the default 6. Now all that's left to do is to replicate our changes for the Textarea field type exactly the same as we did for the Textfield and the core basics are done.


Thank you for taking the time to read this article. Hopefully this helps somebody in their quest to perform the same task, or something similar.

If this article has helped you in any way, or would like to provide any constructive feedback please drop me a comment below.

Top comments (0)

👋 Have You Posted on DEV Yet?

Head over to our Welcome Thread and tell us a bit about yourself!