diff --git a/531Calculator/Components/MyValidationMessage.cs b/531Calculator/Components/MyValidationMessage.cs
new file mode 100644
index 0000000..22e0a2b
--- /dev/null
+++ b/531Calculator/Components/MyValidationMessage.cs
@@ -0,0 +1,106 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Forms;
+using Microsoft.AspNetCore.Components.Rendering;
+
+namespace FiveThreeOneCalculator.Components
+{
+ ///
+ /// Displays a list of validation messages for a specified field within a cascaded .
+ ///
+ public class MyValidationMessage : ComponentBase, IDisposable
+ {
+ private EditContext? _previousEditContext;
+ private Expression>? _previousFieldAccessor;
+ private readonly EventHandler? _validationStateChangedHandler;
+ private FieldIdentifier _fieldIdentifier;
+
+ ///
+ /// Gets or sets a collection of additional attributes that will be applied to the created div element.
+ ///
+ [Parameter(CaptureUnmatchedValues = true)] public IReadOnlyDictionary? AdditionalAttributes { get; set; }
+
+ [CascadingParameter] EditContext CurrentEditContext { get; set; } = default!;
+
+ ///
+ /// Specifies the field for which validation messages should be displayed.
+ ///
+ [Parameter] public Expression>? For { get; set; }
+
+ /// `
+ /// Constructs an instance of .
+ ///
+ public MyValidationMessage()
+ {
+ _validationStateChangedHandler = (sender, eventArgs) => StateHasChanged();
+ }
+
+ ///
+ protected override void OnParametersSet()
+ {
+ if (CurrentEditContext == null)
+ {
+ throw new InvalidOperationException($"{GetType()} requires a cascading parameter " +
+ $"of type {nameof(EditContext)}. For example, you can use {GetType()} inside " +
+ $"an {nameof(EditForm)}.");
+ }
+
+ if (For == null) // Not possible except if you manually specify T
+ {
+ throw new InvalidOperationException($"{GetType()} requires a value for the " +
+ $"{nameof(For)} parameter.");
+ }
+ else if (For != _previousFieldAccessor)
+ {
+ _fieldIdentifier = FieldIdentifier.Create(For);
+ _previousFieldAccessor = For;
+ }
+
+ if (CurrentEditContext != _previousEditContext)
+ {
+ DetachValidationStateChangedListener();
+ CurrentEditContext.OnValidationStateChanged += _validationStateChangedHandler;
+ _previousEditContext = CurrentEditContext;
+ }
+ }
+
+ ///
+ protected override void BuildRenderTree(RenderTreeBuilder builder)
+ {
+ var l = CurrentEditContext.GetValidationMessages().ToArray();
+ foreach (var message in CurrentEditContext.GetValidationMessages(_fieldIdentifier))
+ {
+ builder.OpenElement(0, "div");
+ builder.AddMultipleAttributes(1, AdditionalAttributes);
+ builder.AddAttribute(2, "class", "validation-message");
+ builder.AddContent(3, message);
+ builder.CloseElement();
+ }
+ }
+
+ ///
+ /// Called to dispose this instance.
+ ///
+ /// if called within .
+ protected virtual void Dispose(bool disposing)
+ {
+ }
+
+ void IDisposable.Dispose()
+ {
+ DetachValidationStateChangedListener();
+ Dispose(disposing: true);
+ }
+
+ private void DetachValidationStateChangedListener()
+ {
+ if (_previousEditContext != null)
+ {
+ _previousEditContext.OnValidationStateChanged -= _validationStateChangedHandler;
+ }
+ }
+ }
+}