Skip to content

Build type-safe, dynamic forms in Blazor with an elegant fluent API. FormCraft simplifies complex form creation with automatic field rendering, validation, and dependency management. Features include customizable field renderers, async validation, conditional visibility, and seamless MudBlazor integration.

License

Notifications You must be signed in to change notification settings

phmatray/FormCraft

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

FormCraft 🎨

NuGet Version NuGet Downloads MudBlazor Version Build Status License Stars

Build type-safe, dynamic forms in Blazor with ease ✨

Get Started β€’ Live Demo β€’ Documentation β€’ Examples β€’ Contributing


🌐 Live Demo

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

πŸŽ‰ What's New in v2.5.0

FormCraft v2.5.0 introduces powerful attribute-based form generation and more:

🏷️ Attribute-Based Form Generation (NEW!)

  • 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()

πŸ”’ Security Features (v2.0.0)

  • 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

πŸ“¦ Modular Architecture

  • Separate UI framework packages - Use only what you need
  • FormCraft.ForMudBlazor - MudBlazor implementation package
  • Improved extensibility - Easier to add custom UI frameworks

πŸš€ Other Improvements

  • Enhanced performance with optimized rendering
  • Better type safety with improved generic constraints
  • Comprehensive documentation with live examples
  • 550+ unit tests ensuring reliability

πŸš€ Why FormCraft?

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.

✨ Key Features

  • πŸ”’ 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

πŸ“¦ Installation

FormCraft Core

dotnet add package FormCraft

FormCraft for MudBlazor

dotnet add package FormCraft.ForMudBlazor

Note: FormCraft.ForMudBlazor includes FormCraft as a dependency, so you only need to install the MudBlazor package if you're using MudBlazor components.

🎯 Quick Start

1. Register Services

// Program.cs
builder.Services.AddFormCraft();

2. Create Your Model

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; }
}

3. Build Your Form

@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")
    };
}

🏷️ Attribute-Based Forms (NEW!)

Define your forms directly on your model with attributes - no configuration code needed!

Define Your Model with Attributes

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; }
}

Generate the Form with One Line

var formConfig = FormBuilder<UserRegistration>.Create()
    .AddFieldsFromAttributes()  // That's it! πŸŽ‰
    .Build();

Available Attribute Types

  • [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!

Comparison: Fluent API vs Attributes

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();

🎨 Examples

Dynamic Field Dependencies

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();

Custom Validation

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")

Multiple Layouts

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)

Advanced Field Types

// 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 file

πŸ› οΈ Advanced Features

Conditional Fields

Show/hide fields based on conditions:

.AddField(x => x.CompanyName)
    .VisibleWhen(model => model.UserType == UserType.Business)
    
.AddField(x => x.TaxId)
    .RequiredWhen(model => model.Country == "US")

Field Groups

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();

Security Features (v2.0.0+)

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();

Custom Field Renderers

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

πŸ“Š Performance

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)

πŸ§ͺ Testing

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

🀝 Contributing

We love contributions! Please see our Contributing Guide for details.

Quick Start for Contributors

# 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

πŸ“– Documentation

πŸ“š Complete Documentation - Interactive docs with live examples

πŸ—ΊοΈ Roadmap

βœ… Completed

  • File upload field type
  • Security features (encryption, CSRF, rate limiting, audit logging)
  • Modular UI framework architecture

🚧 In Progress

  • Import/Export forms as JSON
  • Rich text editor field

πŸ“‹ Planned

  • 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

πŸ’¬ Community

πŸ“„ License

FormCraft is licensed under the MIT License.

πŸ™ Acknowledgments

  • 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

About

Build type-safe, dynamic forms in Blazor with an elegant fluent API. FormCraft simplifies complex form creation with automatic field rendering, validation, and dependency management. Features include customizable field renderers, async validation, conditional visibility, and seamless MudBlazor integration.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •