Swipeout (Swipeable List)

Swipeout is an extension of list view that allows you to swipe over list elements to reveal hidden menu with available actions, like swipe-to-delete.

Swipeout Layout

Let's look on layout structure of swipeout element in your list views:

<div class="list">
  <ul>
    <!-- Additional "swipeout" class on li -->
    <li class="swipeout">
      <!-- Usual list element wrapped with "swipeout-content" -->
      <div class="swipeout-content">
        <!-- Your list element here -->
        <div class="item-content">
          <div class="item-media">...</div>
          <div class="item-inner">...</div>
        </div>
      </div>
      <!-- Swipeout actions left -->
      <div class="swipeout-actions-left">
        <!-- Swipeout actions links/buttons -->
        <a href="#">Action 1</a>
        <a href="#">Action 2</a>
      </div>
      <!-- Swipeout actions right -->
      <div class="swipeout-actions-right">
        <!-- Swipeout actions links/buttons -->
        <a href="#" class="swipeout-close">Action 1</a>
        <a href="#" class="swipeout-delete">Delete</a>
      </div>
    </li>
    ...
  </ul>
</div>

Where:

Note that swipeout-content and swipeout-actions-left/right should be direct children of <li>

If you have only "item-content" you can simplify layout by adding "item-content" class to "swipeout-content":

<li class="swipeout">
  <div class="swipeout-content item-content">
    <div class="item-media">...</div>
    <div class="item-inner">...</div>
  </div>
  <div class="swipeout-actions-right">
    <a href="#">Action 1</a>
    <a href="#">Action 2</a>
  </div>
</li>

If you use link items the layout will be following:

<li class="swipeout">
  <div class="swipeout-content">
    <a href="#" class="item-content item-link">
      <div class="item-media">...</div>
      <div class="item-inner">...</div>
    </a>
  </div>
  <div class="swipeout-actions-right">
    <a href="#">Action 1</a>
    <a href="#">Action 2</a>
  </div>
</li>

Swipe To Delete

Framework7 supports this frequently used feature from the box without single line of JavaScript. All you need is to add swipeout-delete class to swipeout actions buttons:

<li class="swipeout">
  <div class="swipeout-content item-content">
    <div class="item-media">...</div>
    <div class="item-inner">...</div>
  </div>
  <div class="swipeout-actions-right">
    <!-- Add this button and item will be deleted automatically -->
    <a href="#" class="swipeout-delete">Delete</a>
  </div>
</li>

It is also possible to call Confirm modal when user clicks on "Delete" button, and element will be removed only after confirmation. To make delete on confirmation you need to add additional data-confirm and data-confirm-title (optional) attributes to Delete link:

<li class="swipeout">
  <div class="swipeout-content item-content">
    <div class="item-media">...</div>
    <div class="item-inner">...</div>
  </div>
  <div class="swipeout-actions-right">
    <!-- We add data-confirm and data-confirm-title attributes -->
    <a href="#" class="swipeout-delete" data-confirm="Are you sure want to delete this item?" data-confirm-title="Delete?">Delete</a>
  </div>
</li>

Overswipe

Swipeouts also support "overswipe" actions that will be triggered automatically if you swipe actions too much. In this case we need to add swipeout-overswipe class to required actions button:

<li class="swipeout">
  <div class="swipeout-content item-content">
    <div class="item-media">...</div>
    <div class="item-inner">...</div>
  </div>
  <div class="swipeout-actions-right">
    <a href="#">More</a>
    <a href="#" class="swipeout-delete swipeout-overswipe">Delete</a>
    </div>
  </div>
</li>
  • overswipe can be used only on last button in right swipeout actions, and only on first button in left swipeout actions.

  • With overswipe, script will automatically trigger "click" event on overswipe button, so you need to add appropriate event listener to this button

  • Overswipe button will have additional swipeout-overswipe-active class during overswipe which you can use for additional styling of such state

<li class="swipeout">
  <div class="swipeout-content">
    <a href="#" class="item-content item-link">
      ...
    </a>
  </div>
  <div class="swipeout-actions-left">
    <a href="#" class="swipeout-overswipe bg-green reply">Reply</a>
    <a href="#" class="bg-blue forward">Forward</a>
  </div>
  <div class="swipeout-actions-right">
    <a href="#" class="mark bg-orange">Mark</a>
    <a href="#" class="swipeout-delete swipeout-overswipe">Delete</a>
  </div>
</li>

Swipeout App Methods

Swipeouts also has rich JavaScript API that allows you to control swipeout elements. Let's look on appropriate App's methods:

app.swipeout.open(el, side, callback) - reveal swipeout actions on specified element

  • el - HTMLElement or string (with CSS Selector) of list (<li>) element with "swipeout" class. Required
  • side - string (could be "left" or "right") swipeout actions to open. Should be specified if item has both left and right swipeout actions. Optional
  • callback - function - callback function will be executed after swipeout element completes its opening animation

app.swipeout.close(el, callback) - close swipeout actions on specified element

  • el - HTMLElement or string (with CSS Selector) of list (<li>) element with "swipeout" class. Required
  • callback - function - callback function will be executed after swipeout element completes its closing animation

app.swipeout.delete(el, callback) - delete specified swipeout element

  • el - HTMLElement or string (with CSS Selector) of list (<li>) element with "swipeout" class. Required
  • callback - function - callback function will be executed after swipeout element completes its delete animation right before it will be removed from DOM

app.swipeout.el - property. Currently opened swipeout HTMLElement. Or undefined if there is no opened swipeout element

Swipeout App Parameters

It is possible to configure global swipeout behavior on app initialisation by passing swipeout related paremeters under swipeout property.

ParameterTypeDefaultDescription
noFollowbooleanfalseFallback option for potentially better performance on old/slow devices. If you enable it, then swipeout item will not follow your finger during touch, it will be automatically opened/closed on swipe left/right.
removeElementsbooleantrueWhen disabled, then framework will not remove swipeout element from DOM on "swipeout-delete" click. Useful to enable if you use another library like Vue or React to manage (remove) swipeout items
removeElementsWithTimeoutbooleanfalseWhen enabled, then framework will remove swipeout element from DOM on "swipeout-delete" click after specified delay
removeElementsTimeoutnumber0Delay in ms to remove swipeout item if removeElementsWithTimeout is enabled.
overswipeRationumber1.2Defines how much/hard needed to swipe to trigger overswipe (defaults to 1.2)

To change these parameters we need to pass them on app init under swipeout property, for example:

var app = new Framework7({
  swipeout: {
    noFollow: true,
    removeElements: false
  }
});

Swipeout Events

Swipeout will fire the following DOM events and events on app instance:

DOM Events

EventTargetDescription
swipeoutSwipeout Element<li class="swipeout">Event will be triggered while you move swipeout element. event.detail contains current opening progress percentage
swipeout:openSwipeout Element<li class="swipeout">Event will be triggered when swipeout element starts its opening animation
swipeout:openedSwipeout Element<li class="swipeout">Event will be triggered after swipeout element completes its opening animation
swipeout:closeSwipeout Element<li class="swipeout">Event will be triggered when swipeout element starts its closing animation
swipeout:closedSwipeout Element<li class="swipeout">Event will be triggered after swipeout element completes its closing animation
swipeout:deleteSwipeout Element<li class="swipeout">Event will be triggered after swipeout element starts its delete animation
swipeout:deletedSwipeout Element<li class="swipeout">Event will be triggered after swipeout element completes its delete animation right before it will be removed from DOM
swipeout:overswipeenterSwipeout Element<li class="swipeout">Event will be triggered when overswipe enabled
swipeout:overswipeexitSwipeout Element<li class="swipeout">Event will be triggered when overswipe disabled

App Instance Events

Swipeout instance emit events on app instance.

EventTargetArgumentsDescription
swipeoutappprogressEvent will be triggered while you move swipeout element
swipeoutOpenappswipeoutElEvent will be triggered when swipeout element starts its opening animation
swipeoutOpenedappswipeoutElEvent will be triggered after swipeout element completes its opening animation
swipeoutCloseappswipeoutElEvent will be triggered when swipeout element starts its closing animation
swipeoutClosedappswipeoutElEvent will be triggered after swipeout element completes its closing animation
swipeoutDeleteappswipeoutElEvent will be triggered after swipeout element starts its delete animation
swipeoutDeletedappswipeoutElEvent will be triggered after swipeout element completes its delete animation right before it will be removed from DOM
swipeoutOverswipeEnterappswipeoutElEvent will be triggered when overswipe enabled
swipeoutOverswipeExitappswipeoutElEvent will be triggered when overswipe disabled

CSS Variables

Below is the list of related CSS variables (CSS custom properties).

:root {
  --f7-swipeout-delete-button-bg-color: #ff3b30;
  --f7-swipeout-button-text-color: #fff;
  --f7-swipeout-button-padding-vertical: 0px;
  --f7-swipeout-button-bg-color: rgba(0, 0, 0, 0.22);
}
:root .dark,
:root.dark {
  --f7-swipeout-button-bg-color: rgba(255, 255, 255, 0.55);
}
.ios {
  --f7-swipeout-button-padding-horizontal: 30px;
  --f7-swipeout-button-font-size: inherit;
  --f7-swipeout-button-font-weight: inherit;
}
.md {
  --f7-swipeout-button-padding-horizontal: 24px;
  --f7-swipeout-button-font-size: 14px;
  --f7-swipeout-button-font-weight: 500;
}
.md .dark,
.md.dark {
  --f7-swipeout-button-text-color: #000;
}

Examples

swipeout.html
<template>
  <div class="page">
    <div class="navbar">
      <div class="navbar-bg"></div>
      <div class="navbar-inner sliding">
        <div class="title">Swipeout</div>
      </div>
    </div>
    <div class="page-content">
      <div class="block">
        <p>
          Swipe out actions on list elements is one of the most awesome F7 features. It allows you to call hidden menu
          for each list element where you can put default ready-to use delete button or any other buttons for some
          required actions.
        </p>
      </div>
      <div class="block-title">Swipe to delete with confirm modal</div>
      <div class="list list-strong list-outline-ios list-dividers-ios inset-md">
        <ul>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media"><i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">Swipe left on me please</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a data-confirm="Are you sure you want to delete this item?" class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media"> <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">Swipe left on me too</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a data-confirm="Are you sure you want to delete this item?" class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li>
            <div class="item-content">
              <div class="item-media">
                <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">I am not removable</div>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">Swipe to delete without confirm</div>
      <div class="list list-strong list-outline-ios list-dividers-ios inset-md">
        <ul>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-inner">
                <div class="item-title">Swipe left on me please</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-inner">
                <div class="item-title">Swipe left on me too</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li>
            <div class="item-content">
              <div class="item-inner">
                <div class="item-title">I am not removable</div>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">Swipe for actions</div>
      <div class="list list-strong list-outline-ios list-dividers-ios inset-md">
        <ul>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media">
                <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">Swipe left on me please</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
              <a class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media">
                <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">Swipe left on me too</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
              <a class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media">
                <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">You can't delete me</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">With callback on remove</div>
      <div class="list list-strong list-outline-ios list-dividers-ios inset-md">
        <ul>
          <li class="swipeout" @swipeout:deleted=${onDeleted}>
            <div class="item-content swipeout-content">
              <div class="item-inner">
                <div class="item-title">Swipe left on me please</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li class="swipeout" @swipeout:deleted=${onDeleted}>
            <div class="item-content swipeout-content">
              <div class="item-inner">
                <div class="item-title">Swipe left on me too</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li>
            <div class="item-content">
              <div class="item-inner">
                <div class="item-title">I am not removable</div>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">With actions on left side (swipe to right)</div>
      <div class="list list-strong list-outline-ios list-dividers-ios inset-md">
        <ul>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media">
                <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">Swipe right on me please</div>
              </div>
            </div>
            <div class="swipeout-actions-left">
              <a class="color-green" @click=${reply}>Reply</a>
              <a class="color-blue" @click=${forward}>Forward</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media">
                <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">Swipe right on me too</div>
              </div>
            </div>
            <div class="swipeout-actions-left">
              <a class="color-green" @click=${reply}>Reply</a>
              <a class="color-blue" @click=${forward}>Forward</a>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">On both sides with overswipes</div>
      <div class="list media-list list-strong list-outline-ios list-dividers-ios inset-md">
        <ul>
          <li class="swipeout">
            <div class="swipeout-content">
              <a class="item-link item-content">
                <div class="item-inner">
                  <div class="item-title-row">
                    <div class="item-title">Facebook</div>
                    <div class="item-after">17:14</div>
                  </div>
                  <div class="item-subtitle">New messages from John Doe</div>
                  <div class="item-text">
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sagittis tellus ut turpis
                    condimentum, ut dignissim lacus tincidunt. Cras dolor metus, ultrices condimentum sodales sit amet,
                    pharetra sodales eros. Phasellus vel felis tellus. Mauris rutrum ligula nec dapibus feugiat. In vel
                    dui laoreet, commodo augue id, pulvinar lacus.
                  </div>
                </div>
              </a>
            </div>
            <div class="swipeout-actions-left">
              <a class="color-green swipeout-overswipe" @click=${reply}>Reply</a>
              <a class="color-blue" @click=${forward}>Forward</a>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
              <a class="color-orange" @click=${mark}>Mark</a>
              <a data-confirm="Are you sure you want to delete this item?"
                class="swipeout-delete swipeout-overswipe">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="swipeout-content">
              <a class="item-link item-content">
                <div class="item-inner">
                  <div class="item-title-row">
                    <div class="item-title">John Doe (via Twitter)</div>
                    <div class="item-after">17:11</div>
                  </div>
                  <div class="item-subtitle">John Doe (@_johndoe) mentioned you on Twitter!</div>
                  <div class="item-text">
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sagittis tellus ut turpis
                    condimentum, ut dignissim lacus tincidunt. Cras dolor metus, ultrices condimentum sodales sit amet,
                    pharetra sodales eros. Phasellus vel felis tellus. Mauris rutrum ligula nec dapibus feugiat. In vel
                    dui laoreet, commodo augue id, pulvinar lacus.
                  </div>
                </div>
              </a>
            </div>
            <div class="swipeout-actions-left">
              <a class="color-green swipeout-overswipe" @click=${reply}>Reply</a>
              <a class="color-blue" @click=${forward}>Forward</a>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
              <a class="color-orange" @click=${mark}>Mark</a>
              <a data-confirm="Are you sure you want to delete this item?"
                class="swipeout-delete swipeout-overswipe">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="swipeout-content">
              <a class="item-link item-content">
                <div class="item-inner">
                  <div class="item-title-row">
                    <div class="item-title">Facebook</div>
                    <div class="item-after">16:48</div>
                  </div>
                  <div class="item-subtitle">New messages from John Doe</div>
                  <div class="item-text">
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sagittis tellus ut turpis
                    condimentum, ut dignissim lacus tincidunt. Cras dolor metus, ultrices condimentum sodales sit amet,
                    pharetra sodales eros. Phasellus vel felis tellus. Mauris rutrum ligula nec dapibus feugiat. In vel
                    dui laoreet, commodo augue id, pulvinar lacus.
                  </div>
                </div>
              </a>
            </div>
            <div class="swipeout-actions-left">
              <a class="color-green swipeout-overswipe" @click=${reply}>Reply</a>
              <a class="color-blue" @click=${forward}>Forward</a>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
              <a class="color-orange" @click=${mark}>Mark</a>
              <a data-confirm="Are you sure you want to delete this item?"
                class="swipeout-delete swipeout-overswipe">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="swipeout-content">
              <a class="item-link item-content">
                <div class="item-inner">
                  <div class="item-title-row">
                    <div class="item-title">John Doe (via Twitter)</div>
                    <div class="item-after">15:32</div>
                  </div>
                  <div class="item-subtitle">John Doe (@_johndoe) mentioned you on Twitter!</div>
                  <div class="item-text">
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sagittis tellus ut turpis
                    condimentum, ut dignissim lacus tincidunt. Cras dolor metus, ultrices condimentum sodales sit amet,
                    pharetra sodales eros. Phasellus vel felis tellus. Mauris rutrum ligula nec dapibus feugiat. In vel
                    dui laoreet, commodo augue id, pulvinar lacus.
                  </div>
                </div>
              </a>
            </div>
            <div class="swipeout-actions-left">
              <a class="color-green swipeout-overswipe" @click=${reply}>Reply</a>
              <a class="color-blue" @click=${forward}>Forward</a>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
              <a class="color-orange" @click=${mark}>Mark</a>
              <a data-confirm="Are you sure you want to delete this item?"
                class="swipeout-delete swipeout-overswipe">Delete</a>
            </div>
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>
<script>
  export default (props, { $f7, $onMounted, $onBeforeUnmount }) => {
    let actions;
    const more = () => {
      actions.open();
    }
    const mark = () => {
      $f7.dialog.alert('Mark');
    }
    const reply = () => {
      $f7.dialog.alert('Reply');
    }
    const forward = () => {
      $f7.dialog.alert('Forward');
    }
    const onDeleted = () => {
      $f7.dialog.alert('Thanks, item removed!');
    }

    $onBeforeUnmount(() => {
      actions.destroy();
    })

    $onMounted(() => {
      actions = $f7.actions.create({
        buttons: [
          [
            {
              text: 'Here comes some optional description or warning for actions below',
              label: true,
            },
            {
              text: 'Action 1',
            },
            {
              text: 'Action 2',
            },
          ],
          [
            {
              text: 'Cancel',
              strong: true,
            }
          ]
        ],
      })
    })

    return $render;
  }
</script>