Templates in DataForm component
4 Nov 202524 minutes to read
The DataForm component supports templating to customize either a specific field editor or the entire form layout and validation experience.
Customization of specific field editor
Customize an individual field editor using the Template RenderFragment inside a FormItem. This enables full control over the rendering, styling, and behavior of a single editor while retaining DataForm features such as validation and labels.
@using Syncfusion.Blazor.DataForm
@using System.ComponentModel.DataAnnotations
@using Syncfusion.Blazor.Inputs
@using Syncfusion.Blazor.Calendars
<SfDataForm ID="MyForm"
Model="@CreditCardModel"
Width="50%">
<FormValidator>
<DataAnnotationsValidator></DataAnnotationsValidator>
</FormValidator>
<FormItems>
<FormItem Field="@nameof(CreditCardModel.Name)" Placeholder="e.g. Andrew Fuller" LabelText="Name on card" ></FormItem>
<FormItem Field="@nameof(CreditCardModel.CardNumber)" LabelText="Card Number" >
</FormItem>
<FormItem Field="@nameof(CreditCardModel.CVV)">
<Template>
<label class="e-form-label">CVV*:</label>
<SfMaskedTextBox Mask="000" @bind-Value="CreditCardModel.CVV" ></SfMaskedTextBox>
</Template>
</FormItem>
<FormItem Field="@nameof(CreditCardModel.ExpiryDate)">
<Template>
<label class="e-form-label">Expiry Date*:</label>
<SfDatePicker TValue="DateTime?" Format="MM/yy" EnableMask="true"></SfDatePicker>
</Template>
</FormItem>
</FormItems>
</SfDataForm>
@code {
public char PromptCharacter { get; set; } = ' ';
public class CreditCard
{
[Required(ErrorMessage = "Please enter the name on card")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter the card number")]
[CreditCard]
public string CardNumber { get; set; }
[Required(ErrorMessage = "Please enter cvv number")]
public string CVV { get; set; }
[Required(ErrorMessage = "Please select/enter expiry date")]
public DateTime? ExpiryDate { get; set; }
}
private CreditCard CreditCardModel = new CreditCard();
}
The above Template approach can also be used alongside FormAutoGenerateItems to auto-generate all items except those explicitly customized with a FormItem template.
Customization of entire form
The DataForm supports customizing the entire form structure using a full-form template. This allows arranging editors, labels, buttons, and validation messages as required and customizing the appearance and text of validation errors.
@using System.ComponentModel;
@using System.ComponentModel.DataAnnotations
@using Syncfusion.Blazor.DataForm
@using Syncfusion.Blazor.Buttons
@using Syncfusion.Blazor.Inputs
@using Syncfusion.Blazor.Calendars
@using Syncfusion.Blazor.DropDowns
@using Syncfusion.Blazor.Navigations
<div class="form-section">
<SfDataForm ID="MyForm"
Model="ProductDetailsModel"
Width="50%"
ButtonsAlignment="FormButtonsAlignment.Center">
<FormValidator>
<DataAnnotationsValidator></DataAnnotationsValidator>
</FormValidator>
<FormTemplate>
<SfAccordion ExpandMode="ExpandMode.Single">
<AccordionItems>
<AccordionItem Expanded="true">
<HeaderTemplate>Product Info</HeaderTemplate>
<ContentTemplate>
<div class="product-details">
<div class="form-group">
<label class="e-form-label">Category</label>
<SfTextBox @bind-Value="ProductDetailsModel.Category" Readonly="true" />
</div>
<div class="form-group">
<label class="e-form-label">Brand</label>
<SfDropDownList TValue="string" TItem="string" DataSource="BrandData" @bind-Value="ProductDetailsModel.Brand">
</SfDropDownList>
<ValidationMessage For="()=>(ProductDetailsModel.Brand)"></ValidationMessage>
</div>
<div class="form-group">
<label class="e-form-label">Color</label>
<SfDropDownList TValue="string" TItem="string" DataSource="Colors" @bind-Value="ProductDetailsModel.Color"></SfDropDownList>
<ValidationMessage For="()=>(ProductDetailsModel.Color)"></ValidationMessage>
</div>
<div class="form-group">
<label class="e-form-label">Size</label>
<SfDropDownList TValue="string" TItem="string" DataSource="SizeData" @bind-Value="ProductDetailsModel.Size"></SfDropDownList>
<ValidationMessage For="()=>(ProductDetailsModel.Size)"></ValidationMessage>
</div>
</div>
</ContentTemplate>
</AccordionItem>
<AccordionItem Expanded="false">
<HeaderTemplate>Payment Details</HeaderTemplate>
<ContentTemplate>
<div class="payment-info">
<div class="form-group">
<label class="e-form-label">Contact Number</label>
<SfMaskedTextBox Mask="+(00) 0000000000" Placeholder="eg. +12 1234567890" @bind-Value="ProductDetailsModel.ContactNumber" />
<ValidationMessage For="()=>(ProductDetailsModel.ContactNumber)"></ValidationMessage>
</div>
<div class="form-group">
<label class="e-form-label">Shipping Address</label>
<SfTextBox Multiline="true" @bind-Value="ProductDetailsModel.ShippingAddress" />
<ValidationMessage For="()=>(ProductDetailsModel.ShippingAddress)"></ValidationMessage>
</div>
<div class="form-group">
<label class="e-form-label">Delivery Instructions (Optional)</label>
<SfTextBox Multiline="true" @bind-Value="ProductDetailsModel.DeliveryInstructions" Placeholder="Landmark , alternate contact number etc.. " />
</div>
</div>
</ContentTemplate>
</AccordionItem>
</AccordionItems>
</SfAccordion>
</FormTemplate>
<FormButtons>
<SfButton>Buy now</SfButton>
</FormButtons>
</SfDataForm>
</div>
@code {
public string[] BrandData = new string[] { "Adidas", "Puma", "Reebok", "Nike", "Skechers", "Vans" };
public string[] Colors = new string[] { "Black", "Grey", "White", "Red", "Beige", "Pink", "Off-White" };
public string[] SizeData = new string[] { "6UK", "7UK", "8UK", "9UK", "10UK", "11UK" };
private ProductDetails ProductDetailsModel = new ProductDetails()
{
Category = "Shoes - Men",
Color = "Black",
Size = "6UK"
};
}public class ProductDetails
{
public string Category { get; set; }
[Required(ErrorMessage = "Please choose the brand.")]
public string Brand { get; set; }
[Required(ErrorMessage = "Please enter the color.")]
public string Color { get; set; }
[Required(ErrorMessage = "Please enter the size.")]
public string Size { get; set; }
[Required(ErrorMessage = "Please enter the shipping address.")]
public string ShippingAddress { get; set; }
public string BillingAddress { get; set; }
public string DeliveryInstructions { get; set; }
[Required(ErrorMessage = "Please enter your contact number.")]
public string ContactNumber { get; set; }
}<style>
.control-wrapper {
max-width: 400px;
margin: 0 auto;
padding: 0px 0px 0px;
}
.control-header {
text-align: center;
}
.form-group {
margin-bottom: 1em;
}
.form-section {
margin-top: 20x;
}
.sf-icon-shopping-cart_01-:before {
content: "\e710";
}
.sf-icon-check:before {
content: "\e715";
}
@@font-face {
font-family: 'Default';
src: url(data:application/x-font-ttf;charset=utf-8;base64,AAEAAAAKAIAAAwAgT1MvMj1vSgcAAAEoAAAAVmNtYXCDeIPaAAABmAAAAF5nbHlmEwr+pwAAAggAAAjQaGVhZCYp2+EAAADQAAAANmhoZWEIUQQHAAAArAAAACRobXR4GAAAAAAAAYAAAAAYbG9jYQhUBlAAAAH4AAAADm1heHABFgErAAABCAAAACBuYW1luF5THQAACtgAAAIlcG9zdJ8LuoMAAA0AAAAAbwABAAAEAAAAAFwEAAAAAAAD9AABAAAAAAAAAAAAAAAAAAAABgABAAAAAQAArxT6wV8PPPUACwQAAAAAAOGLy6UAAAAA4YvLpQAAAAAD9AOaAAAACAACAAAAAAAAAAEAAAAGAR8ABgAAAAAAAgAAAAoACgAAAP8AAAAAAAAAAQQAAZAABQAAAokCzAAAAI8CiQLMAAAB6wAyAQgAAAIABQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUGZFZABA5wLnFQQAAAAAXAQAAAAAAAABAAAAAAAABAAAAAQAAAAEAAAABAAAAAQAAAAEAAAAAAAAAgAAAAMAAAAUAAMAAQAAABQABABKAAAADAAIAAIABOcC5wbnCOcQ5xX//wAA5wLnBucI5xDnFf//AAAAAAAAAAAAAAABAAwADAAMAAwADAAAAAEABAACAAMABQAAAAAAAAEQAiwC3AQkBGgAAAAFAAAAAAP0A18APwB/AIkAxgDrAAABHw8/Dy8OKwEPDQUfDz8PLw4rAQ8NAR8FFSM1JxEfBz8OOwEfDjM/BzUnIw8GATM/Dx8PMxEhAq8BAQIEBAUFBwYICAgJCQoKCgkKCAkIBwcHBQUEAwMBAQEBAwMEBQUHBwcICQgKCQoKCgkJCAgIBgcFBQQEAgH+CwEBAgQEBQUHBggICAkJCgoKCQoICQgHBwcFBQQDAwEBAQEDAwQFBQcHBwgJCAoJCgoKCQkICAgGBwUFBAQCAQJ8AwUIWAwD3n0BAwMGBgYICAMEBQYHBwkJCgsLDA0NDQ4ODQ4MDAwLCgkJCAYGBQMDKAgIBwYFBAECvLsICAYHBQMD/beAAwQFBQcHCAkKCgsLDA0MDg0NDQwLCwsJCQkHBwUFAwKE/eMBAQoJCQkJCAcHBgYFBAMDAQEBAQMDBAUGBgcHCAkJCQkKCgoJCQgICAcGBgQFAwICAgIDBAUFBgcHCAkJCQoLCgkJCQkIBwcGBgUEAwMBAQEBAwMEBQYGBwcICQkJCQoKCgkJCAgIBwYGBAUDAgICAgMEBQUGBwcICQkJCgGuAQIGehYJBKYp/l0ICAcGBQQCAQ0NDQwLCgoJCAgGBQUDAgIDBQUGCAgJCgoLDA0NDQECBAUGBwQI1foBAgQFBgcH/iwNDAwLCwoJCQgHBgUEAwEBAQEDBAUGBwgJCQoLCwwMDQJJAAAABgAAAAAD8wOWAAYAQgBaAGwArQDuAAABBzcfAwUhLwIHIy8PNS8CKwIPHQEHLwEjDwE1LwMjNz0BJzcfBTcfAg8BLwY3OwEfAQcVHw8/Dy8PDw4BFR8PPw8vDw8OAxEWBgEDAgb8/wNuBAUEDQsVFBQTEhEPDw0GCwoIBgQCFhITE+wQDw8PDg4ODg0NDQwNCwwKCwoKCQgJBwcHBgYEBQMEA5FrBAQDBAMBAwMDBgIDagIEBgYGBxwCAwIBFQYGBAgFBgIWAgQHCPcBAgQGBggKCgsMDQ4PDxAQEBAPDw4NDAsLCQgGBgQCAQECBAYGCAkLCwwNDg8PEBAQEA8PDg0MCwoKCAYGBAL+KgEEBQgKCw0PEBETFBQWFxcXFhYUFBMREQ4NDAkIBgMBAQMGCAkMDQ4RERMUFBYWFxcXFhQUExEQDw0LCggFBAEXBhcFBAMDrxYWDQEBAwUHCAsMDQ4IERESFBQUFQQDAgECAgMEBAUGBgYIBwgJCQoKCwsLDAwMDQ0ODQ4PDgEZawIBAQIGBQMCAQQDBgZqBgoHBQMDMAMHBwMWAQICBQYKChYCBlwICBAPDw4NDAsLCQgGBgQCAQECBAYGCAkLCwwNDg8PEBAQEA8PDg0MCwoKCAYGAwMBAQMDBgYICgoLDA0ODw8QATMLDBYVFRQSERAPDQsKCAUEAQEEBQgKCw0PEBESFBUVFhcXFxYVFBISEA8NCwoIBQQBAQQFCAoLDQ8QEhIUFRYXAAAAAAQAAAAAA/QDRwA/AH8AhwCRAAABFR8OPw49AS8NKwEPDQUVHw4/Dj0BLw0rAQ8NEwcTIRMnMSMhMxMhNSEDBzUhA0YBAgMEBAQGBQcGBwgICAgICAgIBwYHBQYEBAQDAgEBAgMEBAQGBQcGBwgICAgICAgIBwYHBQYEBAQDAgH+aAICAgQEBAYFBwYIBwgICAgICAgHBgcFBgQEBAMCAQECAwQEBAYFBwYHCAgICAgICAcIBgcFBgQEBAICAsH6jAFKjPpu/Z3NwgJZ/dzDAf8AAQkICAgHBwcGBgUFBAQCAgEBAQECAgQEBQUGBgcHBwgICAkIBwgHBwYGBQUEAwMCAQECAwMEBQUGBgcHCAcICQgICAcHBwYGBQUEBAICAQEBAQICBAQFBQYGBwcHCAgICQgHCAcHBgYFBQQDAwIBAQIDAwQFBQYGBwcIBwgB+wH+vQFABP5dOgGkAQEAAAADAAAAAANkA5oAnQDxAR4AAAEzHwEdAR8HFQ8DIy8HDwYdAR8WDw0dAQ8BKwIvAT0BLwc9AT8COwEfBj8HLxc/DTU/AwEfDjsBPxEvFiMPFR8BEw8CFR8HMz8HNS8GIw8ELwQrAQ8BAgoCAgENDAwKCggHBQEBAikCAgIEAwQFDA0SBwcGAgIBAQICBgcHBxYKCQkJCAcHBgUFBAMCAQEBAQIDAwQFBQYGBwcPEQECAhUCAQINDAsLCQgHBQICKQICAgQDBAULDhIHBwYCAQEBAQEBAgYHBwcWCgkKCAgHBwYFBQQDAgEBAQECAwMEBAYFBgcHEBABAQED/qwUFRUVFRYWFhYWFxYXFhcXFxcWFxYXFhYWFhYVFRUVFAQCAQICBAUGCAgJCgsLDA0MDQ0NDBk2EQYGqgYGCEsZDQ0NDA0MCwsKCQgIBgUEAgIBAqQCAQEBAwkRNRIHBqADChI1DQoFAgEBAgMEBAoMEw8eTw4IVxkXCwkJBwYCOAIBAiIDAwUGBwgJCgICAQENAQEFAwIDAgECAgMFAwMEBAUDBAMFAwIBAQECAwMEBAUGBgYHCAgICQgHBwcGBgYFBQQEBAYDIgICAQECAiICBAUGBwgJCQMBAgEMAQUDAwIDAQICBAQDBAQEBAQEAwQEAgEBAQICBAMFBQUGBwcICAgJBwgHBgcGBgUFBAQEBQQiAgEBAf6RDAsLCQkICAYGBQUDAwIBAQIDAwUFBgYICAkJCwsMKSckIiAeGxoYFhQTERAPDQwLCgkIDxsJBQUFBQQnEAkKCwwNDxARExQWGBobHiAiJCcCoAMDAwQECA8XPRcKCgUPFz0REAkIBAMDAwMCAQICAwcYAwEaBwQBAgIAAAEAAAAAA/MDNAA0AAABDwQvAw8EHwQ/ETUnIw8LAYsEJwwGAgIwXmMXFBIICCsqKaEqRUclJSYnJykpKiosLC4GFgsCAWMhISIiIiIjIkJAPRwB8AQmCQMBARQuNgsMDgcIJCYnmyZOTycmJiYlJSQjIiIgHwULCAMCAQ4RERITFBUVKy0tFgAAABIA3gABAAAAAAAAAAEAAAABAAAAAAABAAcAAQABAAAAAAACAAcACAABAAAAAAADAAcADwABAAAAAAAEAAcAFgABAAAAAAAFAAsAHQABAAAAAAAGAAcAKAABAAAAAAAKACwALwABAAAAAAALABIAWwADAAEECQAAAAIAbQADAAEECQABAA4AbwADAAEECQACAA4AfQADAAEECQADAA4AiwADAAEECQAEAA4AmQADAAEECQAFABYApwADAAEECQAGAA4AvQADAAEECQAKAFgAywADAAEECQALACQBIyBEZWZhdWx0UmVndWxhckRlZmF1bHREZWZhdWx0VmVyc2lvbiAxLjBEZWZhdWx0Rm9udCBnZW5lcmF0ZWQgdXNpbmcgU3luY2Z1c2lvbiBNZXRybyBTdHVkaW93d3cuc3luY2Z1c2lvbi5jb20AIABEAGUAZgBhAHUAbAB0AFIAZQBnAHUAbABhAHIARABlAGYAYQB1AGwAdABEAGUAZgBhAHUAbAB0AFYAZQByAHMAaQBvAG4AIAAxAC4AMABEAGUAZgBhAHUAbAB0AEYAbwBuAHQAIABnAGUAbgBlAHIAYQB0AGUAZAAgAHUAcwBpAG4AZwAgAFMAeQBuAGMAZgB1AHMAaQBvAG4AIABNAGUAdAByAG8AIABTAHQAdQBkAGkAbwB3AHcAdwAuAHMAeQBuAGMAZgB1AHMAaQBvAG4ALgBjAG8AbQAAAAACAAAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYBAgEDAQQBBQEGAQcADXRyYW5zcG9ydC12YW4LdXNlci1tb2RpZnkRc2hvcHBpbmctY2FydF8wMS0Lc3BlbmQtbW9uZXkFY2hlY2sAAAA=) format('truetype');
font-weight: normal;
font-style: normal;
}
[class^="sf-icon-"], [class*=" sf-icon-"] {
font-family: 'Default' !important;
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: inherit;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
</style>
The FormTemplate renderer can also be integrated together with FormItem elements, as shown in the following example.
@using Syncfusion.Blazor.DataForm
@using System.ComponentModel.DataAnnotations
<SfDataForm Width="50%"
Model="@RegistrationDetailsModel">
<FormValidator>
<DataAnnotationsValidator></DataAnnotationsValidator>
</FormValidator>
<FormItems>
<FormItem Field="@nameof(RegistrationDetailsModel.Name)"></FormItem>
</FormItems>
<FormTemplate>
@* Insert your template layout code here to incorporate additional editor components corresponding to their respective fields *@
</FormTemplate>
</SfDataForm>
@code {
public class RegistrationDetails
{
[Required(ErrorMessage = "Please enter your name")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter your email address")]
[EmailAddress(ErrorMessage = "Please enter valid email address")]
public string Email { get; set; }
}
private RegistrationDetails RegistrationDetailsModel = new RegistrationDetails();
}Tooltip validation message with template
When using the Template renderer, validation messages can be displayed using a tooltip component. Assign an ID to the custom editor that matches the form item’s ID so that validation messages can be targeted correctly.
@using Syncfusion.Blazor.DataForm
@using System.ComponentModel.DataAnnotations
@using Syncfusion.Blazor.Inputs
@using Syncfusion.Blazor.Calendars
<SfDataForm ID="MyForm"
Model="@CreditCardModel"
ValidationDisplayMode="FormValidationDisplay.Tooltip">
<FormValidator>
<DataAnnotationsValidator></DataAnnotationsValidator>
</FormValidator>
<FormItems>
<FormItem Field="@nameof(CreditCardModel.Name)" Placeholder="e.g. Andrew Fuller" LabelText="Name on card"></FormItem>
<FormItem Field="@nameof(CreditCardModel.CardNumber)" LabelText="Card Number">
</FormItem>
<FormItem Field="@nameof(CreditCardModel.CVV)" ID="CVV">
<Template>
<label class="e-form-label">CVV*:</label>
<SfMaskedTextBox Mask="000" @bind-Value="CreditCardModel.CVV" ID="CVV"></SfMaskedTextBox>
</Template>
</FormItem>
<FormItem Field="@nameof(CreditCardModel.ExpiryDate)" ID="ExpiryDate">
<Template>
<label class="e-form-label">Expiry Date*:</label>
<SfDatePicker TValue="DateTime?" Format="MM/yy" EnableMask="true" ID="ExpiryDate"></SfDatePicker>
</Template>
</FormItem>
</FormItems>
</SfDataForm>
@code {
public char PromptCharacter { get; set; } = ' ';
private CreditCard CreditCardModel = new CreditCard();
}public class CreditCard
{
[Required(ErrorMessage = "Please enter the name on card")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter the card number")]
[CreditCard]
public string CardNumber { get; set; }
[Required(ErrorMessage = "Please enter cvv number")]
public string CVV { get; set; }
[Required(ErrorMessage = "Please select/enter expiry date")]
public DateTime? ExpiryDate { get; set; }
}
Validation summary
Use the ValidationSummary tag to display a consolidated list of validation messages. It must be placed within the FormValidator tag to function correctly. The example below demonstrates its usage.
@using Syncfusion.Blazor.DataForm
@using System.ComponentModel.DataAnnotations
@using Syncfusion.Blazor.Inputs
@using Syncfusion.Blazor.Calendars
<SfDataForm ID="MyForm"
Model="@CreditCardModel"
ValidationDisplayMode="FormValidationDisplay.Tooltip">
<FormValidator>
<DataAnnotationsValidator></DataAnnotationsValidator>
<ValidationSummary></ValidationSummary>
</FormValidator>
<FormItems>
<FormItem Field="@nameof(CreditCardModel.Name)" Placeholder="e.g. Andrew Fuller" LabelText="Name on card"></FormItem>
<FormItem Field="@nameof(CreditCardModel.CardNumber)" LabelText="Card Number">
</FormItem>
<FormItem Field="@nameof(CreditCardModel.CVV)" ID="CVV">
<Template>
<label class="e-form-label">CVV*:</label>
<SfMaskedTextBox Mask="000" @bind-Value="CreditCardModel.CVV" ID="CVV"></SfMaskedTextBox>
</Template>
</FormItem>
<FormItem Field="@nameof(CreditCardModel.ExpiryDate)" ID="ExpiryDate">
<Template>
<label class="e-form-label">Expiry Date*:</label>
<SfDatePicker TValue="DateTime?" Format="MM/yy" EnableMask="true" ID="ExpiryDate"></SfDatePicker>
</Template>
</FormItem>
</FormItems>
</SfDataForm>
@code {
public char PromptCharacter { get; set; } = ' ';
private CreditCard CreditCardModel = new CreditCard();
}public class CreditCard
{
[Required(ErrorMessage = "Please enter the name on card")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter the card number")]
[CreditCard]
public string CardNumber { get; set; }
[Required(ErrorMessage = "Please enter cvv number")]
public string CVV { get; set; }
[Required(ErrorMessage = "Please select/enter expiry date")]
public DateTime? ExpiryDate { get; set; }
}