---
title: Style the template
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

## Style the template based on properties

You probably noticed in the last section that the template is not very pretty yet. You'll also find that the dropdowns for color scheme and corner style in the template properties don't change anything.

Let's create a service that maps the options from the dropdown to CSS classes, and a tag helper that uses it to style a `div` element.

### Create a service to retrieve styles

1. Define an `IComponentStyleEnumService` interface in the _\~/Features/Shared/Services_ folder.

2. Include method signatures to retrieve CSS classes based on a `ColorSchemeOption` and `CornerStyleOption` respectively.
   ```csharp title="IComponentStyleEnumService.cs"
   using TrainingGuides.Web.Features.Shared.OptionProviders.ColorScheme;
   using TrainingGuides.Web.Features.Shared.OptionProviders.CornerStyle;

   namespace TrainingGuides.Web.Features.Shared.Services;

   public interface IComponentStyleEnumService
   {
       IEnumerable<string> GetColorSchemeClasses(ColorSchemeOption colorScheme);

       IEnumerable<string> GetCornerStyleClasses(CornerStyleOption cornerStyle);
       ...
   ```

3. Add method signatures to convert the string representation of a selected option to its corresponding enum value, and to retrieve the style for links.
   ```csharp title="IComponentStyleEnumService.cs"
   ...
   CornerStyleOption GetCornerStyle(string cornerStyleString);

   ColorSchemeOption GetColorScheme(string colorSchemeString);

   ColorSchemeOption GetLinkStyle(string linkStyleString);
   }
   ```

4. Implement the interface, mapping the selected options to sets of CSS classes. Use the `Parse` method from the `EnumStringService` we defined [earlier in the series](https://docs.kentico.com/modules/page-builder/map-enum-to-dropdown.md) for the string conversion methods.

   ```csharp title="ComponentStyleEnumService.cs"
   using TrainingGuides.Web.Features.Shared.OptionProviders;
   using TrainingGuides.Web.Features.Shared.OptionProviders.ColorScheme;
   using TrainingGuides.Web.Features.Shared.OptionProviders.CornerStyle;

   namespace TrainingGuides.Web.Features.Shared.Services;

   public class ComponentStyleEnumService(IEnumStringService enumStringService) : IComponentStyleEnumService
   {
       public IEnumerable<string> GetColorSchemeClasses(ColorSchemeOption colorScheme) => colorScheme switch
       {
           ColorSchemeOption.Light1 => ["tg-bg-light-1", "tg-txt-dark"],
           ColorSchemeOption.Light2 => ["tg-bg-light-2", "tg-txt-dark"],
           ColorSchemeOption.Light3 => ["tg-bg-light-3", "tg-txt-dark"],
           ColorSchemeOption.Dark1 => ["tg-bg-primary", "tg-txt-light"],
           ColorSchemeOption.Dark2 => ["tg-bg-secondary", "tg-txt-light"],
           ColorSchemeOption.TransparentLight => ["tg-bg-none", "tg-txt-light"],
           ColorSchemeOption.TransparentMedium => ["tg-bg-none", "tg-txt-medium"],
           ColorSchemeOption.TransparentDark => ["tg-bg-none", "tg-txt-dark"],
           _ => [string.Empty],
       };

       public IEnumerable<string> GetCornerStyleClasses(CornerStyleOption cornerStyle) => cornerStyle switch
       {
           CornerStyleOption.Round => ["tg-corner-rnd"],
           CornerStyleOption.VeryRound => ["tg-corner-v-rnd"],
           CornerStyleOption.Sharp => ["tg-corner-shrp"],
           _ => [string.Empty],
       };

       public CornerStyleOption GetCornerStyle(string cornerStyleString) =>
           enumStringService.Parse(cornerStyleString, CornerStyleOption.Round);

       public ColorSchemeOption GetColorScheme(string colorSchemeString) =>
           enumStringService.Parse(colorSchemeString, ColorSchemeOption.TransparentDark);

       public ColorSchemeOption GetLinkStyle(string linkStyleString)
       {
           var colorScheme = enumStringService.Parse(linkStyleString, LinkStyleOption.TransparentDark);
           return (ColorSchemeOption)colorScheme;
       }
   }
   ```

   > **Info:** Each of the classes in this example are small, usually only setting one css property to minimize collisions across classes.
   >
   > Defining the styles themselves is outside the scope of this series, but you can find their definitions in the _\~/scss_ directory, where .scss styles are defined and later compiled to css.
   >
   > If you are using the [main branch of the Training guides repository](https://github.com/Kentico/xperience-by-kentico-training-guides) to follow along, the classes should already exist.

5. Remember to register the service with the dependency injection container in the _TrainingGuides.Web/ServiceCollectionExtensions.cs_ file:
   ```csharp title="ServiceCollectionExtensions.cs"
   ...
   public static void AddTrainingGuidesServices(this IServiceCollection services)
   {
       ...
       services.AddSingleton<IComponentStyleEnumService, ComponentStyleEnumService>();
       ...
   }
   ...
   ```

### Apply the styles with a tag helper

1. Add a new class called `ComponentStyleTagHelper`to the _\~/Features/Shared/Helpers/TagHelpers_ folder.
2. Inherit from the .NET `TagHelper` class, and decorate it with the `HtmlTargetElement` attribute to set its element name to `tg-component-style`. Acquire an `IComponentStyleEnumService` object through dependency injection.
   ```csharp title="ComponentStyleTagHelper.cs"
   ...
   [HtmlTargetElement("tg-component-style")]
   public class ComponentStyleTagHelper(
       IComponentStyleEnumService componentStyleEnumService) : TagHelper
   ...
   ```
3. Give the tag helper string properties called `ColorScheme` and `CornerStyle`, so that objects that store selections as strings, such as page template properties, can use them directly.
   ```csharp title="ComponentStyleTagHelper.cs"
       ...
       public string ColorScheme { get; set; } = string.Empty;
       public string CornerStyle { get; set; } = string.Empty;
       ...
   ```
4. Use a constant to hold the type of tag, in case we need to add more complex logic for determining the tag name in the future.
   ```csharp title="ComponentStyleTagHelper.cs"
   ...
   private const string DIV_TAG = "div";
   ...
   ```
5. In the `Process` method, use the service to retrieve styles for the output tag.
   ```csharp title="ComponentStyleTagHelper.cs"
   ...
   public override void Process(TagHelperContext context, TagHelperOutput output)
   {
       output.TagName = DIV_TAG;

       List<string> cssClasses = [];

       var colorScheme = componentStyleEnumService.GetColorScheme(ColorScheme);
       cssClasses.AddRange(componentStyleEnumService.GetColorSchemeClasses(colorScheme));

       var cornerStyle = componentStyleEnumService.GetCornerStyle(CornerStyle);
       cssClasses.AddRange(componentStyleEnumService.GetCornerStyleClasses(cornerStyle));

       if (cssClasses.Count > 0)
       {
           foreach (string cssClass in cssClasses)
           {
               output.AddClass(cssClass, HtmlEncoder.Default);
           }
       }
   }
   ...
   ```

In the end, your tag helper should look like this:

```csharp title="ComponentStyleTagHelper.cs"
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Razor.TagHelpers;
using TrainingGuides.Web.Features.Shared.Services;

namespace TrainingGuides.Web.Features.Shared.Helpers.TagHelpers;

[HtmlTargetElement("tg-component-style")]
public class ComponentStyleTagHelper(
    IComponentStyleEnumService componentStyleEnumService) : TagHelper
{
    public string ColorScheme { get; set; } = string.Empty;
    public string CornerStyle { get; set; } = string.Empty;

    private const string DIV_TAG = "div";

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = DIV_TAG;

        List<string> cssClasses = [];

        var colorScheme = componentStyleEnumService.GetColorScheme(ColorScheme);
        cssClasses.AddRange(componentStyleEnumService.GetColorSchemeClasses(colorScheme));

        var cornerStyle = componentStyleEnumService.GetCornerStyle(CornerStyle);
        cssClasses.AddRange(componentStyleEnumService.GetCornerStyleClasses(cornerStyle));

        if (cssClasses.Count > 0)
        {
            foreach (string cssClass in cssClasses)
            {
                output.AddClass(cssClass, HtmlEncoder.Default);
            }
        }
    }
}
```

### Put the tag helper to use

The tag helper is now ready to be added to the view.
If you return to _ServicePagePageTemplate.cshtml_ you can wrap all of the existing markup with the new tag helper tag, and pass along the color scheme and corner style properties from the page template's configuration.

```cshtml title="ServicePagePageTemplate.cshtml"
    @using TrainingGuides.Web.Features.FinancialServices.Models
    @using TrainingGuides.Web.Features.FinancialServices

    @model TemplateViewModel<ServicePagePageTemplateProperties>

    @{
        var templateModel = Model.GetTemplateModel<ServicePageViewModel>();
    }

    <tg-component-style color-scheme="@Model.Properties.ColorScheme" corner-style="@Model.Properties.CornerStyle">
        <div>
            <div>
                <h3>@templateModel.NameHtml</h3>
                <p>@templateModel.ShortDescriptionHtml</p>
            </div>
            
            <div>
                <img src="@templateModel.Media.FirstOrDefault()?.FilePath" alt="@templateModel.Media.FirstOrDefault()?.Description"/>
            </div>
        </div>
    </tg-component-style>
```

If you sign in to the Xperience administration interface, you'll notice that you can now adjust the appearance of the box containing the service's data by clicking the gear icon in the bottom left of the _Page Builder_ pane.

However, if you set the template to use rounded corners and a colored background, you'll see that the corners of the image do not change to match the style of the parent div. The image may also be an unreasonable size, depending on the file.

![Screenshot of incomplete template with rounded corners set. Also showing the Configure template button.](https://docs.kentico.com/docsassets/modules/style-the-template/ScreenshotTemplateProgress.png "Screenshot of incomplete template with rounded corners set. Also showing the Configure template button.")

### Create an image tag helper

1. In the _\~/Features/Shared/Helpers/TagHelpers_ folder, add a new self-closing TagHelper called `StyledImageTagHelper` with the tag name `tg-styled-image`. Inject an `IComponentStyleEnumService` instance.
   ```csharp title="StyledImageTagHelper.cs"
   ...
   namespace TrainingGuides.Web.Features.Shared.Helpers.TagHelpers;

   [HtmlTargetElement("tg-styled-image", TagStructure = TagStructure.WithoutEndTag)]
   public class StyledImageTagHelper(
       IComponentStyleEnumService componentStyleEnumService) : TagHelper
   ...
   ```
2. Set up properties in the same manner as the `ComponentStyleTagHelper`, leaving out the `ColorScheme` property this time.
   ```csharp title="StyledImageTagHelper.cs"
   ...

   public string CornerStyle { get; set; } = string.Empty;

   private const string IMG_TAG = "img";
   ...
   ```
3. In the `Process` method, set the `TagMode` of the rendered HTML tag to `TagMode.SelfClosing` and style the image according to the classes returned by the service.
   ```csharp title="StyledImageTagHelper.cs"
   ...
   public override void Process(TagHelperContext context, TagHelperOutput output)
   {
       output.TagName = IMG_TAG;
       output.TagMode = TagMode.SelfClosing;

       List<string> cssClasses = [];

       var cornerStyle = componentStyleEnumService
           .GetCornerStyle(CornerStyle ?? string.Empty);
       cssClasses.AddRange(componentStyleEnumService
           .GetCornerStyleClasses(cornerStyle));

       if (cssClasses.Count > 0)
       {
           foreach (string cssClass in cssClasses)
           {
               output.AddClass(cssClass, HtmlEncoder.Default);
           }
       }
   }
   ...
   ```

The resulting tag helper should look like this:

```csharp title="StyledImageTagHelper.cs"
using System.Text.Encodings.Web;
using Microsoft.AspNetCore.Mvc.TagHelpers;
using Microsoft.AspNetCore.Razor.TagHelpers;
using TrainingGuides.Web.Features.Shared.Services;

namespace TrainingGuides.Web.Features.Shared.Helpers.TagHelpers;

[HtmlTargetElement("tg-styled-image", TagStructure = TagStructure.WithoutEndTag)]
public class StyledImageTagHelper(
    IComponentStyleEnumService componentStyleEnumService) : TagHelper
{
    public string CornerStyle { get; set; } = string.Empty;

    private const string IMG_TAG = "img";

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        output.TagName = IMG_TAG;
        output.TagMode = TagMode.SelfClosing;

        List<string> cssClasses = [];

        var cornerStyle = componentStyleEnumService.GetCornerStyle(CornerStyle ?? string.Empty);
        cssClasses.AddRange(componentStyleEnumService.GetCornerStyleClasses(cornerStyle));

        if (cssClasses.Count > 0)
        {
            foreach (string cssClass in cssClasses)
            {
                output.AddClass(cssClass, HtmlEncoder.Default);
            }
        }
    }
}
```

The tag helper can be used in the view like this:

```cshtml title="Tag helper usage (e.g., in ServicePagePageTemplate.cshtml)"
@foreach (var asset in templateModel.Media)
{
    <tg-styled-image src="@asset.FilePath" 
        alt="@asset.Description" 
        corner-style="@Model.Properties.CornerStyle" 
        class="c-product-img object-fit-cover" />
}
```
