Blazorise Scheduler component
Create and manage appointments in a calendar layout.
See Scheduler specifications for behavior details and edge cases.
To use the Scheduler component, install the Blazorise.Scheduler package first.
Installation
NuGet
Install extension from NuGet.dotnet add package Blazorise.Scheduler
Imports
In your main _Imports.razor add:
@using Blazorise.Scheduler
Fundamentals
Before we proceed we need to cover some fundamentals on how Scheduler is working.
Using TItem
The Scheduler<TItem> component is generic and can theoretically work with any type. However, the type must contain properties for Title, Start, and End at minimum. These property names can be overridden using property mappings.
Editing
Editing of scheduler items can be enabled or disabled by setting Editable parameter:
- Editable="true": Enables built-in editing capabilities.
- Editable="false": Disables built-in editing. In this case, item creation, updates, and deletions must be handled manually using callbacks like
ItemInserted,ItemUpdated, andItemDeleted.
Customizing the Editor
Use SchedulerColumns and SchedulerColumn to add custom fields to the built-in Add/Edit Appointment modal or to replace the editor for a native scheduler field.
A column whose Field maps to an additional model property, such as Color, is rendered after the native scheduler fields. Its value is copied together with the rest of the appointment when the modal is saved. Additional fields are rendered in a Fields layout and can use ColumnSize to control their width. A column whose Field maps to a native scheduler property, such as Title, replaces the native editor in the modal but still uses the scheduler's built-in state, validation, and save flow.
Drag and Drop
Drag and drop functionality for scheduler items can be toggled using Draggable parameter:
- Draggable="true" (default): Allows items to be moved or resized via drag-and-drop.
- Draggable="false": Disables drag-and-drop interactions.
Recurring Appointments
The Scheduler component supports recurring appointments based on RFC-5545 recurrence rules. Recurrences are dynamically displayed based on these rules and are not persisted by the component itself. Persistence of recurrence data must be managed by the developer and backend.
- Recurring items: Defined by limited RFC-5545 rules and calculated at runtime.
- Exceptions: Edited or deleted occurrences of recurring appointments are exceptions and managed internally by the scheduler component.
Examples
Basic
To start with the Scheduler, just define it using one of the available views.<Scheduler TItem="Appointment" @bind-Date="" Data="" @bind-SelectedView=""> <SchedulerToolbar /> <SchedulerViews> <SchedulerWeekView StartTime="" EndTime="" WorkDayStart="" WorkDayEnd="" /> </SchedulerViews> </Scheduler>
@code { private DateOnly selectedDate = DateOnly.FromDateTime( DateTime.Today ); private SchedulerView selectedView = SchedulerView.Week; private static DateTime today10AM = DateTime.Today.AddHours( 10 ); private TimeOnly startTime = new TimeOnly( 7, 0 ); private TimeOnly endTime = new TimeOnly( 17, 0 ); private TimeOnly workDayStart = new TimeOnly( 8, 0 ); private TimeOnly workDayEnd = new TimeOnly( 16, 0 ); public class Appointment { public Appointment() { } public Appointment( string title, string description, DateTime start, DateTime end, bool allDay = false ) { Id = Guid.NewGuid().ToString(); Title = title; Description = description; Start = start; End = end; AllDay = allDay; } public string Id { get; set; } public string Title { get; set; } public string Description { get; set; } public DateTime Start { get; set; } public DateTime End { get; set; } public bool AllDay { get; set; } public string RecurrenceRule { get; set; } } List<Appointment> Appointments = new List<Appointment> { new Appointment( "Meeting with the CEO", "Regarding the new margeting strategy", today10AM, today10AM.AddHours(1) ), new Appointment( "Some other meeting", "Regarding the new margeting strategy", today10AM, today10AM.AddHours(1) ), new Appointment( "Lunch with the team", "Discussing the new project", today10AM.AddDays(-10).AddHours(2), today10AM.AddDays(-10).AddHours(3)) { RecurrenceRule = "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;INTERVAL=2;COUNT=3" }, }; }
Editable
TheEditable parameter allows you to enable or disable editing of the scheduler items. When set to true, the scheduler will allow users to edit the items directly in the UI.
<Scheduler TItem="Appointment" @bind-Date="" Data="" @bind-SelectedView="" Editable> <SchedulerToolbar /> <SchedulerViews> <SchedulerWeekView StartTime="" EndTime="" WorkDayStart="" WorkDayEnd="" /> </SchedulerViews> </Scheduler>
@code { private DateOnly selectedDate = DateOnly.FromDateTime( DateTime.Today ); private SchedulerView selectedView = SchedulerView.Week; private static DateTime today10AM = DateTime.Today.AddHours( 10 ); private TimeOnly startTime = new TimeOnly( 7, 0 ); private TimeOnly endTime = new TimeOnly( 17, 0 ); private TimeOnly workDayStart = new TimeOnly( 8, 0 ); private TimeOnly workDayEnd = new TimeOnly( 16, 0 ); public class Appointment { public Appointment() { } public Appointment( string title, string description, DateTime start, DateTime end, bool allDay = false ) { Id = Guid.NewGuid().ToString(); Title = title; Description = description; Start = start; End = end; AllDay = allDay; } public string Id { get; set; } public string Title { get; set; } public string Description { get; set; } public DateTime Start { get; set; } public DateTime End { get; set; } public bool AllDay { get; set; } public string RecurrenceRule { get; set; } } List<Appointment> Appointments = new List<Appointment> { new Appointment( "Meeting with the CEO", "Regarding the new margeting strategy", today10AM, today10AM.AddHours(1) ), new Appointment( "Some other meeting", "Regarding the new margeting strategy", today10AM, today10AM.AddHours(1) ), new Appointment( "Lunch with the team", "Discussing the new project", today10AM.AddDays(-10).AddHours(2), today10AM.AddDays(-10).AddHours(3)) { RecurrenceRule = "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;INTERVAL=2;COUNT=3" }, }; }
Draggable
To be able to drag and drop items, set theDraggable parameter to true. This will allow you to move items around the calendar.
<Scheduler TItem="Appointment" @bind-Date="" Data="" @bind-SelectedView="" Editable Draggable> <SchedulerToolbar /> <SchedulerViews> <SchedulerWeekView StartTime="" EndTime="" WorkDayStart="" WorkDayEnd="" /> </SchedulerViews> </Scheduler>
@code { private DateOnly selectedDate = DateOnly.FromDateTime( DateTime.Today ); private SchedulerView selectedView = SchedulerView.Week; private static DateTime today10AM = DateTime.Today.AddHours( 10 ); private TimeOnly startTime = new TimeOnly( 7, 0 ); private TimeOnly endTime = new TimeOnly( 17, 0 ); private TimeOnly workDayStart = new TimeOnly( 8, 0 ); private TimeOnly workDayEnd = new TimeOnly( 16, 0 ); public class Appointment { public Appointment() { } public Appointment( string title, string description, DateTime start, DateTime end, bool allDay = false ) { Id = Guid.NewGuid().ToString(); Title = title; Description = description; Start = start; End = end; AllDay = allDay; } public string Id { get; set; } public string Title { get; set; } public string Description { get; set; } public DateTime Start { get; set; } public DateTime End { get; set; } public bool AllDay { get; set; } public string RecurrenceRule { get; set; } } List<Appointment> Appointments = new List<Appointment> { new Appointment( "Meeting with the CEO", "Regarding the new margeting strategy", today10AM, today10AM.AddHours(1) ), new Appointment( "Some other meeting", "Regarding the new margeting strategy", today10AM, today10AM.AddHours(1) ), new Appointment( "Lunch with the team", "Discussing the new project", today10AM.AddDays(-10).AddHours(2), today10AM.AddDays(-10).AddHours(3)) { RecurrenceRule = "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;INTERVAL=2;COUNT=3" }, }; }
Slot Selection
To easily create new items, set theSlotSelectionMode parameter to Mouse. This will allow you to select slots in the calendar to create new items.
<Scheduler TItem="Appointment" @bind-Date="" Data="" SelectedView="SchedulerView.Week" Editable SlotSelectionMode="SchedulerSlotSelectionMode.Mouse"> <SchedulerToolbar /> <SchedulerViews> <SchedulerWeekView StartTime="" EndTime="" WorkDayStart="" WorkDayEnd="" /> </SchedulerViews> </Scheduler>
@code { private DateOnly selectedDate = DateOnly.FromDateTime( DateTime.Today ); private static DateTime today10AM = DateTime.Today.AddHours( 10 ); private TimeOnly startTime = new TimeOnly( 7, 0 ); private TimeOnly endTime = new TimeOnly( 17, 0 ); private TimeOnly workDayStart = new TimeOnly( 8, 0 ); private TimeOnly workDayEnd = new TimeOnly( 16, 0 ); public class Appointment { public Appointment() { } public Appointment( string title, string description, DateTime start, DateTime end, bool allDay = false ) { Id = Guid.NewGuid().ToString(); Title = title; Description = description; Start = start; End = end; AllDay = allDay; } public string Id { get; set; } public string Title { get; set; } public string Description { get; set; } public DateTime Start { get; set; } public DateTime End { get; set; } public bool AllDay { get; set; } public string RecurrenceRule { get; set; } } List<Appointment> Appointments = new List<Appointment> { new Appointment( "Meeting with the CEO", "Regarding the new margeting strategy", today10AM, today10AM.AddHours(1) ), new Appointment( "Some other meeting", "Regarding the new margeting strategy", today10AM, today10AM.AddHours(1) ), new Appointment( "Lunch with the team", "Discussing the new project", today10AM.AddDays(-10).AddHours(2), today10AM.AddDays(-10).AddHours(3)) { RecurrenceRule = "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;INTERVAL=2;COUNT=3" }, }; }
Custom Styling
Use theSlotStylingTemplate to inspect each rendered slot through SchedulerSlotContext and update slot.Styling based on the slot Start and End values.
<Scheduler TItem="Appointment" @bind-Date="" Data="" SelectedView="SchedulerView.Week"> <SchedulerToolbar /> <SchedulerViews> <SchedulerWeekView StartTime="" EndTime="" WorkDayStart="" WorkDayEnd=""> <SlotStylingTemplate Context="slot"> @{ ApplySlotStyling( slot ); } </SlotStylingTemplate> </SchedulerWeekView> </SchedulerViews> </Scheduler>
@code { private DateOnly selectedDate = DateOnly.FromDateTime( DateTime.Today ); private static DateTime today9AM = DateTime.Today.AddHours( 9 ); private TimeOnly startTime = new TimeOnly( 7, 0 ); private TimeOnly endTime = new TimeOnly( 17, 0 ); private TimeOnly workDayStart = new TimeOnly( 8, 0 ); private TimeOnly workDayEnd = new TimeOnly( 16, 0 ); private TimeOnly focusTimeStart = new TimeOnly( 9, 0 ); private TimeOnly focusTimeEnd = new TimeOnly( 10, 0 ); private TimeOnly lunchBreakStart = new TimeOnly( 12, 0 ); private TimeOnly lunchBreakEnd = new TimeOnly( 13, 0 ); public class Appointment { public Appointment() { } public Appointment( string title, string description, DateTime start, DateTime end, bool allDay = false ) { Id = Guid.NewGuid().ToString(); Title = title; Description = description; Start = start; End = end; AllDay = allDay; } public string Id { get; set; } public string Title { get; set; } public string Description { get; set; } public DateTime Start { get; set; } public DateTime End { get; set; } public bool AllDay { get; set; } } private void ApplySlotStyling( SchedulerSlotContext slot ) { if ( IsSlotInRange( slot, lunchBreakStart, lunchBreakEnd ) ) { slot.Styling.Background = Background.Warning; slot.Styling.Style = "opacity: 0.35;"; } else if ( IsSlotInRange( slot, focusTimeStart, focusTimeEnd ) ) { slot.Styling.Background = Background.Success; slot.Styling.Style = "opacity: 0.2;"; } } private static bool IsSlotInRange( SchedulerSlotContext slot, TimeOnly rangeStart, TimeOnly rangeEnd ) { return slot.Start.TimeOfDay >= rangeStart.ToTimeSpan() && slot.End.TimeOfDay <= rangeEnd.ToTimeSpan(); } List<Appointment> Appointments = new List<Appointment> { new Appointment( "Team sync", "Weekly status update", today9AM, today9AM.AddMinutes( 30 ) ), new Appointment( "Design review", "Scheduler custom slot styling", today9AM.AddHours( 2 ), today9AM.AddHours( 3 ) ), new Appointment( "Lunch and learn", "New scheduler templates", today9AM.AddHours( 3 ), today9AM.AddHours( 4 ) ), }; }
Custom Fields
UseSchedulerColumns to customize the Add/Edit Appointment modal. This example replaces the native Title editor and adds custom Color and Location fields. The additional fields use ColumnSize to share a row on desktop, and the color is applied through ItemStyling.
<Scheduler TItem="Appointment" @bind-Date="" Data="" @bind-SelectedView="" Editable ItemStyling=""> <SchedulerToolbar /> <SchedulerViews> <SchedulerWeekView StartTime="" EndTime="" WorkDayStart="" WorkDayEnd="" /> </SchedulerViews> <SchedulerColumns> <SchedulerColumn TItem="Appointment" Field="@nameof( Appointment.Title )" Caption="Appointment title" TValue="string"> <EditTemplate Context="context"> <TextInput @bind-Value="@context.Value" /> </EditTemplate> </SchedulerColumn> <SchedulerColumn TItem="Appointment" Field="@nameof( Appointment.Color )" Caption="Color" TValue="string" ColumnSize="ColumnSize.IsHalf.OnDesktop"> <EditTemplate Context="context"> <ColorPicker @bind-Value="@context.Value" /> </EditTemplate> </SchedulerColumn> <SchedulerColumn TItem="Appointment" Field="@nameof( Appointment.Location )" Caption="Location" TValue="string" ColumnSize="ColumnSize.IsHalf.OnDesktop"> <EditTemplate Context="context"> <TextInput @bind-Value="@context.Value" /> </EditTemplate> </SchedulerColumn> </SchedulerColumns> </Scheduler>
@code { private DateOnly selectedDate = DateOnly.FromDateTime( DateTime.Today ); private SchedulerView selectedView = SchedulerView.Week; private static DateTime today10AM = DateTime.Today.AddHours( 10 ); private TimeOnly startTime = new TimeOnly( 7, 0 ); private TimeOnly endTime = new TimeOnly( 17, 0 ); private TimeOnly workDayStart = new TimeOnly( 8, 0 ); private TimeOnly workDayEnd = new TimeOnly( 16, 0 ); private void OnItemStyling( Appointment appointment, SchedulerItemStyling itemStyling ) { if ( !string.IsNullOrEmpty( appointment.Color ) ) { itemStyling.Background = Background.Default; itemStyling.Style = $"background-color: {appointment.Color};"; itemStyling.TextColor = TextColor.White; } } public class Appointment { public Appointment() { } public Appointment( string title, string description, DateTime start, DateTime end, string color, string location ) { Id = Guid.NewGuid().ToString(); Title = title; Description = description; Start = start; End = end; Color = color; Location = location; } public string Id { get; set; } public string Title { get; set; } public string Description { get; set; } public DateTime Start { get; set; } public DateTime End { get; set; } public bool AllDay { get; set; } public string Color { get; set; } public string Location { get; set; } } List<Appointment> Appointments = new List<Appointment> { new Appointment( "Design review", "Reviewing the new dashboard", today10AM, today10AM.AddHours( 1 ), "#0d6efd", "Conference room" ), new Appointment( "Planning", "Sprint planning session", today10AM.AddHours( 2 ), today10AM.AddHours( 3 ), "#198754", "Main office" ), new Appointment( "Customer call", "Quarterly product feedback", today10AM.AddDays( 1 ).AddHours( 1 ), today10AM.AddDays( 1 ).AddHours( 2 ), "#dc3545", "Remote" ), }; }
Fixed Size
To set a fixed size for the scheduler, set theViewHeight parameter to a specific value. This will ensure that the scheduler maintains a consistent height across different views.
<Scheduler TItem="Appointment" Data="" SelectedView="SchedulerView.Week"> <SchedulerToolbar /> <SchedulerViews> <SchedulerWeekView ViewHeight="500" /> </SchedulerViews> </Scheduler>
@code { private static DateTime today10AM = DateTime.Today.AddHours( 10 ); public class Appointment { public Appointment() { } public Appointment( string title, string description, DateTime start, DateTime end, bool allDay = false ) { Id = Guid.NewGuid().ToString(); Title = title; Description = description; Start = start; End = end; AllDay = allDay; } public string Id { get; set; } public string Title { get; set; } public string Description { get; set; } public DateTime Start { get; set; } public DateTime End { get; set; } public bool AllDay { get; set; } public string RecurrenceRule { get; set; } } List<Appointment> Appointments = new List<Appointment> { new Appointment( "Meeting with the CEO", "Regarding the new margeting strategy", today10AM, today10AM.AddHours(1) ), new Appointment( "Some other meeting", "Regarding the new margeting strategy", today10AM, today10AM.AddHours(1) ), new Appointment( "Lunch with the team", "Discussing the new project", today10AM.AddDays(-10).AddHours(2), today10AM.AddDays(-10).AddHours(3)) { RecurrenceRule = "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;INTERVAL=2;COUNT=3" }, }; }
All Enabled
The full example shows all available views and how to use them. It also shows how to set theStartTime, EndTime, WorkDayStart, and WorkDayEnd parameters.
<Scheduler TItem="Appointment" @bind-Date="" Data="" @bind-SelectedView="" Editable Draggable SlotSelectionMode="SchedulerSlotSelectionMode.Mouse"> <SchedulerToolbar /> <SchedulerViews> <SchedulerDayView StartTime="" EndTime="" WorkDayStart="" WorkDayEnd="" /> <SchedulerWeekView StartTime="" EndTime="" WorkDayStart="" WorkDayEnd="" /> <SchedulerWorkWeekView StartTime="" EndTime="" WorkDayStart="" WorkDayEnd="" /> <SchedulerMonthView StartTime="" EndTime="" WorkDayStart="" WorkDayEnd="" /> </SchedulerViews> </Scheduler>
@code { private DateOnly selectedDate = DateOnly.FromDateTime( DateTime.Today ); private SchedulerView selectedView = SchedulerView.Week; private static DateTime today10AM = DateTime.Today.AddHours( 10 ); private TimeOnly startTime = new TimeOnly( 7, 0 ); private TimeOnly endTime = new TimeOnly( 17, 0 ); private TimeOnly workDayStart = new TimeOnly( 8, 0 ); private TimeOnly workDayEnd = new TimeOnly( 16, 0 ); public class Appointment { public Appointment() { } public Appointment( string title, string description, DateTime start, DateTime end, bool allDay = false ) { Id = Guid.NewGuid().ToString(); Title = title; Description = description; Start = start; End = end; AllDay = allDay; } public string Id { get; set; } public string Title { get; set; } public string Description { get; set; } public DateTime Start { get; set; } public DateTime End { get; set; } public bool AllDay { get; set; } public string RecurrenceRule { get; set; } } List<Appointment> Appointments = new List<Appointment> { new Appointment( "Meeting with the CEO", "Regarding the new margeting strategy", today10AM, today10AM.AddHours(1) ), new Appointment( "Some other meeting", "Regarding the new margeting strategy", today10AM, today10AM.AddHours(1) ), new Appointment( "Lunch with the team", "Discussing the new project", today10AM.AddDays(-10).AddHours(2), today10AM.AddDays(-10).AddHours(3)) { RecurrenceRule = "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR;INTERVAL=2;COUNT=3" }, }; }
API
See the API reference for the parameters, events, methods, and related types available to the components covered on this page.