diff --git a/src/Components/Blazor/Templates/src/content/BlazorHosted-CSharp/BlazorHosted-CSharp.Client/_ViewImports.cshtml b/src/Components/Blazor/Templates/src/content/BlazorHosted-CSharp/BlazorHosted-CSharp.Client/_ViewImports.cshtml index 6c4eae0fe4..087fc85bad 100644 --- a/src/Components/Blazor/Templates/src/content/BlazorHosted-CSharp/BlazorHosted-CSharp.Client/_ViewImports.cshtml +++ b/src/Components/Blazor/Templates/src/content/BlazorHosted-CSharp/BlazorHosted-CSharp.Client/_ViewImports.cshtml @@ -1,4 +1,5 @@ @using System.Net.Http +@using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Layouts @using Microsoft.AspNetCore.Components.Routing @using Microsoft.JSInterop diff --git a/src/Components/Blazor/Templates/src/content/BlazorHosted-CSharp/BlazorHosted-CSharp.Client/wwwroot/css/site.css b/src/Components/Blazor/Templates/src/content/BlazorHosted-CSharp/BlazorHosted-CSharp.Client/wwwroot/css/site.css index 7338534ed3..fa2c7f19b7 100644 --- a/src/Components/Blazor/Templates/src/content/BlazorHosted-CSharp/BlazorHosted-CSharp.Client/wwwroot/css/site.css +++ b/src/Components/Blazor/Templates/src/content/BlazorHosted-CSharp/BlazorHosted-CSharp.Client/wwwroot/css/site.css @@ -84,6 +84,18 @@ app { background-color: rgba(255, 255, 255, 0.1); } +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid red; +} + +.validation-message { + color: red; +} + @media (max-width: 767.98px) { .main .top-row { display: none; diff --git a/src/Components/Blazor/Templates/src/content/BlazorStandalone-CSharp/_ViewImports.cshtml b/src/Components/Blazor/Templates/src/content/BlazorStandalone-CSharp/_ViewImports.cshtml index 491a46a96c..c01cdd4ec4 100644 --- a/src/Components/Blazor/Templates/src/content/BlazorStandalone-CSharp/_ViewImports.cshtml +++ b/src/Components/Blazor/Templates/src/content/BlazorStandalone-CSharp/_ViewImports.cshtml @@ -1,4 +1,5 @@ @using System.Net.Http +@using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Layouts @using Microsoft.AspNetCore.Components.Routing @using Microsoft.JSInterop diff --git a/src/Components/Blazor/Templates/src/content/BlazorStandalone-CSharp/wwwroot/css/site.css b/src/Components/Blazor/Templates/src/content/BlazorStandalone-CSharp/wwwroot/css/site.css index 7338534ed3..fa2c7f19b7 100644 --- a/src/Components/Blazor/Templates/src/content/BlazorStandalone-CSharp/wwwroot/css/site.css +++ b/src/Components/Blazor/Templates/src/content/BlazorStandalone-CSharp/wwwroot/css/site.css @@ -84,6 +84,18 @@ app { background-color: rgba(255, 255, 255, 0.1); } +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid red; +} + +.validation-message { + color: red; +} + @media (max-width: 767.98px) { .main .top-row { display: none; diff --git a/src/Components/Blazor/testassets/StandaloneApp/wwwroot/css/site.css b/src/Components/Blazor/testassets/StandaloneApp/wwwroot/css/site.css index 7338534ed3..fa2c7f19b7 100644 --- a/src/Components/Blazor/testassets/StandaloneApp/wwwroot/css/site.css +++ b/src/Components/Blazor/testassets/StandaloneApp/wwwroot/css/site.css @@ -84,6 +84,18 @@ app { background-color: rgba(255, 255, 255, 0.1); } +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid red; +} + +.validation-message { + color: red; +} + @media (max-width: 767.98px) { .main .top-row { display: none; diff --git a/src/Components/Components/src/Forms/InputComponents/InputBase.cs b/src/Components/Components/src/Forms/InputComponents/InputBase.cs index a1c61da5bd..4c7f525afd 100644 --- a/src/Components/Components/src/Forms/InputComponents/InputBase.cs +++ b/src/Components/Components/src/Forms/InputComponents/InputBase.cs @@ -42,7 +42,7 @@ namespace Microsoft.AspNetCore.Components.Forms /// /// Gets or sets a callback that updates the bound value. /// - [Parameter] Action ValueChanged { get; set; } + [Parameter] EventCallback ValueChanged { get; set; } /// /// Gets or sets an expression that identifies the bound value. @@ -71,7 +71,7 @@ namespace Microsoft.AspNetCore.Components.Forms if (hasChanged) { Value = value; - ValueChanged?.Invoke(value); + _ = ValueChanged.InvokeAsync(value); EditContext.NotifyFieldChanged(FieldIdentifier); } } diff --git a/src/Components/Components/test/Forms/InputBaseTest.cs b/src/Components/Components/test/Forms/InputBaseTest.cs index cf0e33a0b6..a66078798c 100644 --- a/src/Components/Components/test/Forms/InputBaseTest.cs +++ b/src/Components/Components/test/Forms/InputBaseTest.cs @@ -459,7 +459,8 @@ namespace Microsoft.AspNetCore.Components.Forms { childBuilder.OpenComponent(0); childBuilder.AddAttribute(0, "Value", Value); - childBuilder.AddAttribute(1, "ValueChanged", ValueChanged); + childBuilder.AddAttribute(1, "ValueChanged", + EventCallback.Factory.Create(this, ValueChanged)); childBuilder.AddAttribute(2, "ValueExpression", ValueExpression); childBuilder.AddAttribute(3, nameof(Id), Id); childBuilder.AddAttribute(4, nameof(Class), Class); diff --git a/src/Components/test/E2ETest/Tests/FormsTest.cs b/src/Components/test/E2ETest/Tests/FormsTest.cs index f7046bc256..1ebf4c3e09 100644 --- a/src/Components/test/E2ETest/Tests/FormsTest.cs +++ b/src/Components/test/E2ETest/Tests/FormsTest.cs @@ -316,6 +316,27 @@ namespace Microsoft.AspNetCore.Components.E2ETest.Tests WaitAssert.Empty(emailMessagesAccessor); } + [Fact] + public void InputComponentsCauseContainerToRerenderOnChange() + { + var appElement = MountTestComponent(); + var ticketClassInput = new SelectElement(appElement.FindElement(By.ClassName("ticket-class")).FindElement(By.TagName("select"))); + var selectedTicketClassDisplay = appElement.FindElement(By.Id("selected-ticket-class")); + var messagesAccessor = CreateValidationMessagesAccessor(appElement); + + // Shows initial state + WaitAssert.Equal("Economy", () => selectedTicketClassDisplay.Text); + + // Refreshes on edit + ticketClassInput.SelectByValue("Premium"); + WaitAssert.Equal("Premium", () => selectedTicketClassDisplay.Text); + + // Leaves previous value unchanged if new entry is unparseable + ticketClassInput.SelectByText("(select)"); + WaitAssert.Equal(new[] { "The TicketClass field is not valid." }, messagesAccessor); + WaitAssert.Equal("Premium", () => selectedTicketClassDisplay.Text); + } + private Func CreateValidationMessagesAccessor(IWebElement appElement) { return () => appElement.FindElements(By.ClassName("validation-message")) diff --git a/src/Components/test/testassets/BasicTestApp/FormsTest/TypicalValidationComponent.cshtml b/src/Components/test/testassets/BasicTestApp/FormsTest/TypicalValidationComponent.cshtml index 6941594fc1..bfa01565da 100644 --- a/src/Components/test/testassets/BasicTestApp/FormsTest/TypicalValidationComponent.cshtml +++ b/src/Components/test/testassets/BasicTestApp/FormsTest/TypicalValidationComponent.cshtml @@ -34,6 +34,7 @@ + @person.TicketClass

Accepts terms: diff --git a/src/Components/test/testassets/BasicTestApp/wwwroot/style.css b/src/Components/test/testassets/BasicTestApp/wwwroot/style.css index 740eb993c6..8bb7630162 100644 --- a/src/Components/test/testassets/BasicTestApp/wwwroot/style.css +++ b/src/Components/test/testassets/BasicTestApp/wwwroot/style.css @@ -1,9 +1,9 @@ -.modified.valid { - box-shadow: 0px 0px 0px 2px rgb(78, 203, 37); +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; } .invalid { - box-shadow: 0px 0px 0px 2px rgb(255, 0, 0); + outline: 1px solid red; } .validation-message { diff --git a/src/Components/test/testassets/ComponentsApp.Server/wwwroot/css/site.css b/src/Components/test/testassets/ComponentsApp.Server/wwwroot/css/site.css index 7338534ed3..fa2c7f19b7 100644 --- a/src/Components/test/testassets/ComponentsApp.Server/wwwroot/css/site.css +++ b/src/Components/test/testassets/ComponentsApp.Server/wwwroot/css/site.css @@ -84,6 +84,18 @@ app { background-color: rgba(255, 255, 255, 0.1); } +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid red; +} + +.validation-message { + color: red; +} + @media (max-width: 767.98px) { .main .top-row { display: none; diff --git a/src/Hosting/Abstractions/ref/Microsoft.AspNetCore.Hosting.Abstractions.netcoreapp3.0.cs b/src/Hosting/Abstractions/ref/Microsoft.AspNetCore.Hosting.Abstractions.netcoreapp3.0.cs index 0f031ee9a7..9d856ad0ed 100644 --- a/src/Hosting/Abstractions/ref/Microsoft.AspNetCore.Hosting.Abstractions.netcoreapp3.0.cs +++ b/src/Hosting/Abstractions/ref/Microsoft.AspNetCore.Hosting.Abstractions.netcoreapp3.0.cs @@ -3,6 +3,7 @@ namespace Microsoft.AspNetCore.Hosting { + [System.ObsoleteAttribute("This type is obsolete and will be removed in a future version. The recommended alternative is Microsoft.Extensions.Hosting.Environments.", false)] public static partial class EnvironmentName { public static readonly string Development; diff --git a/src/Hosting/Abstractions/src/EnvironmentName.cs b/src/Hosting/Abstractions/src/EnvironmentName.cs index d5522d1124..df93c4ddf1 100644 --- a/src/Hosting/Abstractions/src/EnvironmentName.cs +++ b/src/Hosting/Abstractions/src/EnvironmentName.cs @@ -6,10 +6,11 @@ namespace Microsoft.AspNetCore.Hosting ///

/// Commonly used environment names. /// + [System.Obsolete("This type is obsolete and will be removed in a future version. The recommended alternative is Microsoft.Extensions.Hosting.Environments.", error: false)] public static class EnvironmentName { public static readonly string Development = "Development"; public static readonly string Staging = "Staging"; public static readonly string Production = "Production"; } -} \ No newline at end of file +} diff --git a/src/Hosting/Hosting/src/Internal/HostingEnvironment.cs b/src/Hosting/Hosting/src/Internal/HostingEnvironment.cs index ee1ab42cdd..1e894ebb1a 100644 --- a/src/Hosting/Hosting/src/Internal/HostingEnvironment.cs +++ b/src/Hosting/Hosting/src/Internal/HostingEnvironment.cs @@ -9,7 +9,7 @@ namespace Microsoft.AspNetCore.Hosting.Internal public class HostingEnvironment : IHostingEnvironment, Extensions.Hosting.IHostingEnvironment, IWebHostEnvironment #pragma warning restore CS0618 // Type or member is obsolete { - public string EnvironmentName { get; set; } = Hosting.EnvironmentName.Production; + public string EnvironmentName { get; set; } = Extensions.Hosting.Environments.Production; public string ApplicationName { get; set; } diff --git a/src/Hosting/Hosting/test/StartupManagerTests.cs b/src/Hosting/Hosting/test/StartupManagerTests.cs index 75d5ccb98c..8f64fb37e5 100644 --- a/src/Hosting/Hosting/test/StartupManagerTests.cs +++ b/src/Hosting/Hosting/test/StartupManagerTests.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Hosting.Internal; using Microsoft.AspNetCore.Hosting.Tests.Internal; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; using Xunit; @@ -510,7 +511,7 @@ namespace Microsoft.AspNetCore.Hosting.Tests serviceCollection.AddSingleton, MyContainerFactory>(); var services = serviceCollection.BuildServiceProvider(); - var startup = StartupLoader.LoadMethods(services, typeof(MyContainerStartup), EnvironmentName.Development); + var startup = StartupLoader.LoadMethods(services, typeof(MyContainerStartup), Environments.Development); var app = new ApplicationBuilder(services); app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection); @@ -526,7 +527,7 @@ namespace Microsoft.AspNetCore.Hosting.Tests serviceCollection.AddSingleton, MyContainerFactory>(); var services = serviceCollection.BuildServiceProvider(); - var startup = StartupLoader.LoadMethods(services, typeof(MyContainerStartupBaseClass), EnvironmentName.Development); + var startup = StartupLoader.LoadMethods(services, typeof(MyContainerStartupBaseClass), Environments.Development); var app = new ApplicationBuilder(services); app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection); @@ -542,13 +543,13 @@ namespace Microsoft.AspNetCore.Hosting.Tests serviceCollection.AddSingleton, MyContainerFactory>(); var services = serviceCollection.BuildServiceProvider(); - var startup = StartupLoader.LoadMethods(services, typeof(MyContainerStartupEnvironmentBased), EnvironmentName.Production); + var startup = StartupLoader.LoadMethods(services, typeof(MyContainerStartupEnvironmentBased), Environments.Production); var app = new ApplicationBuilder(services); app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection); Assert.IsType(app.ApplicationServices); - Assert.Equal(((MyContainer)app.ApplicationServices).Environment, EnvironmentName.Production); + Assert.Equal(((MyContainer)app.ApplicationServices).Environment, Environments.Production); } [Fact] @@ -557,7 +558,7 @@ namespace Microsoft.AspNetCore.Hosting.Tests var serviceCollection = new ServiceCollection(); var services = serviceCollection.BuildServiceProvider(); - var startup = StartupLoader.LoadMethods(services, typeof(MyContainerStartup), EnvironmentName.Development); + var startup = StartupLoader.LoadMethods(services, typeof(MyContainerStartup), Environments.Development); Assert.Throws(() => startup.ConfigureServicesDelegate(serviceCollection)); } @@ -568,7 +569,7 @@ namespace Microsoft.AspNetCore.Hosting.Tests var serviceCollection = new ServiceCollection(); var services = serviceCollection.BuildServiceProvider(); - Assert.Throws(() => StartupLoader.LoadMethods(services, typeof(MyContainerStartupBaseClass), EnvironmentName.Development)); + Assert.Throws(() => StartupLoader.LoadMethods(services, typeof(MyContainerStartupBaseClass), Environments.Development)); } [Fact] @@ -578,7 +579,7 @@ namespace Microsoft.AspNetCore.Hosting.Tests serviceCollection.AddSingleton, MyContainerFactory>(); var services = serviceCollection.BuildServiceProvider(); - Assert.Throws(() => StartupLoader.LoadMethods(services, typeof(MyContainerStartupWithOverloads), EnvironmentName.Development)); + Assert.Throws(() => StartupLoader.LoadMethods(services, typeof(MyContainerStartupWithOverloads), Environments.Development)); } [Fact] @@ -588,7 +589,7 @@ namespace Microsoft.AspNetCore.Hosting.Tests serviceCollection.AddSingleton, MyBadContainerFactory>(); var services = serviceCollection.BuildServiceProvider(); - var startup = StartupLoader.LoadMethods(services, typeof(MyContainerStartup), EnvironmentName.Development); + var startup = StartupLoader.LoadMethods(services, typeof(MyContainerStartup), Environments.Development); var app = new ApplicationBuilder(services); app.ApplicationServices = startup.ConfigureServicesDelegate(serviceCollection); @@ -629,12 +630,12 @@ namespace Microsoft.AspNetCore.Hosting.Tests public void ConfigureDevelopmentContainer(MyContainer container) { - container.Environment = EnvironmentName.Development; + container.Environment = Environments.Development; } public void ConfigureProductionContainer(MyContainer container) { - container.Environment = EnvironmentName.Production; + container.Environment = Environments.Production; } public void Configure(IApplicationBuilder app) diff --git a/src/Hosting/Hosting/test/WebHostConfigurationsTests.cs b/src/Hosting/Hosting/test/WebHostConfigurationsTests.cs index 88a43a4319..35ac6f8b4c 100644 --- a/src/Hosting/Hosting/test/WebHostConfigurationsTests.cs +++ b/src/Hosting/Hosting/test/WebHostConfigurationsTests.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using Microsoft.AspNetCore.Hosting.Internal; using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Hosting; using Xunit; namespace Microsoft.AspNetCore.Hosting.Tests @@ -18,7 +19,7 @@ namespace Microsoft.AspNetCore.Hosting.Tests { WebHostDefaults.WebRootKey, "wwwroot"}, { WebHostDefaults.ApplicationKey, "MyProjectReference"}, { WebHostDefaults.StartupAssemblyKey, "MyProjectReference" }, - { WebHostDefaults.EnvironmentKey, EnvironmentName.Development}, + { WebHostDefaults.EnvironmentKey, Environments.Development}, { WebHostDefaults.DetailedErrorsKey, "true"}, { WebHostDefaults.CaptureStartupErrorsKey, "true" }, { WebHostDefaults.SuppressStatusMessagesKey, "true" } @@ -29,7 +30,7 @@ namespace Microsoft.AspNetCore.Hosting.Tests Assert.Equal("wwwroot", config.WebRoot); Assert.Equal("MyProjectReference", config.ApplicationName); Assert.Equal("MyProjectReference", config.StartupAssembly); - Assert.Equal(EnvironmentName.Development, config.Environment); + Assert.Equal(Environments.Development, config.Environment); Assert.True(config.CaptureStartupErrors); Assert.True(config.DetailedErrors); Assert.True(config.SuppressStatusMessages); @@ -38,10 +39,10 @@ namespace Microsoft.AspNetCore.Hosting.Tests [Fact] public void ReadsOldEnvKey() { - var parameters = new Dictionary() { { "ENVIRONMENT", EnvironmentName.Development } }; + var parameters = new Dictionary() { { "ENVIRONMENT", Environments.Development } }; var config = new WebHostOptions(new ConfigurationBuilder().AddInMemoryCollection(parameters).Build()); - Assert.Equal(EnvironmentName.Development, config.Environment); + Assert.Equal(Environments.Development, config.Environment); } [Theory] diff --git a/src/Hosting/Hosting/test/WebHostTests.cs b/src/Hosting/Hosting/test/WebHostTests.cs index 177ec6c8cd..2b55a00bcb 100644 --- a/src/Hosting/Hosting/test/WebHostTests.cs +++ b/src/Hosting/Hosting/test/WebHostTests.cs @@ -812,8 +812,8 @@ namespace Microsoft.AspNetCore.Hosting #pragma warning disable CS0618 // Type or member is obsolete var env2 = host.Services.GetService(); #pragma warning restore CS0618 // Type or member is obsolete - Assert.Equal(EnvironmentName.Production, env.EnvironmentName); - Assert.Equal(EnvironmentName.Production, env2.EnvironmentName); + Assert.Equal(Environments.Production, env.EnvironmentName); + Assert.Equal(Environments.Production, env2.EnvironmentName); } } @@ -822,7 +822,7 @@ namespace Microsoft.AspNetCore.Hosting { var vals = new Dictionary { - { "Environment", EnvironmentName.Staging } + { "Environment", Environments.Staging } }; var builder = new ConfigurationBuilder() @@ -835,8 +835,8 @@ namespace Microsoft.AspNetCore.Hosting #pragma warning disable CS0618 // Type or member is obsolete var env2 = host.Services.GetService(); #pragma warning restore CS0618 // Type or member is obsolete - Assert.Equal(EnvironmentName.Staging, env.EnvironmentName); - Assert.Equal(EnvironmentName.Staging, env.EnvironmentName); + Assert.Equal(Environments.Staging, env.EnvironmentName); + Assert.Equal(Environments.Staging, env.EnvironmentName); } } @@ -873,7 +873,7 @@ namespace Microsoft.AspNetCore.Hosting { await host.StartAsync(); var env = host.Services.GetRequiredService(); - Assert.True(env.IsEnvironment(EnvironmentName.Production)); + Assert.True(env.IsEnvironment(Environments.Production)); Assert.True(env.IsEnvironment("producTion")); } } diff --git a/src/Hosting/samples/SampleStartups/StartupFullControl.cs b/src/Hosting/samples/SampleStartups/StartupFullControl.cs index f438111050..81a2605557 100644 --- a/src/Hosting/samples/SampleStartups/StartupFullControl.cs +++ b/src/Hosting/samples/SampleStartups/StartupFullControl.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; // Note that this sample will not run. It is only here to illustrate usage patterns. @@ -25,7 +26,7 @@ namespace SampleStartups .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) // Override the content root with the current directory .UseUrls("http://*:1000", "https://*:902") - .UseEnvironment(EnvironmentName.Development) + .UseEnvironment(Environments.Development) .UseWebRoot("public") .ConfigureServices(services => { diff --git a/src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs b/src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs index 1524622bd4..b817468df7 100644 --- a/src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs +++ b/src/Mvc/Mvc.Testing/src/WebApplicationFactory.cs @@ -13,7 +13,6 @@ using Microsoft.AspNetCore.TestHost; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyModel; using Microsoft.Extensions.Hosting; -using EnvironmentName = Microsoft.Extensions.Hosting.EnvironmentName; namespace Microsoft.AspNetCore.Mvc.Testing { @@ -307,7 +306,7 @@ namespace Microsoft.AspNetCore.Mvc.Testing var hostBuilder = HostFactoryResolver.ResolveHostBuilderFactory(typeof(TEntryPoint).Assembly)?.Invoke(Array.Empty()); if (hostBuilder != null) { - hostBuilder.UseEnvironment(EnvironmentName.Development); + hostBuilder.UseEnvironment(Environments.Development); } return hostBuilder; } @@ -336,7 +335,7 @@ namespace Microsoft.AspNetCore.Mvc.Testing } else { - return builder.UseEnvironment(EnvironmentName.Development); + return builder.UseEnvironment(Environments.Development); } } diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorComponentsWeb-CSharp/Components/_ViewImports.cshtml b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorComponentsWeb-CSharp/Components/_ViewImports.cshtml index 28fb28776b..13358155d4 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorComponentsWeb-CSharp/Components/_ViewImports.cshtml +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorComponentsWeb-CSharp/Components/_ViewImports.cshtml @@ -1,4 +1,5 @@ @using System.Net.Http +@using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Layouts @using Microsoft.AspNetCore.Components.Routing @using Microsoft.JSInterop diff --git a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorComponentsWeb-CSharp/wwwroot/css/site.css b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorComponentsWeb-CSharp/wwwroot/css/site.css index 7338534ed3..fa2c7f19b7 100644 --- a/src/ProjectTemplates/Web.ProjectTemplates/content/RazorComponentsWeb-CSharp/wwwroot/css/site.css +++ b/src/ProjectTemplates/Web.ProjectTemplates/content/RazorComponentsWeb-CSharp/wwwroot/css/site.css @@ -84,6 +84,18 @@ app { background-color: rgba(255, 255, 255, 0.1); } +.valid.modified:not([type=checkbox]) { + outline: 1px solid #26b050; +} + +.invalid { + outline: 1px solid red; +} + +.validation-message { + color: red; +} + @media (max-width: 767.98px) { .main .top-row { display: none;