Build type-safe, dynamic forms in Blazor with ease β¨
Get Started β’ Live Demo β’ Documentation β’ Examples β’ Contributing
Experience FormCraft in action! Visit our interactive demo to see:
- π― Various form layouts and configurations
- π Dynamic field dependencies
- β¨ Custom field renderers
- π€ File upload capabilities
- π¨ Real-time form generation
FormCraft v2.5.0 introduces powerful attribute-based form generation and more:
- Zero-configuration forms - Generate complete forms from model attributes
- Rich attribute library - TextField, EmailField, NumberField, DateField, SelectField, CheckboxField, TextArea
- Automatic validation - Integrates with DataAnnotations attributes
- One-line setup - Just call
.AddFieldsFromAttributes()
- Field-level encryption for sensitive data protection
- CSRF protection with built-in anti-forgery tokens
- Rate limiting to prevent form spam
- Audit logging to track all form interactions
- Separate UI framework packages - Use only what you need
- FormCraft.ForMudBlazor - MudBlazor implementation package
- Improved extensibility - Easier to add custom UI frameworks
- Enhanced performance with optimized rendering
- Better type safety with improved generic constraints
- Comprehensive documentation with live examples
- 550+ unit tests ensuring reliability
FormCraft revolutionizes form building in Blazor applications by providing a fluent, type-safe API that makes complex forms simple. Say goodbye to repetitive form markup and hello to elegant, maintainable code.
- π Type-Safe - Full IntelliSense support with compile-time validation
- π― Fluent API - Intuitive method chaining for readable form configuration
- π·οΈ Attribute-Based Forms - Generate forms from model attributes with zero configuration
- π¨ MudBlazor Integration - Beautiful Material Design components out of the box
- π Dynamic Forms - Create forms that adapt based on user input
- β Advanced Validation - Built-in, custom, and async validators
- π Field Dependencies - Link fields together with reactive updates
- π Flexible Layouts - Multiple layout options to fit your design
- π High Performance - Optimized rendering with minimal overhead
- π§ͺ Fully Tested - 550+ unit tests ensuring reliability
FormCraft stands out among Blazor form solutions with its type-safe fluent API, automatic field rendering, and built-in field dependency management. See how it compares to Blazor EditForm, Blazored.FluentValidation, and MudBlazor Forms:
| Capability | EditForm | MudBlazor Forms | FormCraft |
|---|---|---|---|
| Fluent API configuration | - | - | Yes |
| Automatic field rendering | - | - | Yes |
| Built-in field dependencies | Manual | Manual | Yes |
| Conditional visibility | Manual | Manual | Built-in |
| Field-level encryption | - | - | Yes |
| Attribute-based generation | - | - | Yes |
View the full comparison β includes detailed feature matrix, code examples, and guidance on when to use each solution.
dotnet add package FormCraftdotnet add package FormCraft.ForMudBlazorNote: FormCraft.ForMudBlazor includes FormCraft as a dependency, so you only need to install the MudBlazor package if you're using MudBlazor components.
// Program.cs builder.Services.AddFormCraft();public class UserRegistration { public string FirstName { get; set; } public string LastName { get; set; } public string Email { get; set; } public int Age { get; set; } public string Country { get; set; } public bool AcceptTerms { get; set; } }@page "/register" @using FormCraft @using FormCraft.ForMudBlazor <h3>User Registration</h3> <FormCraftComponent TModel="UserRegistration" Model="@model" Configuration="@formConfig" OnValidSubmit="@HandleSubmit" ShowSubmitButton="true" /> @code { private UserRegistration model = new(); private IFormConfiguration<UserRegistration> formConfig; protected override void OnInitialized() { formConfig = FormBuilder<UserRegistration>.Create() .AddRequiredTextField(x => x.FirstName, "First Name") .AddRequiredTextField(x => x.LastName, "Last Name") .AddEmailField(x => x.Email) .AddNumericField(x => x.Age, "Age", min: 18, max: 120) .AddSelectField(x => x.Country, "Country", GetCountries()) .AddCheckboxField(x => x.AcceptTerms, "I accept the terms and conditions") .IsRequired("You must accept the terms") .Build(); } private async Task HandleSubmit(UserRegistration model) { // Handle form submission await UserService.RegisterAsync(model); } private List<SelectOption<string>> GetCountries() => new() { new("us", "United States"), new("uk", "United Kingdom"), new("ca", "Canada"), new("au", "Australia") }; }Define your forms directly on your model with attributes - no configuration code needed!
public class UserRegistration { [TextField("First Name", "Enter your first name")] [Required(ErrorMessage = "First name is required")] [MinLength(2)] public string FirstName { get; set; } = string.Empty; [TextField("Last Name", "Enter your last name")] [Required(ErrorMessage = "Last name is required")] public string LastName { get; set; } = string.Empty; [EmailField("Email Address")] [Required] public string Email { get; set; } = string.Empty; [NumberField("Age", "Your age")] [Range(18, 120, ErrorMessage = "Age must be between 18 and 120")] public int Age { get; set; } [DateField("Date of Birth")] public DateTime BirthDate { get; set; } [SelectField("Country", "United States", "Canada", "United Kingdom", "Australia")] public string Country { get; set; } = string.Empty; [TextArea("Bio", "Tell us about yourself")] [MaxLength(500)] public string Bio { get; set; } = string.Empty; [CheckboxField("Newsletter", "Subscribe to our newsletter")] public bool SubscribeToNewsletter { get; set; } }var formConfig = FormBuilder<UserRegistration>.Create() .AddFieldsFromAttributes() // That's it! π .Build();[TextField]- Standard text input[EmailField]- Email input with validation[NumberField]- Numeric input with min/max support[DateField]- Date picker with constraints[SelectField]- Dropdown with predefined options[CheckboxField]- Boolean checkbox[TextArea]- Multiline text input
All attributes work seamlessly with standard DataAnnotations validators like [Required], [MinLength], [MaxLength], [Range], and more!
| Fluent API | Attribute-Based |
|---|---|
var config = FormBuilder<User>.Create() .AddField(x => x.Name, field => field .WithLabel("Full Name") .WithPlaceholder("Enter name") .Required("Name is required") .WithMinLength(2)) .AddField(x => x.Email, field => field .WithLabel("Email") .WithInputType("email") .Required()) .Build(); | public class User { [TextField("Full Name", "Enter name")] [Required(ErrorMessage = "Name is required")] [MinLength(2)] public string Name { get; set; } [EmailField("Email")] [Required] public string Email { get; set; } } // One line to generate! var config = FormBuilder<User>.Create() .AddFieldsFromAttributes() .Build(); |
Create forms where fields react to each other:
var formConfig = FormBuilder<OrderForm>.Create() .AddSelectField(x => x.ProductType, "Product Type", productOptions) .AddSelectField(x => x.ProductModel, "Model", dependsOn: x => x.ProductType, optionsProvider: (productType) => GetModelsForType(productType)) .AddNumericField(x => x.Quantity, "Quantity", min: 1) .AddField(x => x.TotalPrice, "Total Price") .IsReadOnly() .DependsOn(x => x.ProductModel, x => x.Quantity) .WithValueProvider((model, _) => CalculatePrice(model)) .Build();Add complex validation logic with ease:
.AddField(x => x.Username) .WithValidator(new CustomValidator<User, string>( username => !forbiddenUsernames.Contains(username.ToLower()), "This username is not available")) .WithAsyncValidator(async (username, services) => { var userService = services.GetRequiredService<IUserService>(); return await userService.IsUsernameAvailableAsync(username); }, "Username is already taken")Choose the layout that fits your design:
// Vertical Layout (default) .WithLayout(FormLayout.Vertical) // Horizontal Layout .WithLayout(FormLayout.Horizontal) // Grid Layout .WithLayout(FormLayout.Grid, columns: 2) // Inline Layout .WithLayout(FormLayout.Inline)// Password field with confirmation .AddPasswordField(x => x.Password, "Password") .WithHelpText("Must be at least 8 characters") .AddPasswordField(x => x.ConfirmPassword, "Confirm Password") .MustMatch(x => x.Password, "Passwords do not match") // Date picker with constraints .AddDateField(x => x.BirthDate, "Date of Birth") .WithMaxDate(DateTime.Today.AddYears(-18)) .WithHelpText("Must be 18 or older") // Multi-line text with character limit .AddTextAreaField(x => x.Description, "Description", rows: 5) .WithMaxLength(500) .WithHelpText("Maximum 500 characters") // File upload .AddFileUploadField(x => x.Resume, "Upload Resume", acceptedFileTypes: new[] { ".pdf", ".doc", ".docx" }, maxFileSize: 5 * 1024 * 1024) // 5MB // Multiple file upload .AddMultipleFileUploadField(x => x.Documents, "Upload Documents", maxFiles: 3, acceptedFileTypes: new[] { ".pdf", ".jpg", ".png" }, maxFileSize: 10 * 1024 * 1024) // 10MB per fileShow/hide fields based on conditions:
.AddField(x => x.CompanyName) .VisibleWhen(model => model.UserType == UserType.Business) .AddField(x => x.TaxId) .RequiredWhen(model => model.Country == "US")Organize related fields into groups with customizable layouts:
var formConfig = FormBuilder<UserModel> .Create() .AddFieldGroup(group => group .WithGroupName("Personal Information") .WithColumns(2) // Two-column layout .ShowInCard(2) // Show in card with elevation 2 .AddField(x => x.FirstName, field => field .WithLabel("First Name") .Required()) .AddField(x => x.LastName, field => field .WithLabel("Last Name") .Required()) .AddField(x => x.DateOfBirth)) .AddFieldGroup(group => group .WithGroupName("Contact Information") .WithColumns(3) // Three-column layout .ShowInCard() // Default elevation 1 .AddField(x => x.Email) .AddField(x => x.Phone) .AddField(x => x.Address)) .Build();Protect your forms with built-in security features:
var formConfig = FormBuilder<SecureForm>.Create() .WithSecurity(security => security .EncryptField(x => x.SSN) // Encrypt sensitive fields .EncryptField(x => x.CreditCard) .EnableCsrfProtection() // Enable anti-forgery tokens .WithRateLimit(5, TimeSpan.FromMinutes(1)) // Max 5 submissions per minute .EnableAuditLogging()) // Log all form interactions .AddField(x => x.SSN, field => field .WithLabel("Social Security Number") .WithMask("000-00-0000")) .AddField(x => x.CreditCard, field => field .WithLabel("Credit Card") .WithMask("0000 0000 0000 0000")) .Build();Create specialized input controls for specific field types:
// Create a custom renderer public class ColorPickerRenderer : CustomFieldRendererBase<string> { public override RenderFragment Render(IFieldRenderContext context) { return builder => { var value = GetValue(context) ?? "#000000"; builder.OpenElement(0, "input"); builder.AddAttribute(1, "type", "color"); builder.AddAttribute(2, "value", value); builder.AddAttribute(3, "onchange", EventCallback.Factory.CreateBinder<string>( this, async (newValue) => await SetValue(context, newValue), value)); builder.CloseElement(); }; } } // Use in your form configuration .AddField(x => x.Color, field => field .WithLabel("Product Color") .WithCustomRenderer<ProductModel, string, ColorPickerRenderer>() .WithHelpText("Select the primary color")) // Register custom renderers (optional for DI) services.AddScoped<ColorPickerRenderer>(); services.AddScoped<RatingRenderer>();Built-in example renderers:
- ColorPickerRenderer - Visual color selection with hex input
- RatingRenderer - Star-based rating control using MudBlazor
FormCraft is designed for optimal performance:
- β‘ Minimal re-renders using field-level change detection
- π― Targeted validation execution
- π Efficient dependency tracking
- π¦ Small bundle size (~50KB gzipped)
FormCraft is extensively tested with over 400 unit tests covering:
- β All field types and renderers
- β Validation scenarios
- β Field dependencies
- β Edge cases and error handling
- β Integration scenarios
We love contributions! Please see our Contributing Guide for details.
# Clone the repository git clone https://github.com/phmatray/FormCraft.git # Build the project dotnet build # Run tests dotnet test # Create a local NuGet package ./pack-local.sh # or pack-local.ps1 on Windowsπ Complete Documentation - Interactive docs with live examples
- File upload field type
- Security features (encryption, CSRF, rate limiting, audit logging)
- Modular UI framework architecture
- Import/Export forms as JSON
- Rich text editor field
- Wizard/stepper forms
- Drag-and-drop form builder UI
- Form templates library
- Localization support
- More layout options
- Integration with popular CSS frameworks
- Form state persistence
- Discussions: GitHub Discussions
- Issues: GitHub Issues
- Twitter: @phmatray
FormCraft is licensed under the MIT License.
- MudBlazor for the amazing component library
- FluentValidation for validation inspiration
- The Blazor community for feedback and support
If you find FormCraft useful, please consider giving it a β on GitHub!
Made with β€οΈ by phmatray