Telerik Forums
UI for Blazor Forum
1 answer
4 views
Hello Telerik Team,

I'm building advanced forms using <TelerikForm> and <FormItem> components. My use case includes complex grid layouts (4+ columns), dynamic label/input structures, and the ability to switch orientations (horizontal ↔ vertical) depending on the layout.

The problem I face is related to label positioning and flexibility. Since labels are tightly bound to inputs inside <FormItem>, it's hard to restructure the layout dynamically or follow modern design principles where labels float, stack, or separate cleanly from inputs.

Additionally, because <FormItem> doesn’t offer properties like LabelCssClass or FieldCssClass, I’m forced to use <Template> for nearly every form element. And in large forms (50+ fields), that creates a huge boilerplate mess.

Here's a code example of how I currently break label/input pairing just to achieve layout control:
<FormItem Field="Number1" ColSpan="2">
	<Template>
		<label for="Number" class="k-label k-form-label">
			@Localizer["Form_JednAdminView_Number"]:
		</label>
	</Template>
</FormItem>
<FormItem Field="Number1" ColSpan="1">
	<Template>
		<TelerikNumericTextBox Id="Number1" Value="@DataContext.FormData.Number1" ValueExpression="@(() => DataContext.FormData.Number1)" ReadOnly="true" />
		<TelerikValidationTooltip For="@(() => DataContext.FormData.Number1)" TargetSelector="#Number1" />
	</Template>
</FormItem>
<FormItem Field="Number2" ColSpan="1">
	<Template>
		<TelerikTextBox Id="Number2" Value="@DataContext.FormData.Number2" ValueExpression="@(() => DataContext.FormData.Number2)" ReadOnly="true" />
		<TelerikValidationTooltip For="@(() => DataContext.FormData.Number2)" TargetSelector="#Number2" />
	</Template>
</FormItem>
@GetEmptyFormItem(4)
Some notes about the limitations:
-I cannot use RenderFragment loops with a shared template to render controls dynamically — because I lose the ability to manage each control’s UI and behavior precisely.
-Using @refs to manage these dynamic elements becomes a nightmare — they don't give me flexible access to the rendered markup/UI, and the logic becomes very hard to maintain.
-So to preserve clean control over layout and per-control behavior, I'm forced to manually write each <FormItem> and control in a verbose way — which feels like overkill.

In aim to have less boilerplate UI and code, but still have an ability to change layout structure in real time - my questions are:
-Can we request a feature to separate labels from inputs, but still associate them logically (e.g., via an Id, or LabelFor property)?
-Is there any plan or recommendation to make <TelerikForm> more flexible — for instance, to allow label placement (above/beside) or wrapping via a simple layout option?
-Are there any workarounds/best practices for advanced layouts with full control over label/input rendering, while preserving strong typing and validation?

But the main aim is to have an opportunity to have Labels aligned by left and have "space between" input and label,
Maybe there is some easy approach with overriding some of your classes like k-input or k-label or k-form-label etc...?
I’d really appreciate your insights.

Thanks for your time and help!
Best regards,
Bohdan (Blazor Developer)

Dimo
Telerik team
 answered on 03 Jun 2025
1 answer
6 views

Can you tell me how to get a consistent height for my huge "Create New" button?  I expected it to just use the space it needed instead of being 5X the size it is.

.gsi-height-32px{
    height: 32px !important;
}
<TelerikStackLayout Height="100%"
                    Width="100%"
                    Orientation="StackLayoutOrientation.Vertical">

    <TelerikButton OnClick="@OnCreate"
                   Class="gsi-width-100pct gsi-height-32px">
        Create New
    </TelerikButton>

    <TelerikGrid Data=@Patients
                 SelectedItems="SelectedPatients"
                 Pageable=true
                 PageSize="20"
                 Height="100%"
                 SelectionMode=GridSelectionMode.Single
                 SelectedItemsChanged="@((IEnumerable<Gsi.Customer.Models.Person> m) => OnPatientSelected(m))">

        <GridColumns>
            <GridColumn Field=@nameof(Person.FirstName) Title="First Name" />
            <GridColumn Field=@nameof(Person.LastName) Title="Last Name" />
            <GridColumn Field=@($"{nameof(Patient)}.{nameof(Patient.DateOfBirthDisplay)}") Title="Date of Birth" Width="125px" />
            <GridColumn Field=@($"{nameof(Patient)}.{nameof(Patient.GenderDisplay)}") Title="Sex" Width="100px" />
            <GridColumn Field=@nameof(Person.LastSessionTimestampDisplay) Title="Last Session" />
        </GridColumns>
    </TelerikGrid>
</TelerikStackLayout>

Dimo
Telerik team
 answered on 03 Jun 2025
1 answer
11 views

Hello Everyone,

I'm working on a Blazor Server project, and I've replaced the default navigation menu with a TelerikMenu component. It produces this:

When I click the Counter, Weather, etc, I get to the correct page. Here's how my project is layed out:

You can see that the Home.razor page is in the same location as the Weather and Counter page. I'm also able to get to the pages under the DisplayData folder. Here's the code:


<div>
<img src="picture.png" style="height: 300px; margin-right: 10px;">
</div>

<TelerikMenu Data="@MenuData"
            Orientation=@MenuOrientation.Vertical></TelerikMenu>



@code{
    public List<MenuItem> MenuData { get; set; }

    public class MenuItem
    {
        public string Text { get; set; }
        public string Url { get; set; }
        public ISvgIcon Icon { get; set; }
        public List<MenuItem> Items { get; set; }
    }

    protected override void OnInitialized()
    {
        GenerateMenuData();
    }

    public void GenerateMenuData()
    {
        MenuData = new List<MenuItem>()
        {
            new MenuItem()
            {
                Text = "Home",
                Url = "Home",
                Icon = SvgIcon.Home
            },
            new MenuItem()
            {
                Text = "Counter",
                Url = "Counter",
                Icon = SvgIcon.Calculator
            },
            new MenuItem()
            {
                Text = "Weather",
                Url = "Weather",
                Icon = SvgIcon.Globe
            },            
            new MenuItem()
            {
                Text = "Display Data",
                Url = "",
                Icon = SvgIcon.Data,
                Items = new List<MenuItem>()
                {
                    new MenuItem()
                    {
                        Text = "Delme Table",
                        Url = "/DelMeTable",
                        Icon = SvgIcon.Data // SvgIcon.User
                    },
                    new MenuItem()
                    {
                        Text = "Delme Telerik",
                        Url = "/DelmeTelerikTable",
                        Icon = SvgIcon.Data
                    },
                    new MenuItem()
                    {
                        Text = "Delme Telerik SQL",
                        Url = "/DelmeTelerikTableSQL",
                        Icon = SvgIcon.Data
                    }
                }
            }
        };//end of MenuData
        
    }//end of GenerateMenuData()

//
}

When I try to get back to the Home page, I get a "Not Found" error. Also of note, when the application launches to the Home page, here is the URL (from the debugger): localhost:7044.

My question is, how do I set the URL for the home page to get back to it?

 

Thanks,

Mike

Justin
Telerik team
 answered on 30 May 2025
1 answer
6 views

I copied this example and got it working:

https://www.telerik.com/blazor-ui/documentation/knowledge-base/treelist-expand-nodes-programmatically

Can you tell me how to default my TreeList to have everything expanded when my page loads?  It seems running the SetTreeListExpandedItems after loading my data does not expand everything automatically... which is confusing to me.


            <TelerikCard>
                <CardBody Class="gsi-padding-0">
                    <TelerikButton OnClick="@SetTreeListExpandedItems"
                                   Class="gsi-width-100pct">
                        Expand/Collapse Groups
                    </TelerikButton>
                </CardBody>
            </TelerikCard>

            <TelerikTreeList @ref=TreeListRef
                             Data="@Groups"
                             SelectedItems="@SelectedGroups"
                             IdField="@nameof(Gsi.Customer.Models.Group.Id)"
                             ParentIdField="@nameof(Gsi.Customer.Models.Group.ParentId)"
                             OnStateInit="((TreeListStateEventArgs<Gsi.Customer.Models.Group> args) => OnStateInitHandler(args))"
                             Pageable="false"
                             Sortable="false"
                             SelectionMode="TreeListSelectionMode.Single"
                             FilterMode="@TreeListFilterMode.FilterMenu"
                             SelectedItemsChanged="@((IEnumerable<Gsi.Customer.Models.Group> m) => OnGroupSelected(m))">
                <TreeListColumns>
                    <TreeListColumn Field="Name" Title="Group Filter" Expandable="true">
                        <Template>
                            @{
                                var item = context as Gsi.Customer.Models.Group;
                                <img height="32" width="32" src="@item.ImageUrl" />
                                @item.Name
                            }
                        </Template>
                    </TreeListColumn>
                </TreeListColumns>
            </TelerikTreeList>

Justin
Telerik team
 answered on 30 May 2025
0 answers
8 views
How do I fill the 2nd row to the bottom with my data grid?  The top row filled as expected in using enough space for the button.  However, I expected the bottom row to then use the rest of the area and dock the data grid.  Is there a height setting that says fill the rest of the area?


            <TelerikGridLayout Class="grid-layout">
                <GridLayoutRows>
                    <GridLayoutRow />
                    <GridLayoutRow />
                </GridLayoutRows>
                <GridLayoutItems>
                    <GridLayoutItem Row="1">
                        <TelerikButton OnClick="@OnCreate"
                                       Class="gsi-width-100pct gsi-height-32px">
                            Create New
                        </TelerikButton>
                    </GridLayoutItem>
                    <GridLayoutItem Row="2">
                        <TelerikGrid Data=@Patients
                                     SelectedItems="SelectedPatients"
                                     Pageable=true
                                     PageSize="20"
                                     Height="100%"
                                     SelectionMode=GridSelectionMode.Single
                                     SelectedItemsChanged="@((IEnumerable<Gsi.Customer.Models.Person> m) => OnPatientSelected(m))">

                            <GridColumns>
                                <GridColumn Field=@nameof(Person.FirstName) Title="First Name" />
                                <GridColumn Field=@nameof(Person.LastName) Title="Last Name" />
                                <GridColumn Field=@($"{nameof(Patient)}.{nameof(Patient.DateOfBirthDisplay)}") Title="Date of Birth" Width="125px" />
                                <GridColumn Field=@($"{nameof(Patient)}.{nameof(Patient.GenderDisplay)}") Title="Sex" Width="100px" />
                                <GridColumn Field=@nameof(Person.LastSessionTimestampDisplay) Title="Last Session" />
                            </GridColumns>
                        </TelerikGrid>
                    </GridLayoutItem>
                </GridLayoutItems>
            </TelerikGridLayout>

Joel
Top achievements
Rank 2
Bronze
Iron
Iron
 asked on 30 May 2025
1 answer
11 views

Hey guys,

I'm trying to setup my TelerikScheduler similar to this:

Blazor Display Only All-Day Appointments in the Scheduler - Telerik UI for Blazor

When I have multiple items for a single day, the items overlap, instead of stacking:

REPL: Telerik REPL for Blazor - The best place to play, experiment, share & learn using Blazor.

Which produces the overlapping items ("ABC" and "XYZ"):

If you click "Next day" a couple times you'll see another example ("DEF" and "UVW" overlapping).

Go one more day and it looks fine:

If you click "Week" view at the top (which is also using the TimelineView), you can see an example of one of them overlapping (on the 27th):

Is there any way to work around this issue? I would like to have multiple items listed per day (without time slots showing). Just stacked.

Everything looks how it should in Month view.

Everything looks how it should if they span more than one day generally.

Thanks

-Adam

UPDATE: Forgot to mention - SlotDivisions="1" may have something to do with it.  However, if I don't include this, it will have two columns per day which I don't want.

Stamo Gochev
Telerik team
 answered on 30 May 2025
1 answer
9 views
Hi Folks,

For the below component the dropdown loads the data only after 10 seconds or so after the component is rendered on the browser.
How would I get it to load immediately on the component load and not show the "No data" message on dropdown selection. The dropdown is loaded with data from an api service to an oracle database and it returns about 100 records. 

@page "/Startup"
@rendermode @(new InteractiveServerRenderMode(prerender: false))
@using ance.UI.Components.Layout
@layout MainLayout
@inject NavigationManager Navigation
@inject tenance.UI.Services.ApiService apiService
@inject Blazored.SessionStorage.ISessionStorageService sessionStorage
@using sMaintenance.UI.Dtos
@using Microsoft.AspNetCore.Http
@using Microsoft.AspNetCore.DataProtection
@using estExtensions.Core.Principal
@using System.Text.Json;
@using System.IO;
@inject IHttpContextAccessor HttpContextAccessor
@inject IDataProtectionProvider DataProtectionProvider
@inject IConfiguration configuration;
@inject GlobalTokenContainer globalTokenContainer;

<h1 > Test Page</h1>
<label class="card-title">Select : </label>
<TelerikDropDownList Data="@Testdata"
TextField="UserName"
ValueField="NewideId"
@bind-Value="selectedValue"
OnChange="@OnUserSelectionChanged"
Width="20%" /> 
<br />
<br /><br />
<div style="display: flex; gap: 1rem; align-items: center;">
    <div style="display: flex; align-items: center; gap: 0.5rem;">
        <label class="card-title">NewwideID : </label>
        <TelerikTextBox @bind-Value="@Name" Width="150px"  ReadOnly="@true"/>
    </div>
    <div style="display: flex; align-items: center; gap: 0.5rem;">
        <label class="card-title">Role : </label>
        <TelerikTextBox @bind-Value="@Role" Width="150px" ReadOnly="@true" />
    </div>
</div>
<br />
<div>
    <label class="card-title">demo No. : </label>
    <TelerikTextBox @bind-Value="@ClaimNo" Width="20%" />
</div>
<br />
<div>
    <TelerikButton OnClick="@GoToClms" ThemeColor="@(ThemeConstants.Button.ThemeColor.Primary)">GO</TelerikButton>
    <TelerikButton>Send Letter</TelerikButton>
    <TelerikButton OnClick="@GoToOtherPage">Catastrophe Manager</TelerikButton>
</div>
<br />
@if (!string.IsNullOrEmpty(warningMessage))
{
    <div class="alert alert-danger">Global token is empty </div>
}
@code {
    private string? NewideID;
    private string Role = "Adjster";
    private string? ClaimNo;
    public string? Name;
    private string Token = string.Empty;
    private List<AdjerDto> adjusters = new();
    private string? selectedValue;
    private string? globalToken;
    private const string CookieName = "UserInfo";
    private const bool V = true;
    private string cookieValue = "";
    private string? warningMessage;
    private string? baseHref; 

    public async Task GetOrFetchTokenAsync(string nwideId)
    {
        // Check if the token exists in session storage
        var globalToken = await sessionStorage.GetItemAsync<string>("gltoken");
        var wetoken= await sessionStorage.GetItemAsync<string>("wetoken");

        if (string.IsNullOrEmpty(gltoken))
        {
            gltoken= await apiService.GetGlobalTokenAsync(newideId);
            if (!string.IsNullOrEmpty(gltoken))
            {
                // Store the fetched token in session storage
                await sessionStorage.SetItemAsync("globaltoken", gltoken);
                globalTokenConer.GlolToken = gltoken;
            }
        }
        if (string.IsNullOrEmpty(cimToken))
        {
            wetoken= await apiService.GetCimTokenAsync(newideId);
            if (!string.IsNullOrEmpty(cimToken))
            {
                // Store the fetched token in session storage
                await sessionStorage.SetItemAsync("cimtoken", cimToken);
            }
        }
    }

    // Method to handle navigation to the Catastrophe Management page after obtaining a global token
    private async Task GoToOtherPage()
    {
        try
        {
            // Reset the global token to ensure a fresh start
            globalToken = string.Empty;

            // Proceed only if a Name is provided
            if (Name is not null)
            {
                // Fetch or retrieve token for the provided Name (possibly from a cache or API)
                await GetOrFetchTokenAsync(Name);

                // Attempt to get the actual global token from the API
                globalToken = await apiService.GetGlobalTokenAsync(Name);

                // Log and check if the token is successfully retrieved
                if (!string.IsNullOrWhiteSpace(globalToken))
                {
                    Console.WriteLine($"Received Global Token: {globalToken}");
                }
                else
                {
                    // Set a warning message if the token is null or empty
                    warningMessage = $"Warning: API returned an empty or null token for  {Name}";
                    Console.WriteLine(warningMessage);

                    // Trigger UI update and exit the method early
                    StateHasChanged();
                    return;
                }

                // Update the UI to reflect new state
                StateHasChanged();
            }

            // Store the global token in the browser's session storage
            await sessionStorage.SetItemAsync("globaltoken", globalToken);

            // If token is valid, clear warning message and navigate to the Catastrophe Management page
            if (!string.IsNullOrWhiteSpace(globalToken))
            {
                warningMessage = string.Empty;
                Navigation.NavigateTo($"{baseHref}CatastrophePages/CatastropheManagement?globalToken={globalToken}", true);
            }
        }
        catch (Exception ex)
        {
            // Log any exceptions that occur during the process
            Console.WriteLine(ex.Message);
        }
    }

    private async Task GoToClms()
    {
        try
        {
            gloToken = string.Empty;
            if (Name is not null)
            {
                await GetOrFetchTokenAsync(Name);
                glToken = await apiService.GetGlobalTokenAsync(Name);
                if (!string.IsNullOrWhiteSpace(glToken ))
                {
                    Console.WriteLine($"Received Global Token: {glToken }");
                }
                else
                {
                    warningMessage = $"Warning: API returned an empty or null token for  {Name}";
                    Console.WriteLine($"Warning: API returned an empty or null token for  { Name}");
                    StateHasChanged();
                    return;
                }
                StateHasChanged();
            }
            await sessionStorage.SetItemAsync("globaltoken", glToken );
            if (!string.IsNullOrWhiteSpace(ClaimNo) && !string.IsNullOrWhiteSpace(glToken ))
            {
                warningMessage = string.Empty;
                Navigation.NavigateTo($"{baseHref}ClaimDetails/{ClaimNo}?globalToken={glToken }", true);
            }
            else if (!string.IsNullOrWhiteSpace(globalToken))
            {
                warningMessage = string.Empty;
                Navigation.NavigateTo($"{baseHref}Claitory?globalToken={glToken }", true);
            }
         }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
     
    }
    // Component Initialization code
    protected override async Task OnInitializedAsync()
    {
        await sessionStorage.SetItemAsync("name", "John Smith");
        var name = await sessionStorage.GetItemAsync<string>("name");
        warningMessage = string.Empty;
        baseHref = configuration.GetValue<string>("baseHref");
        Testdata= await GetLoadAersAsync();
    }
    // Adjuster Dropdown list selection changed event
    private async Task OnUserSelectionChanged(object value)
    {
        warningMessage = string.Empty;
        if (value is string selectedNwideId)
        {
            Name = selectedNwideId;
            globalToken = await apiService.GetGlobalTokenAsync(Name);
        }
        StateHasChanged();
    }
    // Fetch from the API
    public async Task<List<AdstrDto>> GetLoadAdjusAsync()
    {
            var response = await apiService.GetjustersAsync();
            return response ?? new List<AdstrDto>();
    }    
}
Nadezhda Tacheva
Telerik team
 answered on 28 May 2025
1 answer
15 views

Can you tell me how I can define the Grid to fill the entire splitter area without trying to guess?


                <TelerikGrid Data=@Sessions
                             SelectedItems="SelectedSessions"
                             Pageable=true
                             PageSize="20"
                             Height="80%"
                             SelectionMode=GridSelectionMode.Single
                             SelectedItemsChanged="@((IEnumerable<Gsi.Customer.Models.Session> m) => OnSessionSelected(m))">

                    <GridColumns>
                        <GridColumn Field=@nameof(Session.TimestampDisplayName) Title="Timestamp" />
                        <GridColumn Field=@nameof(Session.TimeZoneOffset) Title="Time Zone Offset" />
                    </GridColumns>
                </TelerikGrid>

    <TelerikSplitter Orientation="SplitterOrientation.Horizontal" Height="75vh">
        <SplitterPanes>

            <SplitterPane Size="50%" Min="30%" Max="70%" Collapsible="false" Class="k-scrollable">
            </SplitterPane>

            <SplitterPane Min="30%" Max="70%" Collapsible="false" Class="k-sc            </SplitterPane>
        </SplitterPanes>
    </TelerikSplitter>


Nadezhda Tacheva
Telerik team
 answered on 28 May 2025
2 answers
46 views

Hello
I need RowNumber in <GridColumns> in Dynamic Grid which is set with ExpandoObject.
Please help.

Thank you

Johan
Top achievements
Rank 2
Iron
Iron
 answered on 27 May 2025
1 answer
13 views

Is it possible to have nested tiles in a TileLayout.

For example. The main page could have 2 tiles which the user could reorder or resize and within each of these tiles there would be some components that could be reordered or resized just within the inner tile.

In the image below I was able to create 2 tiles but they cannot be reordered.

I tried placing these 2 tiles inside another TelerikTileLayout but had issues when attempting to reorder or resize the inner components.

In my actual application I may end up with multiple levels of nesting and the structure is generated from a definition read in by the page.

I create an example here https://blazorrepl.telerik.com/QTapQGvU54CO5Pjw05

Regards

Hristian Stefanov
Telerik team
 answered on 27 May 2025
Top users last month
Will
Top achievements
Rank 2
Iron
Motti
Top achievements
Rank 1
Iron
Hester
Top achievements
Rank 1
Iron
Bob
Top achievements
Rank 3
Iron
Iron
Veteran
Thomas
Top achievements
Rank 2
Iron
Want to show your ninja superpower to fellow developers?
Want to show your ninja superpower to fellow developers?