SwipeTrap
A SwipeTrap is a component that traps swipe actions and triggers corresponding events.
Usage
Basic
Try swipe or drag on the container:
StartX: 
                    StartY: 
                    DiffX: 
                    DiffY: 
                    ---
                    Triggered? False
                    Trigger direction: 
                    Trigger diffX: 
                    Trigger diffY: 
<style> .basic-container { width: 100%; cursor: grab; height: 500px; display: flex; user-select: none; align-items: center; flex-direction: column; justify-content: center; border: 1px solid lightgray; } </style> <BitSwipeTrap Throttle="10" OnStart="HandleOnStartBasic" OnMove="HandleOnMoveBasic" OnEnd="HandleOnEndBasic" OnTrigger="HandleOnTriggerBasic"> <div class="basic-container"> <div>StartX: @swipeTrapEventArgs?.StartX</div> <div>StartY: @swipeTrapEventArgs?.StartY</div> <div>DiffX: @swipeTrapEventArgs?.DiffX</div> <div>DiffY: @swipeTrapEventArgs?.DiffY</div> <div>---</div> <div>Triggered? @isTriggered</div> <div>Trigger direction: <b>@swipeTrapTriggerArgs?.Direction</b></div> <div>Trigger diffX: @swipeTrapTriggerArgs?.DiffX</div> <div>Trigger diffY: @swipeTrapTriggerArgs?.DiffY</div> </div> </BitSwipeTrap>@code { private bool isTriggeredBasic; BitSwipeTrapEventArgs? swipeTrapEventArgsBasic; BitSwipeTrapTriggerArgs? swipeTrapTriggerArgsBasic; private void HandleOnStartBasic(BitSwipeTrapEventArgs args) { swipeTrapEventArgsBasic = args; } private void HandleOnMoveBasic(BitSwipeTrapEventArgs args) { swipeTrapEventArgsBasic = args; } private void HandleOnEndBasic(BitSwipeTrapEventArgs args) { swipeTrapEventArgsBasic = args; } private void HandleOnTriggerBasic(BitSwipeTrapTriggerArgs args) { isTriggeredBasic = true; swipeTrapTriggerArgsBasic = args; _ = Task.Delay(2000).ContinueWith(_ => { isTriggeredBasic = false; swipeTrapEventArgsBasic = null; swipeTrapTriggerArgsBasic = null; InvokeAsync(StateHasChanged); }); } }
Panel
Open the panel and try to close it by swiping it to the left:
Title
Item1
                            Item2
                            Item3
<style> .panel-container { width: 100%; height: 300px; overflow: hidden; user-select: none; position: relative; border: 1px solid lightgray; } .panel-container button { padding: 0.5rem; } .panel-container .panel { left: 0; color: black; width: 200px; cursor: grab; inset-block: 0; position: absolute; background-color: lightgray; transform: translateX(-100%); } .panel-container .panel.open { transform: translateX(0); } .panel-container .panel-trap { gap: 1rem; height: 100%; display: flex; flex-direction: column; background-color: gray; } </style> <div class="panel-container"> <button @onclick="OpenPanel"> Open </button> <div class="panel@(isPanelOpen ? " open": "")" style="@GetPanelStyle()"> <button @onclick="ClosePanel" style="position:absolute;top:0;right:0"> Close </button> <BitSwipeTrap Style="width:100%;height:100%" OnMove="HandleOnMovePanel" OnEnd="HandleOnEndPanel" OnTrigger="HandleOnTriggerPanel"> <div class="panel-trap"> <h3>Title</h3> <div>Item1</div> <div>Item2</div> <div>Item3</div> </div> </BitSwipeTrap> </div> </div>@code { private decimal diffXPanel; private bool isPanelOpen; private void OpenPanel() { isPanelOpen = true; } private void ClosePanel() { isPanelOpen = false; } private void HandleOnMovePanel(BitSwipeTrapEventArgs args) { diffXPanel = args.DiffX; } private void HandleOnEndPanel(BitSwipeTrapEventArgs args) { diffXPanel = 0; } private void HandleOnTriggerPanel(BitSwipeTrapTriggerArgs args) { if (args.Direction == BitSwipeDirection.Left) { diffXPanel = 0; ClosePanel(); } } private string GetPanelStyle() { return diffXPanel < 0 ? $"transform: translateX({diffXPanel}px)" : ""; } }
List
Swipe each row to the right to trigger the delete action:
Delete
                        Item1
Delete
                        Item2
Delete
                        Item3
Delete
                        Item4
Delete
                        Item5
Delete
                        Item6
Delete
                        Item7
Delete
                        Item8
Delete
                        Item9
Delete
                        Item10
<style> .list-container { gap: 4px; width: 100%; color: black; height: 300px; display: flex; overflow-y: auto; user-select: none; overflow-x: hidden; position: relative; flex-direction: column; border: 1px solid lightgray; } .list-container .row { min-height: 40px; position: relative; } .list-container .delete { width: 60px; color: white; height: 100%; padding: 4px; position: absolute; background-color: red; } .list-container .row-trap { width: 100%; height: 100%; cursor: grab; padding: 4px; position: absolute; background-color: gray; } </style> <div class="list-container"> @foreach (int idx in itemsList) { var i = idx; <div @key="@i" class="row"> <div class="delete">Delete</div> <BitSwipeTrap Style="width:100%;height:100%" Trigger="60m" Threshold="10" OnMove="args => HandleOnMoveList(args, i)" OnEnd="args => HandleOnEndList(args, i)" OnTrigger="args => HandleOnTriggerList(args, i)"> <div class="row-trap" style="@GetRowStyle(i)"> <div>Item@(i + 1)</div> </div> </BitSwipeTrap> </div> } </div> <BitButton OnClick="ResetList">Reset</BitButton> <BitDialog @bind-IsOpen="isListDialogOpen" Title="Delete item?" Message="Are you sure you want to delete this item?" OnOk="HandleOnOkList" OnCancel="HandleOnCancelList" />@code { private int deletingIndex = -1; private bool isListDialogOpen; private TaskCompletionSource listTcs; private List<int> itemsList = Enumerable.Range(0, 10).ToList(); private decimal[] diffXList = Enumerable.Repeat(0m, 10).ToArray(); private void HandleOnMoveList(BitSwipeTrapEventArgs args, int index) { diffXList[index] = args.DiffX; } private void HandleOnEndList(BitSwipeTrapEventArgs args, int index) { if (diffXList[index] < 60) { diffXList[index] = 0; } } private async Task HandleOnTriggerList(BitSwipeTrapTriggerArgs args, int index) { if (args.Direction == BitSwipeDirection.Right) { deletingIndex = index; listTcs = new(); isListDialogOpen = true; await listTcs.Task; isListDialogOpen = false; diffXList[index] = 0; deletingIndex = -1; } } private string GetRowStyle(int index) { var x = Math.Min(diffXList[index], 60); return x > 0 ? $"transform: translateX({x}px)" : ""; } private void HandleOnOkList() { if (deletingIndex != -1) { itemsList.Remove(deletingIndex); } listTcs.SetResult(); } private void HandleOnCancelList() { listTcs.SetResult(); } private void ResetList() { itemsList = Enumerable.Range(0, 10).ToList(); } }
Advanced
An illustrative example of integrating this component into a straightforward mobile application.
            bit BlazorUI
Swipe left or right
Left Menu
Item1
                                        Item2
                                        Item3
Right Menu
Item1
                                        Item2
                                        Item3
<style> .mobile-frame { height: 666px; max-width: 375px; overflow: hidden; position: relative; border-radius: 36px; border: 16px solid #333; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); background-color: var(--bit-clr-fg-sec); } .mobile-frame .screen { width: 100%; height: 100%; } .mobile-frame .layout { height: 100%; display: flex; flex-direction: column; } .mobile-frame .header { gap: 1rem; width: 100%; height: 66px; display: flex; align-items: center; justify-content: center; background-color: var(--bit-clr-bg-sec); } .mobile-frame .main { flex-grow: 1; position: relative; } .mobile-frame .main-text { height: 100%; display: flex; align-items: center; justify-content: center; } .mobile-frame .panel { color: black; cursor: grab; inset-block: 0; user-select: none; position: absolute; background-color: lightgray; .mobile-frame .panel.left { left: 0; width: 200px; transform: translateX(-100%); } .mobile-frame .panel.right { right: 0; width: 200px; transform: translateX(100%); } .mobile-frame .panel-trap { gap: 1rem; height: 100%; display: flex; padding-top: 0.2rem; padding-left: 0.8rem; flex-direction: column; background-color: gray; } </style> <div class="mobile-frame"> <div class="screen"> <div class="layout"> <div class="header"> <BitImage Src="/images/bit-logo.svg" Width="50" /> <BitText Typography="BitTypography.H4" Color="BitColor.Info"> bit BlazorUI </BitText> </div> <div class="main"> <BitSwipeTrap Style="width:100%;height:100%" OnMove="HandleOnMovePanelAdvanced" OnEnd="HandleOnEndPanelAdvanced" OnTrigger="HandleOnTriggerPanelAdvanced"> <div class="main-text"> <BitText Style="user-select:none" Typography="BitTypography.H4" Color="BitColor.SecondaryBackground"> Swipe left or right </BitText> </div <div class="panel left" style="@GetLeftPanelAdvancedStyle()"> <div class="panel-trap"> <h3>Left Menu</h3> <div>Item1</div> <div>Item2</div> <div>Item3</div> </div> </div> <div class="panel right" style="@GetRightPanelAdvancedStyle()"> <div class="panel-trap"> <h3>Right Menu</h3> <div>Item1</div> <div>Item2</div> <div>Item3</div> </div> </div> </BitSwipeTrap> </div> </div> </div> </div>@code { private decimal? diffXPanelAdvanced; private BitSwipeDirection? direction; private BitSwipeDirection? panelOpen; private void OpenPanelAdvanced(BitSwipeDirection swipeDirection) { if (panelOpen == swipeDirection) return; direction = null; panelOpen = swipeDirection; diffXPanelAdvanced = 0; } private void ClosePanelAdvanced() { panelOpen = null; diffXPanelAdvanced = null; } private void HandleOnMovePanelAdvanced(BitSwipeTrapEventArgs args) { diffXPanelAdvanced = args.DiffX; if (Math.Abs(args.DiffX) > 2 || Math.Abs(args.DiffY) > 2) { direction = Math.Abs(args.DiffX) > Math.Abs(args.DiffY) ? args.DiffX > 0 ? BitSwipeDirection.Right : BitSwipeDirection.Left : args.DiffY > 0 ? BitSwipeDirection.Bottom : BitSwipeDirection.Top; } else { direction = null; } } private void HandleOnEndPanelAdvanced(BitSwipeTrapEventArgs args) { if (panelOpen.HasValue) { diffXPanelAdvanced = 0; } else { diffXPanelAdvanced = null; } } private void HandleOnTriggerPanelAdvanced(BitSwipeTrapTriggerArgs args) { if (args.Direction == BitSwipeDirection.Left) { if (panelOpen.HasValue is false || panelOpen == BitSwipeDirection.Right) { OpenPanelAdvanced(BitSwipeDirection.Right); } else if (panelOpen == BitSwipeDirection.Left) { ClosePanelAdvanced(); } } else if (args.Direction == BitSwipeDirection.Right) { if (panelOpen.HasValue is false || panelOpen == BitSwipeDirection.Left) { OpenPanelAdvanced(BitSwipeDirection.Left); } else if (panelOpen == BitSwipeDirection.Right) { ClosePanelAdvanced(); } } } private string GetLeftPanelAdvancedStyle() { if (panelOpen == BitSwipeDirection.Left && direction != BitSwipeDirection.Left) { return "transform: translateX(0px)"; } else if((panelOpen.HasValue is false && direction == BitSwipeDirection.Right) || (panelOpen == BitSwipeDirection.Left && direction == BitSwipeDirection.Left)) { return diffXPanelAdvanced switch { 0 or > 200 => "transform: translateX(0px)", < 0 and < 200 => $"transform: translateX({diffXPanelAdvanced}px)", > 0 => $"transform: translateX(calc(-100% + {diffXPanelAdvanced}px))", _ => string.Empty }; } return string.Empty; } private string GetRightPanelAdvancedStyle() { if (panelOpen == BitSwipeDirection.Right && direction != BitSwipeDirection.Right) { return "transform: translateX(0px)"; } else if ((panelOpen.HasValue is false && direction == BitSwipeDirection.Left) || (panelOpen == BitSwipeDirection.Right && direction == BitSwipeDirection.Right)) { return diffXPanelAdvanced switch { 0 or < -200 => "transform: translateX(0px)", > 0 => $"transform: translateX({diffXPanelAdvanced}px)", < 0 => $"transform: translateX(calc(100% - {(-1 * diffXPanelAdvanced)}px))", _ => string.Empty }; } return string.Empty; } }
API
BitSwipeTrap parameters
| Name | Type | Default value | Description | 
|---|---|---|---|
| ChildContent | RenderFragment? | null | The content of the swipe trap. | 
| OnStart | EventCallback<BitSwipeTrapEventArgs> | The event callback for when the swipe action starts on the container of the swipe trap. | |
| OnMove | EventCallback<BitSwipeTrapEventArgs> | The event callback for when the swipe action moves on the container of the swipe trap. | |
| OnEnd | EventCallback<BitSwipeTrapEventArgs> | The event callback for when the swipe action ends on the container of the swipe trap. | |
| OnTrigger | EventCallback<BitSwipeTrapTriggerArgs> | The event callback for when the swipe action triggers based on the Trigger constraint. | |
| OrientationLock | BitSwipeOrientation? | null | Specifies the orientation lock in which the swipe trap allows to trap the swipe actions. | 
| Threshold | decimal? | null | The threshold in pixel for swiping distance that starts the swipe process process which stops the default behavior. | 
| Throttle | int? | null | The throttle time in milliseconds to apply a delay between periodic calls to raise the events (default is 10). | 
| Trigger | decimal? | null | The swiping point (fraction of element's width or an absolute value) to trigger and call the OnTrigger event (default is 0.25m). | 
BitComponentBase parameters
| Name | Type | Default value | Description | 
|---|---|---|---|
| AriaLabel | string? | null | The aria-label of the control for the benefit of screen readers. | 
| Class | string? | null | Custom CSS class for the root element of the component. | 
| Dir | BitDir? | null | Determines the component direction. | 
| HtmlAttributes | Dictionary<string, object> | new Dictionary<string, object>() | Capture and render additional attributes in addition to the component's parameters. | 
| Id | string? | null | Custom id attribute for the root element. if null the UniqueId will be used instead. | 
| IsEnabled | bool | true | Whether or not the component is enabled. | 
| Style | string? | null | Custom CSS style for the root element of the component. | 
| Visibility | BitVisibility | BitVisibility.Visible | Whether the component is visible, hidden or collapsed. | 
BitComponentBase public members
| Name | Type | Default value | Description | 
|---|---|---|---|
| UniqueId | Guid | Guid.NewGuid() | The readonly unique id of the root element. it will be assigned to a new Guid at component instance construction. | 
| RootElement | ElementReference | The ElementReference of the root element. | 
BitSwipeTrapEventArgs properties
The event arguments of the SwipeTrap events.
| Name | Type | Default value | Description | 
|---|---|---|---|
| StartX | decimal | 0 | The horizontal start point of the swipe action in pixels. | 
| StartY | decimal | 0 | The vertical start point of the swipe action in pixels. | 
| DiffX | decimal | 0 | The horizontal difference of swipe action in pixels. | 
| DiffY | decimal | 0 | The vertical difference of swipe action in pixels. | 
BitSwipeTrapTriggerArgs properties
The event arguments of the SwipeTrap trigger event.
| Name | Type | Default value | Description | 
|---|---|---|---|
| Direction | BitSwipeDirection | The swipe direction in which the action triggered. | |
| DiffX | decimal | 0 | The horizontal difference of swipe action in pixels. | 
| DiffY | decimal | 0 | The vertical difference of swipe action in pixels. | 
BitSwipeOrientation enum
| Name | Value | Description | 
|---|---|---|
| None | 0 | Not orientation lock for swipe trap. | 
| Horizontal | 1 | Horizontal orientation lock of trapping the swipe action. | 
| Vertical | 2 | Vertical orientation lock of trapping the swipe action. | 
BitSwipeDirection enum
| Name | Value | Description | 
|---|---|---|
| Right | 0 | Swipe to right direction. | 
| Left | 1 | Swipe to left direction. | 
| Top | 2 | Swipe to top direction. | 
| Bottom | 3 | Swipe to bottom direction. | 
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. | 
Feedback
You can give us your feedback through our GitHub repo by filing a new Issue or starting a new Discussion.
Or you can review / edit this page on GitHub.
Or you can review / edit this component on GitHub.
- On this page