Appearance topic
Appearance
This is part of the kalender documentation.
What the calendar looks like: event tiles, theming, and replacing the default components. For where tiles are placed rather than how they look, see Layout.
Tile Components
TileComponents is the primary way to control how events look in the calendar. Pass it to KalenderHeader and/or KalenderBody for day, multi-day, and month views.
For schedule views, use ScheduleTileComponents instead (passed via KalenderBody.scheduleTileComponents).
Simple tile
For most apps a plain tileBuilder is all you need:
KalenderBody(
multiDayTileComponents: TileComponents(
tileBuilder: (context, event, tileRange) {
final myEvent = event as Event;
return Container(
decoration: BoxDecoration(
color: myEvent.color ?? Colors.blue,
borderRadius: BorderRadius.circular(4),
),
padding: const EdgeInsets.all(4),
child: Text(myEvent.title, style: const TextStyle(color: Colors.white)),
);
},
),
)
All TileComponents options
Every aspect of an event tile's appearance and drag behavior can be overridden.
Only tileBuilder is required. Every other field defaults to null, which keeps
the package's own behavior, so set only what you want to change.
TileComponents reference
TileComponents(
// Required: the stationary event tile.
tileBuilder: (context, event, tileRange) => Container(),
// Shown over the calendar in portal overlays instead of tileBuilder.
overlayTileBuilder: (context, event, tileRange) => Container(),
// Shown in place of the tile while it is being dragged.
tileWhenDraggingBuilder: (context, event) => Container(),
// The tile that follows the cursor / finger during a drag.
feedbackTileBuilder: (context, event, dropTargetWidgetSize) => Container(),
// Rendered beneath the dragged tile to show where it will land.
dropTargetTile: (context, event) => Container(),
// The drag anchor strategy used by feedbackTileBuilder.
dragAnchorStrategy: childDragAnchorStrategy,
// Position and size the resize handles. `details` carries the tile's geometry
// and builds the detectors, so decide the layout and place them.
resizeHandlePositioner: (context, details) => Stack(
fit: StackFit.expand,
children: [
if (details.showStart())
Positioned(top: 0, left: 0, right: 0, height: 8, child: details.startResizeDetector),
if (details.showEnd())
Positioned(bottom: 0, left: 0, right: 0, height: 8, child: details.endResizeDetector),
],
),
// The vertical resize handle widget.
verticalResizeHandle: Container(),
// The horizontal resize handle widget.
horizontalResizeHandle: Container(),
)
Warning
The snippet above omits resizeDragAnchorStrategy. It defaults to a pointer
anchor. Setting it to childDragAnchorStrategy makes a vertical resize jump to
the neighbouring day on the smallest sideways movement.
ScheduleTileComponents
Schedule view tiles have a different set of builders since they are laid out in a list rather than a grid.
ScheduleTileComponents reference
ScheduleTileComponents(
// Required: the stationary event tile.
tileBuilder: (context, event, tileRange) => Container(),
// Shown in place of the tile while it is being dragged.
tileWhenDraggingBuilder: (context, event) => Container(),
// The tile that follows the cursor / finger during a drag.
feedbackTileBuilder: (context, event, dropTargetWidgetSize) => Container(),
// The drag anchor strategy used by feedbackTileBuilder.
dragAnchorStrategy: childDragAnchorStrategy,
)
Schedule tiles cannot be resized, so ScheduleTileComponents takes no resize handles. It also takes no dropTargetTile: during a drag the schedule marks the destination by highlighting the row, built by ScheduleComponents.scheduleTileHighlightBuilder and styled by ScheduleTileHighlightStyle. The empty-day and month heading rows are list rows rather than event tiles, so their builders live on ScheduleComponents as well.
Advanced tiles with event-tile utilities
For tiles that need to know the exact tapped time or find nearby events, use the provided mixins.
Tip
Disabling the calendar's built-in tap detector: The calendar only wraps event tiles in a GestureDetector when onEventTapped or onEventTappedWithDetail is provided in KalenderCallbacks. If you omit both callbacks, the wrapper is skipped and a GestureDetector inside your custom tile widget can receive events unobstructed. This is the intended pattern when using DayEventTileUtils or MultiDayEventTileUtils.
DayEventTileUtils (day / multi-day body tiles)
class CustomDayEventTile extends StatelessWidget with DayEventTileUtils {
@override
final KalenderEvent event;
@override
final KalenderDateTimeRange tileRange;
const CustomDayEventTile({
super.key,
required this.event,
required this.tileRange,
});
Event get myEvent => event as Event;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapUp: (details) {
// Convert a local tap position into an exact DateTime.
final tappedTime = dateTimeFromPosition(context, details.localPosition);
debugPrint('Tapped at: $tappedTime');
// Find events that overlap a ±15-minute window around this one.
final nearby = nearbyEvents(
context,
before: const Duration(minutes: 15),
after: const Duration(minutes: 15),
);
debugPrint('Found ${nearby.length} nearby events');
},
child: Container(
decoration: BoxDecoration(
color: myEvent.color ?? Colors.blue,
borderRadius: BorderRadius.circular(4),
),
padding: const EdgeInsets.all(4),
child: Text(myEvent.title, style: const TextStyle(color: Colors.white)),
),
);
}
// Static factory. Pass directly to TileComponents.tileBuilder.
static Widget builder(BuildContext context, KalenderEvent event, KalenderDateTimeRange tileRange) =>
CustomDayEventTile(
event: event,
tileRange: tileRange,
);
}
const dayTileComponents = TileComponents(tileBuilder: CustomDayEventTile.builder);
MultiDayEventTileUtils (month view / multi-day header tiles)
class CustomMultiDayEventTile extends StatelessWidget with MultiDayEventTileUtils {
@override
final KalenderEvent event;
@override
final KalenderDateTimeRange tileRange;
const CustomMultiDayEventTile({
super.key,
required this.event,
required this.tileRange,
});
Event get myEvent => event as Event;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTapUp: (details) {
// Convert a horizontal tap position into a specific date.
final tappedDate = dateFromPosition(context, details.localPosition);
debugPrint('Tapped on: $tappedDate');
final overlapping = nearbyEvents(context);
debugPrint('Found ${overlapping.length} overlapping events');
},
child: Container(
decoration: BoxDecoration(
color: myEvent.color ?? Colors.green,
borderRadius: BorderRadius.circular(4),
),
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 2),
child: Text(
myEvent.title,
style: const TextStyle(color: Colors.white, fontSize: 12),
overflow: TextOverflow.ellipsis,
),
),
);
}
static Widget builder(BuildContext context, KalenderEvent event, KalenderDateTimeRange tileRange) =>
CustomMultiDayEventTile(
event: event,
tileRange: tileRange,
);
}
const multiDayTileComponents = TileComponents(tileBuilder: CustomMultiDayEventTile.builder);
Theming
By default the calendar follows your app's Material 3 theme: line colors, text styles, and the rest are derived from the ambient ColorScheme and TextTheme.
To change how every calendar in the app looks, register a KalenderThemeData on your theme. Any field you leave out keeps its Material 3 default.
MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
extensions: [
KalenderThemeData(
hourLinesStyle: HourLinesStyle(thickness: 2),
timeIndicatorStyle: TimeIndicatorStyle(lineColor: Colors.pink),
),
],
),
)
Theming part of the app
Registering on ThemeData covers every calendar in the app. To theme one of
them differently, wrap it in a KalenderTheme:
KalenderTheme(
data: const KalenderThemeData(
hourLinesStyle: HourLinesStyle(thickness: 2),
),
child: KalenderView(
eventsController: DefaultEventsController(),
kalenderController: KalenderController(),
viewConfiguration: MultiDayViewConfiguration.week(),
body: KalenderBody(),
),
)
The nearest one wins when they nest, and fields it leaves out fall through to
the theme registered on ThemeData, so a scope can change one thing without
restating the rest.
This is an InheritedTheme, so it also reaches widgets the calendar builds into
an Overlay, such as the tile that follows a drag.
How a style is resolved
Four layers, most specific first. Each one fills in the fields the layer above it leaves null.
- A style passed directly to a widget, which is how a custom builder styles the widget it returns (see Appearance).
- The nearest
KalenderThemeabove the calendar. - The
KalenderThemeDataregistered onThemeData.extensions. - The Material 3 defaults.
Note
Gutter widths are not styles. The month week number column and the multi-day timeline are drawn in the body and reserved again in the header, so the calendar measures each once and both halves read that number. A KalenderTheme scoped inside one half restyles the gutter there without resizing it. Set the width with MonthBodyComponents.weekNumberWidth or MultiDayBodyComponents.timelineWidth.
Switching themes transitions the calendar's colors along with the rest of the app. A KalenderTheme scope does not animate.
The overflow overlay
The overlay that opens from the +3 button, which stands in for events that do not fit, is themed the same way. Its card and close button take Flutter's own CardThemeData and ButtonStyle.
KalenderThemeData(
multiDayOverlayStyle: MultiDayOverlayStyle(
cardTheme: CardThemeData(
color: Colors.white,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
),
closeButtonStyle: IconButton.styleFrom(backgroundColor: Colors.amber),
// Dims the calendar behind the card. Transparent by default.
barrierColor: Colors.black54,
width: 320,
),
)
closeButtonStyle merges over the defaults of a filled tonal icon button, so set only the fields you change.
Appearance / Custom Components
Pass a KalenderComponents object to KalenderView to override the default widget builders.
Note
KalenderComponents carries builders only. Styles live on KalenderThemeData:
register one on ThemeData.extensions for the whole app, or wrap a calendar in
a KalenderTheme to style one of them.
Every builder receives a BuildContext as its first argument and resolves what
it needs from it: styles with KalenderTheme.of(context), and the state of the
enclosing calendar with KalenderScope, one accessor per value.
MultiDayComponents
KalenderComponents(
multiDayComponents: MultiDayComponents(
headerComponents: MultiDayHeaderComponents(
dayHeaderBuilder: (context, date) => CustomWidget(),
weekNumberBuilder: (context, visibleDateTimeRange) => CustomWidget(),
leftTriggerBuilder: (context, pageWidth) => SizedBox(width: pageWidth / 20),
rightTriggerBuilder: (context, pageWidth) => SizedBox(width: pageWidth / 20),
overlayBuilders: OverlayBuilders(
multiDayPortalOverlayButtonBuilder:
(context, portalController, numberOfHiddenRows) => SizedBox(),
),
),
bodyComponents: MultiDayBodyComponents(
hourLines: (context, heightPerMinute, timeOfDayRange) => CustomWidget(),
timeline: (context, heightPerMinute, timeOfDayRange, eventBeingDragged, visibleDateTimeRange) =>
CustomWidget(),
// Sizes the timeline gutter, for example to fit a custom timeline's labels.
timelineWidth: (context, timeOfDayRange) => 48,
daySeparator: (context) => CustomWidget(),
timeIndicator: (context, timeOfDayRange, heightPerMinute, location) => CustomWidget(),
leftTriggerBuilder: (context, pageWidth) => SizedBox(width: pageWidth / 20),
rightTriggerBuilder: (context, pageWidth) => SizedBox(width: pageWidth / 20),
topTriggerBuilder: (context, viewPortHeight) => SizedBox(height: viewPortHeight / 20),
bottomTriggerBuilder: (context, viewPortHeight) => SizedBox(height: viewPortHeight / 20),
),
),
)
MonthComponents
KalenderComponents(
monthComponents: MonthComponents(
headerComponents: MonthHeaderComponents(
weekDayHeaderBuilder: (context, date) => SizedBox(),
),
bodyComponents: MonthBodyComponents(
monthDayHeaderBuilder: (context, date) => SizedBox(),
// Custom per-cell background, or use the ready-made
// MonthDayCell.shadeAdjacentMonths() to shade adjacent-month days.
monthDayCellBuilder: (context, details) => SizedBox(),
monthGridBuilder: (context, numberOfRows) => SizedBox(),
weekNumberBuilder: (context, visibleDateTimeRange) => SizedBox(),
leftTriggerBuilder: (context, pageWidth) => SizedBox(),
rightTriggerBuilder: (context, pageWidth) => SizedBox(),
overlayBuilders: OverlayBuilders(
multiDayPortalOverlayButtonBuilder:
(context, portalController, numberOfHiddenRows) => SizedBox(),
),
),
),
)
ScheduleComponents
KalenderComponents(
scheduleComponents: ScheduleComponents(
// The date column shown beside the first row of each day.
leadingDateBuilder: (context, date) => Container(),
// Wraps a row to highlight it as the drop target during a drag.
scheduleTileHighlightBuilder: (context, date, range, child) =>
Container(child: child),
// Optional: builder for days with no events.
emptyItemBuilder: (context, tileRange) => Container(),
// Optional: builder for the month heading rows.
monthItemBuilder: (context, monthRange) => Container(),
),
)
Classes
- DayHeader Appearance
- A widget that displays the name of the day and the day number of the week.
- DayHeaderStyle Appearance
- The styling class for the DayHeader.
- DayNumberStyle Appearance
-
The DayNumberStyle class is used by the
DayNumberwidget. - DaySeparator Appearance
- A widget that displays a separator between days.
- DaySeparatorStyle Appearance
- The style for the DaySeparator widget.
- HourLines Appearance
- A widget that displays lines for each hour based on the timeOfDayRange and heightPerMinute.
- HourLinesStyle Appearance
- The style of the HourLines widget.
- KalenderComponents Appearance
- A class holding the widget builders used by the KalenderView.
- KalenderTheme Appearance
- Applies a KalenderThemeData to the calendars below it.
- KalenderThemeData Appearance
- The calendar's visual theme, following the same layering as Flutter's own component themes.
- MonthBodyComponents Appearance
- The component builders used by the MonthBody.
- MonthComponents Appearance
- A class containing custom widget builders for the MonthBody and MonthHeader.
- MonthDayCell Appearance
- Renders the background of a single day cell in the month body.
- MonthDayCellDetails Appearance
- Details describing a single day cell, passed to a MonthDayCellBuilder.
- MonthDayHeader Appearance
- A widget that displays the day number.
- MonthDayHeaderStyle Appearance
- The style of the MonthDayHeader.
- MonthGrid Appearance
- A widget that displays the month grid.
- MonthGridStyle Appearance
- The MonthGridStyle class is used by the MonthGrid widget.
- MonthHeaderComponents Appearance
- The component builders used by the MonthHeader.
- MultiDayBodyComponents Appearance
- The component builders used by the MultiDayBody.
- MultiDayComponents Appearance
- A class containing custom widget builders for the MultiDayBody and MultiDayHeader.
- MultiDayEventOverlayTile Appearance
- MultiDayHeaderComponents Appearance
- The component builders used by the MultiDayHeader.
- MultiDayOverlay Appearance
- MultiDayOverlayPortal Appearance
- A widget that manages the overlay portal for a single day.
- MultiDayOverlayStyle Appearance
- MultiDayPortalOverlayButton Appearance
- MultiDayPortalOverlayButtonStyle Appearance
- OverlayBuilders Appearance
- Builders used to create the overlayPortal, overlay and overlay button widgets.
- ResizeHandleStyle Appearance
- The style of the resize handles laid out by DefaultResizeHandles.
- ScheduleComponents Appearance
-
A class containing custom widget builders for the
ScheduleBody. - ScheduleDate Appearance
- A widget that displays the name of the day and the day number of the week.
- ScheduleDateStyle Appearance
- The style of the ScheduleDate.
- ScheduleTileComponents Appearance
- The components used by the ScheduleBody to render the event tiles.
- ScheduleTileHighlight Appearance
- A widget that highlights the list item if the date is within the given range.
- ScheduleTileHighlightStyle Appearance
- TileComponents Appearance
- The components used by the MultiDayBody/MonthBody to render the event tiles.
- TimeIndicator Appearance
- A widget that displays the current time as a line and a circle.
- TimeIndicatorStyle Appearance
- The style of the TimeIndicator widget.
- TimeLine Appearance
- A widget that displays a list of times based on the timeOfDayRange and heightPerMinute.
- TimelineStyle Appearance
- The style of the TimeLine widget.
- WeekDayHeader Appearance
- A widget that displays the name of the day of the week.
- WeekDayHeaderStyle Appearance
- The WeekDayHeaderStyle class is used by the default WeekDayHeader widget.
- WeekNumber Appearance
- A widget that displays the week number.
- WeekNumberStyle Appearance
- The style of the WeekNumber.
Mixins
- DayEventTileUtils Appearance
- A mixin that provides useful utilities for day-based event tiles.
- EventTileUtils Appearance
- MultiDayEventTileUtils Appearance
- A mixin that provides useful utilities for multi-day event tiles.
- TimeLineUtils Appearance
- A mixin that provides utility methods for the TimeLine and HourLines widget.
Extensions
- KalenderLocale on BuildContext Appearance
- Gives a string builder access to the locale of the calendar it is building for.
Constants
- kDefaultWeekNumberWidth → const double Appearance
- The width defaultWeekNumberWidth returns when the style sets none.
Functions
-
defaultTimelineWidth(
BuildContext context, KalenderTimeRange timeOfDayRange) → double Appearance - The default TimelineWidthBuilder.
-
defaultWeekNumberWidth(
BuildContext context) → double Appearance - The default WeekNumberWidthBuilder.
Typedefs
- DateStringBuilder = String Function(BuildContext context, DateTime date) Appearance
-
Builds the text displayed for
date. - DayHeaderBuilder = Widget Function(BuildContext context, DateTime date) Appearance
- The day header builder.
- DaySeparatorBuilder = Widget Function(BuildContext context) Appearance
- The day separator builder.
- EmptyItemBuilder = Widget Function(BuildContext context, KalenderDateTimeRange tileRange) Appearance
- The builder for the empty item.
- FeedbackTileBuilder = Widget Function(BuildContext context, KalenderEvent event, Size dropTargetWidgetSize) Appearance
- The builder for the feedback tile. (When dragging)
- HiddenEventCountStringBuilder = String Function(BuildContext context, int numberOfHiddenEvents) Appearance
- Builds the text displayed on the overlay button that opens the hidden events.
- HourLinesBuilder = Widget Function(BuildContext context, double heightPerMinute, KalenderTimeRange timeOfDayRange) Appearance
- The hour lines builder.
- KalenderTimeStringBuilder = String Function(BuildContext context, KalenderTime time) Appearance
-
Builds the text displayed for
time. - MonthDayCellBuilder = Widget Function(BuildContext context, MonthDayCellDetails details) Appearance
- Builds the background of a single day cell in the month body.
- MonthDayHeaderBuilder = Widget Function(BuildContext context, DateTime date) Appearance
- The month day header builder.
- MonthGridBuilder = Widget Function(BuildContext context, int numberOfRows) Appearance
- The month grid builder.
- MonthItemBuilder = Widget Function(BuildContext context, KalenderDateTimeRange tileRange) Appearance
- The builder for the month item.
-
MultiDayOverlayBuilder
= Widget Function(BuildContext context, {required DateTime date, required List<
KalenderEvent> events, required RenderBoxCallback getMultiDayEventLayoutRenderBox, required RenderBoxCallback getOverlayPortalRenderBox, required MultiDayOverlayEventTileBuilder overlayTileBuilder, required OverlayPortalController portalController, required double tileHeight}) Appearance - A function that returns a MultiDayOverlay widget.
- MultiDayOverlayEventTileBuilder = MultiDayEventOverlayTile Function(BuildContext context, KalenderEvent event, FloatingDateTimeRange floatingRange, VoidCallback dismissOverlay) Appearance
- A function that returns a MultiDayEventOverlayTile for the multi-day overlay.
-
MultiDayOverlayPortalBuilder
= Widget Function(BuildContext context, {required DateTime date, required List<
KalenderEvent> events, required RenderBoxCallback getMultiDayEventLayoutRenderBox, required int numberOfHiddenRows, required OverlayBuilders? overlayBuilders, required MultiDayOverlayEventTileBuilder overlayTileBuilder, required double tileHeight}) Appearance - A function that returns a MultiDayOverlayPortal.
- MultiDayPortalOverlayButtonBuilder = Widget Function(BuildContext context, OverlayPortalController portalController, int numberOfHiddenRows) Appearance
- The builder used to create the button for the MultiDayPortalOverlayButton.
- ScheduleDateBuilder = Widget Function(BuildContext context, FloatingDateTime date) Appearance
- The day header builder.
-
ScheduleTileHighlightBuilder
= Widget Function(BuildContext context, FloatingDateTime date, ValueNotifier<
FloatingDateTimeRange?> range, Widget child) Appearance - The schedule tile highlight builder.
- TileBuilder = Widget Function(BuildContext context, KalenderEvent event, KalenderDateTimeRange tileRange) Appearance
- The default builder for the event tiles.
- TileDropTargetBuilder = Widget Function(BuildContext context, KalenderEvent event) Appearance
- The builder for the drop target event tile.
- TileWhenDraggingBuilder = Widget Function(BuildContext context, KalenderEvent event) Appearance
- The builder for the event tile when dragging.
- TimeIndicatorBuilder = Widget Function(BuildContext context, KalenderTimeRange timeOfDayRange, double heightPerMinute, Location? location) Appearance
- The time indicator builder.
-
TimeLineBuilder
= Widget Function(BuildContext context, double heightPerMinute, KalenderTimeRange timeOfDayRange, ValueNotifier<
KalenderEvent?> eventBeingDragged, ValueNotifier<KalenderDateTimeRange?> visibleDateTimeRange) Appearance - The time line builder.
- TimelineWidthBuilder = double Function(BuildContext context, KalenderTimeRange timeOfDayRange) Appearance
- Resolves the width of the timeline gutter.
- WeekDayHeaderBuilder = Widget Function(BuildContext context, DateTime date) Appearance
- The week day header builder.
- WeekNumberBuilder = Widget Function(BuildContext context, KalenderDateTimeRange visibleDateTimeRange) Appearance
- The week number builder.
- WeekNumberWidthBuilder = double Function(BuildContext context) Appearance
- The width of the month's week number column.