Skip to content
# PullToRefresh ## Description The PullToRefresh component adds the pull down to refresh gesture to a page or any scrollable element. It engages only while the scroller sits at its top, damps the pull so it feels like weight rather than a drag, and holds an indicator open until the work is done - by touch, by mouse, or from code. ## Parameters | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | Anchor | `RenderFragment?` | null | The anchor element that the pull to refresh component adheres to (alias of ChildContent). | | ChildContent | `RenderFragment?` | null | The anchor element that the pull to refresh component adheres to. | | Classes | `BitPullToRefreshClassStyles?` | null | Custom CSS classes for different parts of the BitPullToRefresh. | | Color | `BitColor?` | null | The general color of the pull indicator. It colors the glyph inside the indicator's disc, which the pull, the refresh and the complete states all draw. | | Complete | `RenderFragment?` | null | The custom template to replace the default checkmark svg shown while the complete state is visible. | | CompleteDelay | `int` | 0 | The duration in milliseconds to keep the complete indicator visible after a successful refresh before snapping back (0 disables the complete state). | | CompleteLabel | `string` | Refresh complete | The text that gets announced to screen readers while the complete state is visible after a successful refresh. | | CustomColor | `string?` | null | The custom css color of the pull indicator. It only applies while Color is left unset. | | Factor | `decimal` | 1.5 | The factor to balance the pull height out. The pull-down distance gets divided by it, so higher values make the pull feel heavier. Values below 0.1 are treated as 0.1. | | FullWidth | `bool` | false | Whether the component takes the whole width of its container instead of shrink-wrapping its anchor. | | Loading | `RenderFragment?` | null | The custom loading template to replace the default loading svg. It is what the indicator shows while the pull is under way and while the refresh is running, so it covers every state that Release and Complete do not take over. | | Margin | `int` | 30 | The value in pixel to add to the top of pull element as a margin for the pull height. | | MaxPull | `int` | 0 | The furthest the pull can travel, in pixels, past which it stops following the finger; 0 stops it at Trigger. The indicator holds its full size over that stretch, and only the strip keeps growing. It is measured on the same damped scale as Trigger. | | OnRefresh | `EventCallback` | | The callback for when the trigger condition of the pull-down happens. | | OnPullStart | `EventCallback<BitPullToRefreshPullStartArgs>` | | The callback for the starting of the pull-down. | | OnPullMove | `EventCallback<decimal>` | | The callback for when the pull-down is in progress, reporting the pull height in pixels, which is capped at Trigger - or at MaxPull where the pull is allowed past it. The reports are coalesced to at most one per frame and never repeat a whole pixel. | | OnPullEnd | `EventCallback<decimal>` | | The callback for the ending of the pull-down. | | OnPullCancel | `EventCallback<decimal>` | | The callback for when the pull-down gets canceled before release, providing the last pull height. | | RefreshingLabel | `string` | Refreshing | The text that gets announced to screen readers while the refresh is in progress. | | Release | `RenderFragment?` | null | The custom template to replace the default svg while the pull has passed the trigger and releasing starts the refresh. | | ReleaseLabel | `string` | Release to refresh | The text that gets announced to screen readers while the pull has passed the trigger and releasing starts the refresh. An empty string leaves the release state unannounced. | | ScrollerElement | `ElementReference?` | null | The element that is the scroller in the anchor to control the behavior of the pull to refresh. | | ScrollerSelector | `string?` | null | The CSS selector of the element that is the scroller in the anchor to control the behavior of the pull to refresh. It is looked up inside the anchor first and in the document afterwards; left unset, the first element of the anchor is taken as the scroller. | | Styles | `BitPullToRefreshClassStyles?` | null | Custom CSS styles for different parts of the BitPullToRefresh. | | Threshold | `int` | 0 | The dead-zone distance in pixel that the pull-down must travel before the pull to refresh process starts and the indicator appears. | | Trigger | `int` | 80 | The pulling height in pixel that triggers the refresh. It is also the distance the indicator grows to its full size over. Values below 1 are treated as 1. | | AriaLabel | `string?` | null | Gets or sets the accessible label for the component, used by assistive technologies. | | Class | `string?` | null | Gets or sets the CSS class name(s) to apply to the rendered element. | | Dir | `BitDir?` | null | Gets or sets the text directionality for the component's content. | | ForceAnimation | `bool` | false | Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested. | | HtmlAttributes | `Dictionary<string, object>` | new Dictionary<string, object>() | Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters. | | Id | `string?` | null | Gets or sets the unique identifier for the component's root element. | | IsEnabled | `bool` | true | Gets or sets a value indicating whether the component is enabled and can respond to user interaction. | | Style | `string?` | null | Gets or sets the CSS style string to apply to the rendered element. | | TabIndex | `string?` | null | Gets or sets the tab order index for the component when navigating with the keyboard. | | Visibility | `BitVisibility` | BitVisibility.Visible | Gets or sets the visibility state (visible, hidden, or collapsed) of the component. | ## Public Members | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | IsRefreshing | `bool` | false | Whether a refresh is currently running - the pull was released past the trigger, or RefreshAsync was called, and the OnRefresh callback has not returned yet. | | PullProgress | `decimal` | 0 | How far the current pull has come as a fraction of Trigger: 0 while nothing is being pulled, and 1 once releasing would start a refresh. It reads 1 for the whole of a refresh. | | RefreshAsync | `Task` | | Starts the refresh process programmatically, showing the loading indicator and invoking the OnRefresh callback. It has no effect while the component is disabled, a refresh is already in progress or the complete state is visible. | | UniqueId | `Guid` | Guid.NewGuid() | Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed. | | RootElement | `ElementReference` | | Gets the reference to the root HTML element associated with this component. | ## Enums ### BitColor Enum | Name | Value | Description | | :--- | :--- | :---------- | | Primary | 0 | Info Primary general color. | | Secondary | 1 | Secondary general color. | | Tertiary | 2 | Tertiary general color. | | Info | 3 | Info general color. | | Success | 4 | Success general color. | | Warning | 5 | Warning general color. | | SevereWarning | 6 | SevereWarning general color. | | Error | 7 | Error general color. | | PrimaryBackground | 8 | Primary background color. | | SecondaryBackground | 9 | Secondary background color. | | TertiaryBackground | 10 | Tertiary background color. | | PrimaryForeground | 11 | Primary foreground color. | | SecondaryForeground | 12 | Secondary foreground color. | | TertiaryForeground | 13 | Tertiary foreground color. | | PrimaryBorder | 14 | Primary border color. | | SecondaryBorder | 15 | Secondary border color. | | TertiaryBorder | 16 | Tertiary border color. | ### BitVisibility Enum | Name | Value | Description | | :--- | :--- | :---------- | | Visible | 0 | The content of the component is visible. | | Hidden | 1 | The content of the component is hidden, but the space it takes on the page remains (visibility:hidden). | | Collapsed | 2 | The component is hidden (display:none). | ### BitDir Enum | Name | Value | Description | | :--- | :--- | :---------- | | Ltr | 0 | Ltr (left to right) is to be used for languages that are written from the left to the right (like English). | | Rtl | 1 | Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic). | | Auto | 2 | Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element. | ## Sub Classes ### BitPullToRefreshPullStartArgs Properties | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | Top | `decimal` | | The top offset of the pull to refresh element in pixels. | | Left | `decimal` | | The left offset of the pull to refresh element in pixels. | | Width | `decimal` | | The width of the pull to refresh element in pixels. | ### BitPullToRefreshClassStyles Properties | Name | Type | Default Value | Description | | :--- | :--- | :------------ | :---------- | | Root | `string?` | null | Custom CSS classes/styles for the root element of the PullToRefresh. | | Loading | `string?` | null | Custom CSS classes/styles for the loading element. | | SpinnerWrapper | `string?` | null | Custom CSS classes/styles for the spinner wrapper element. | | SpinnerWrapperCanRelease | `string?` | null | Custom CSS classes/styles for the spinner wrapper element when the pull passed the trigger and releasing starts the refresh. | | SpinnerWrapperRefreshing | `string?` | null | Custom CSS classes/styles for the spinner wrapper element in refreshing mode. | | SpinnerWrapperComplete | `string?` | null | Custom CSS classes/styles for the spinner wrapper element while the complete state is visible after a successful refresh. | | Spinner | `string?` | null | Custom CSS classes/styles for the spinner element. | | SpinnerCanRelease | `string?` | null | Custom CSS classes/styles for the spinner element when the pull passed the trigger and releasing starts the refresh. | | SpinnerRefreshing | `string?` | null | Custom CSS classes/styles for the spinner element in refreshing mode. | | SpinnerComplete | `string?` | null | Custom CSS classes/styles for the spinner element while the complete state is visible after a successful refresh. | ## Examples \n**Basic**: ```razor
@foreach (var (idx, i) in basicItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
``` ```csharp private (int, int)[] basicItems = GenerateRandomNumbers(1, 51); private async Task HandleOnRefreshBasic() { await Task.Delay(2000); basicItems = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ``` \n**Custom loading**: ```razor
@foreach (var (idx, i) in customItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
``` ```csharp private (int, int)[] customItems = GenerateRandomNumbers(1, 51); private async Task HandleOnRefreshCustom() { await Task.Delay(2000); customItems = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ``` \n**Multiple**: ```razor
@foreach (var (idx, i) in multiItems1) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
@foreach (var (idx, i) in multiItems2) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
``` ```csharp private (int, int)[] multiItems1 = GenerateRandomNumbers(0, 50); private async Task HandleOnRefresh1() { await Task.Delay(2000); multiItems1 = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private (int, int)[] multiItems2 = GenerateRandomNumbers(51, 101); private async Task HandleOnRefresh2() { await Task.Delay(2000); multiItems2 = GenerateRandomNumbers(51, 101); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ``` \n**Advanced**: ```razor
BlazorUI
@foreach (var (idx, i) in advancedItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
``` ```csharp private (int, int)[] advancedItems = GenerateRandomNumbers(1, 51); private async Task HandleOnRefreshAdvanced() { await Task.Delay(2000); advancedItems = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ``` \n**Disabled**: ```razor
@foreach (var (idx, i) in disabledItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
``` ```csharp private bool isEnabled = true; private (int, int)[] disabledItems = GenerateRandomNumbers(1, 51); private async Task HandleOnRefreshDisabled() { await Task.Delay(2000); disabledItems = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ``` \n**Behavior**: ```razor
@foreach (var (idx, i) in behaviorItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}




``` ```csharp private double trigger = 80; private double factor = 1.5; private double margin = 30; private double threshold = 0; private double maxPull = 0; private (int, int)[] behaviorItems = GenerateRandomNumbers(1, 51); private async Task HandleOnRefreshBehavior() { await Task.Delay(2000); behaviorItems = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ``` \n**Programmatic refresh**: ```razor Refresh
@foreach (var (idx, i) in programmaticItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
``` ```csharp private BitPullToRefresh pullToRefreshRef = default!; private (int, int)[] programmaticItems = GenerateRandomNumbers(1, 51); private async Task RefreshProgrammatically() { await pullToRefreshRef.RefreshAsync(); } private async Task HandleOnRefreshProgrammatic() { await Task.Delay(2000); programmaticItems = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ``` \n**Events**: ```razor
@foreach (var (idx, i) in eventsItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
PullStart: @(pullStartArgs is null ? "-" : $"top:{pullStartArgs.Top:F0}, left:{pullStartArgs.Left:F0}, width:{pullStartArgs.Width:F0}")
PullMove diff: @pullMoveDiff.ToString("F1")
PullEnd diff: @pullEndDiff.ToString("F1")
PullCancel diff: @pullCancelDiff.ToString("F1")
Refresh count: @refreshCount
``` ```csharp private int refreshCount; private decimal pullMoveDiff; private decimal pullEndDiff; private decimal pullCancelDiff; private BitPullToRefreshPullStartArgs? pullStartArgs; private (int, int)[] eventsItems = GenerateRandomNumbers(1, 51); private void HandleOnPullStart(BitPullToRefreshPullStartArgs args) { pullStartArgs = args; } private void HandleOnPullMove(decimal diff) { pullMoveDiff = diff; } private void HandleOnPullEnd(decimal diff) { pullEndDiff = diff; } private void HandleOnPullCancel(decimal diff) { pullCancelDiff = diff; } private async Task HandleOnRefreshEvents() { refreshCount++; await Task.Delay(2000); eventsItems = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ``` \n**Complete state**: ```razor
@foreach (var (idx, i) in completeItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
@foreach (var (idx, i) in completeCustomItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
🎉
``` ```csharp private (int, int)[] completeItems = GenerateRandomNumbers(1, 51); private async Task HandleOnRefreshComplete() { await Task.Delay(2000); completeItems = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private (int, int)[] completeCustomItems = GenerateRandomNumbers(51, 101); private async Task HandleOnRefreshCompleteCustom() { await Task.Delay(2000); completeCustomItems = GenerateRandomNumbers(51, 101); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ``` \n**Release state**: ```razor
@foreach (var (idx, i) in releaseItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
``` ```csharp private (int, int)[] releaseItems = GenerateRandomNumbers(1, 51); private async Task HandleOnRefreshRelease() { await Task.Delay(2000); releaseItems = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ``` \n**Color**: ```razor
@foreach (var (idx, i) in colorItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
@foreach (var (idx, i) in customColorItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
``` ```csharp private (int, int)[] colorItems = GenerateRandomNumbers(1, 51); private async Task HandleOnRefreshColor() { await Task.Delay(2000); colorItems = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private (int, int)[] customColorItems = GenerateRandomNumbers(51, 101); private async Task HandleOnRefreshCustomColor() { await Task.Delay(2000); customColorItems = GenerateRandomNumbers(51, 101); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ``` \n**Style & Class**: ```razor
@foreach (var (idx, i) in styleItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
@foreach (var (idx, i) in classItems) {
@(idx.ToString().PadLeft(2, '0')). Item @i
}
``` ```csharp private (int, int)[] styleItems = GenerateRandomNumbers(1, 51); private async Task HandleOnRefreshStyle() { await Task.Delay(2000); styleItems = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private (int, int)[] classItems = GenerateRandomNumbers(51, 101); private async Task HandleOnRefreshClass() { await Task.Delay(2000); classItems = GenerateRandomNumbers(51, 101); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ``` \n**RTL**: ```razor
@foreach (var (idx, i) in rtlItems) {
@(idx.ToString().PadLeft(2, '0')) .مورد @i
}
``` ```csharp private (int, int)[] rtlItems = GenerateRandomNumbers(1, 51); private async Task HandleOnRefreshRtl() { await Task.Delay(2000); rtlItems = GenerateRandomNumbers(1, 51); _ = Task.Delay(1000).ContinueWith(_ => InvokeAsync(StateHasChanged)); } private static (int, int)[] GenerateRandomNumbers(int min, int max) { var random = new Random(); return Enumerable.Range(min, max - min).Select(i => (i, random.Next(min, max))).ToArray(); } ```