JavaScript/jQuery Floating Action Button - Getting Started

jQuery
NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.
Angular
NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.
Vue
NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.
React
NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.

The Floating Action Button (FAB) sits above all screen content and triggers a primary action. FAB either executes a single action or expands to display two to five related actions (speed dial).

NOTE
Place only one FAB on a screen.

In DevExtreme, the FAB acts as a container for SpeedDialAction components.

This tutorial demonstrates how to create single and multi-action FABs, and how to update action sets during screen transitions.

Single Action

A single-action FAB triggers the main screen action:

Add one SpeedDialAction to the page and specify its onClick and icon properties. You can also define a hint.

Set the FAB's position property in GlobalConfig.

The code example is available in the following GitHub repository:

View on GitHub

Multiple Actions (Speed Dial)

A FAB can open a menu with multiple related actions (speed dial).

To create a FAB that triggers a speed dial, place multiple SpeedDialAction components on the page. Assign a unique icon and onClick event handler to each action. FAB sorts actions by index.

Define general FAB options in the floatingActionButtonConfig object. Specify position, max speed dial actions, icon, closeIcon, and other properties.

See the code example in the following GitHub repository:

View on GitHub

Handle Screen Transitions

In the following example, each screen has a distinct FAB, as each FAB contains only actions for that screen. The DevExtreme TabPanel emulates screen switching:

The following code includes the TabPanel configuration and an empty switchSDA function. Implement switchSDA to control action visibility:

jQuery
index.js
index.html
index.css
$(function() {
    $("#tab-panel").dxTabPanel({
        items: [{
            title: "Edit Tab",
            template: function() {
                return "<p>Edit tab's content</p>";
            }
        }, {
            title: "Share Tab",
            template: function() {
                return "<p>Share tab's content</p>";
            }
        }],
        onSelectionChanged: function(e) {
            switchSDAs(e.addedItems[0].title);
        }
    });

    function switchSDAs(tabTitle) {
        // To be implemented
    }
});
<html>
    <head>
        <!-- ... -->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

        <!-- DevExtreme resources -->
        <link rel="stylesheet" href="https://cdn3.devexpress.com/jslib/25.1.6/css/dx.material.blue.light.css">
        <script type="text/javascript" src="https://cdn3.devexpress.com/jslib/25.1.6/js/dx.all.js"></script>

        <link rel="stylesheet" href="index.css">
        <script type="text/javascript" src="index.js"></script>
    </head>
    <body class="dx-viewport">
        <div id="app-container">
            <div id="tab-panel"></div>
            <div id="action-edit"></div>
            <div id="action-mail"></div>
            <div id="action-copy"></div>
            <div id="action-facebook"></div>
        </div>
    </body>
</html>
.dx-fa-button-icon, .dx-fa-button-icon-close {
    text-align: center;
}

p {
    text-align: center;
}

#app-container {
    height: 360px;
    width: 320px;
}

.dx-tabpanel .dx-tabs-wrapper {
    display: flex;
    flex-flow: row nowrap;
}

.dx-tab {
    display: flex;
    flex-flow: row nowrap;
    flex: 1;
    justify-content: center;
}
Angular
app.component.html
app.component.ts
app.component.css
<div id="app-container">
    <dx-tab-panel
        (onSelectionChanged)="switchSDAs($event)">
        <dxi-item title="Edit tab">
            <p>Edit tab's content</p>
        </dxi-item>
        <dxi-item title="Share tab">
            <p>Share tab's content</p>
        </dxi-item>
    </dx-tab-panel>
    <!-- To be implemented -->
</div>
import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {
    switchSDAs(e) {
        // To be implemented
        this.currentTab = e.addedItems[0].title; 
    }
}
::ng-deep .dx-fa-button-icon, .dx-fa-button-icon-close {
    text-align: center;
}

p {
    text-align: center;
}

#app-container {
    height: 360px;
    width: 320px;
}

::ng-deep .dx-tabpanel .dx-tabs-wrapper {
    display: flex;
    flex-flow: row nowrap;
}

::ng-deep .dx-tab {
    display: flex;
    flex-flow: row nowrap;
    flex: 1;
    justify-content: center;
}
Vue
App.vue
<template>
    <div id="app-container">
        <DxTabPanel
            @selection-changed="switchSDAs">
            <DxItem title="Edit tab">
                <template #default>
                    <p>Edit tab's content</p>
                </template>
            </DxItem>
            <DxItem title="Share tab">
                <template #default>
                    <p>Share tab's content</p>
                </template>
            </DxItem>
        </DxTabPanel>
        <!-- To be implemented -->
    </div>
</template>

<script setup lang="ts">
import 'devextreme/dist/css/dx.material.blue.light.css';
import DxTabPanel, { DxItem } from 'devextreme-vue/tab-panel';

// switchSDAs to be implemented
</script>

<style>
.dx-fa-button-icon, .dx-fa-button-icon-close {
    text-align: center;
}

p {
    text-align: center;
}

#app-container {
    height: 360px;
    width: 320px;
    border: 1px solid black;
}

.dx-tabpanel .dx-tabs-wrapper {
    display: flex;
    flex-flow: row nowrap;
}

.dx-tab {
    display: flex;
    flex-flow: row nowrap;
    flex: 1;
    justify-content: center;
}
</style>
React
App.tsx
App.css
import React from 'react';
import 'devextreme/dist/css/dx.material.blue.light.css';
import './App.css';

import TabPanel, { Item } from 'devextreme-react/tab-panel';

function App(): JSX.Element {
    // switchSDAs to be implemented

    return (
        <div id="app-container">
            <<TabPanel onSelectionChanged={switchSDAs}>
                <Item title="Edit tab">
                    <p>Edit tab's content</p>
                </Item>
                <Item title="Share tab">
                    <p>Share tab's content</p>
                </Item>
            </TabPanel>
            {/* To be implemented */}
        </div>
    );
}

export default App;
.dx-fa-button-icon, .dx-fa-button-icon-close {
    text-align: center;
}

p {
    text-align: center;
}

#app-container {
    height: 360px;
    width: 320px;
}

.dx-tabpanel .dx-tabs-wrapper {
    display: flex;
    flex-flow: row nowrap;
}

.dx-tab {
    display: flex;
    flex-flow: row nowrap;
    flex: 1;
    justify-content: center;
}

The following code creates four SpeedDialActions. At launch, only "Edit" appears. The switchSDA function displays or hides actions depending on the active tab:

jQuery
index.js
$(function() {
    // TabPanel is configured here
    // ...

    DevExpress.config({
        floatingActionButtonConfig: {
            icon: "share",
            position: {
                my: "right bottom",
                at: "right bottom",
                of: "#app-container",
                offset: "-16 -16"
            }
        }
    });

    const editAction = $("#action-edit").dxSpeedDialAction({
        hint: "Edit",
        icon: "edit",
        onClick: function() {
            showNotification("Edit is clicked")
        }
    }).dxSpeedDialAction("instance");

    const copyAction = $("#action-copy").dxSpeedDialAction({
        hint: "Copy to clipboard",
        icon: "copy",
        visible: false,
        onClick: function() {
            showNotification("Copied to clipboard")
        }
    }).dxSpeedDialAction("instance");

    const mailAction = $("#action-mail").dxSpeedDialAction({
        hint: "Send by email",
        icon: "email",
        visible: false,
        onClick: function() {
            showNotification("Sent by email")
        }
    }).dxSpeedDialAction("instance");

    const facebookAction = $("#action-facebook").dxSpeedDialAction({
        hint: "Share on Facebook",
        icon: "link",
        visible: false,
        onClick: function() {
            showNotification("Shared on Facebook")
        }
    }).dxSpeedDialAction("instance");

    function switchSDAs(tabTitle) {
        if(tabTitle === "Edit Tab") {
            editAction.option("visible", true);
            copyAction.option("visible", false);
            mailAction.option("visible", false);
            facebookAction.option("visible", false);
        }
        if(tabTitle === "Share Tab") {
            editAction.option("visible", false);
            copyAction.option("visible", true);
            mailAction.option("visible", true);
            facebookAction.option("visible", true);
        }
    }

    function showNotification(message) {
        DevExpress.ui.notify({
            message: message,
            position: {
                my: "left bottom",
                at: "left bottom",
                of: "#app-container",
                offset: "16 -16"
            },
            minWidth: null,
            width: function() {
                return $("#app-container").width() * 0.7;
            }
        }, "info", 1000);
    }
});
Angular
app.component.html
app.component.ts
<div id="app-container">
    <!-- TabPanel is configured here -->
    <!-- ... -->
    <dx-speed-dial-action
        hint="Edit"
        icon="edit"
        [visible]="currentTab === 'Edit tab'"
        (onClick)="showNotification('Edit is clicked')">
    </dx-speed-dial-action>

    <dx-speed-dial-action
        hint="Copy to clipboard"
        icon="copy"
        [visible]="currentTab === 'Share tab'"
        (onClick)="showNotification('Copied to clipboard')">
    </dx-speed-dial-action>
    <dx-speed-dial-action
        hint="Send by email"
        icon="email"
        [visible]="currentTab === 'Share tab'"
        (onClick)="showNotification('Sent by email')">
    </dx-speed-dial-action>
    <dx-speed-dial-action
        hint="Share on Facebook"
        icon="link"
        [visible]="currentTab === 'Share tab'"
        (onClick)="showNotification('Shared on Facebook')">
    </dx-speed-dial-action>
</div>
import { Component } from '@angular/core';
import notify from 'devextreme/ui/notify';
import config from 'devextreme/core/config';

config({
    floatingActionButtonConfig: {
        icon: 'share',
        position: {
            my: 'right bottom',
            at: 'right bottom',
            of: '#app-container',
            offset: '-16 -16'
        }
    }
});
// ...
export class AppComponent {
    currentTab: string;
    constructor() {
        this.currentTab = 'Edit tab';
    }
    switchSDAs(e) {
        this.currentTab = e.addedItems[0].title; 
    }
    showNotification(message: string) {
        notify({
            message: message,
            position: {
                my: 'left bottom',
                at: 'left bottom',
                of: '#app-container',
                offset: '16 -16'
            },
            minWidth: null,
            width: 320 * 0.7
        }, 'info', 1000);
    }
}
Vue
App.vue
<template>
    <div id="app-container">
        <!-- TabPanel is configured here -->
        <DxSpeedDialAction
            hint="Edit"
            icon="edit"
            :visible="currentTab === 'Edit tab'"
            @click="showNotification('Edit is clicked')"
        />
        <DxSpeedDialAction
            hint="Copy to clipboard"
            icon="copy"
            :visible="currentTab === 'Share tab'"
            @click="showNotification('Copied to clipboard')"
        />
        <DxSpeedDialAction
            hint="Send by email"
            icon="email"
            :visible="currentTab === 'Share tab'"
            @click="showNotification('Sent by email')"
        />
        <DxSpeedDialAction
            hint="Share on Facebook"
            icon="link"
            :visible="currentTab === 'Share tab'"
            @click="showNotification('Shared on Facebook')"
        />
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { DxTabPanel, DxItem } from 'devextreme-vue/tab-panel';
import DxSpeedDialAction from 'devextreme-vue/speed-dial-action';
import type { DxTabPanelTypes } from 'devextreme-vue/tab-panel';
import type { GlobalConfig } from 'devextreme/common';
import type { Properties as ToastProperties } from 'devextreme/ui/toast';
import notify from 'devextreme/ui/notify';
import config from 'devextreme/core/config';
import type { TabItem } from '../types';

const floatingActionButtonConfig: GlobalConfig = {
    floatingActionButtonConfig: {
        icon: 'share',
        position: {
            my: 'right bottom',
            at: 'right bottom',
            of: '#app-container',
            offset: '-16 -16',
        },
    },
};

config(floatingActionButtonConfig);

const currentTab = ref<string>('Edit tab');

const switchSDAs = (e: DxTabPanelTypes.SelectionChangedEvent): void => {
    const addedItem = e.addedItems[0] as TabItem;
    currentTab.value = addedItem.title;
};

const showNotification = (message: string): void => {
    const options: ToastProperties = {
        message,
        position: {
            my: 'left bottom',
            at: 'left bottom',
            of: '#app-container',
            offset: '16 -16',
        },
        width: 320 * 0.7,
        minWidth: 0,
    };
    notify(options, 'info', 1000);
};
</script>
React
App.js
// ...
import { useCallback, useState } from 'react';
import TabPanel, { Item } from 'devextreme-react/tab-panel';
import SpeedDialAction from 'devextreme-react/speed-dial-action';
import config from 'devextreme/core/config';
import type { GlobalConfig } from 'devextreme/common';
import notify from 'devextreme/ui/notify';
import type { TabPanelTypes } from 'devextreme-react/tab-panel';
import type { Properties as ToastProperties } from 'devextreme/ui/toast';

const globalConfig: GlobalConfig = {
    floatingActionButtonConfig: {
        icon: 'share',
        position: {
            my: 'right bottom',
            at: 'right bottom',
            of: '#app-container',
            offset: '-16 -16',
        },
    },
};

config(globalConfig);

function showNotification(message: string): void {
    const options: ToastProperties = {
        message,
        position: {
            my: 'left bottom',
            at: 'left bottom',
            of: '#app-container',
            offset: '16 -16',
        },
        width: 320 * 0.7,
        minWidth: 0,
    };

    notify(options, 'info', 1000);
}

function App(): JSX.Element {
    const [currentTab, setCurrentTab] = useState<string>('Edit tab');

    const switchSDAs = useCallback(
        (e: TabPanelTypes.SelectionChangedEvent): void => {
            setCurrentTab(e.addedItems[0].title);
        },
        [],
    );

    const handleEditClick = useCallback((): void => {
        showNotification('Edit is clicked');
    }, []);

    const handleCopyClick = useCallback((): void => {
        showNotification('Copied to clipboard');
    }, []);

    const handleMailClick = useCallback((): void => {
        showNotification('Sent by email');
    }, []);

    const handleSocialClick = useCallback((): void => {
        showNotification('Shared on Social Media');
    }, []);

    return (
        <div id="app-container">
            <!-- TabPanel configuration -->
            <SpeedDialAction
                hint="Edit"
                icon="edit"
                visible={currentTab === 'Edit tab'}
                onClick={handleEditClick}
            />
            <SpeedDialAction
                hint="Copy to clipboard"
                icon="copy"
                visible={currentTab === 'Share tab'}
                onClick={handleCopyClick}
            />
            <SpeedDialAction
                hint="Send by email"
                icon="email"
                visible={currentTab === 'Share tab'}
                onClick={handleMailClick}
            />
            <SpeedDialAction
                hint="Share on Social Media"
                icon="link"
                visible={currentTab === 'Share tab'}
                onClick={handleSocialClick}
            />
        </div>
    );
}

export default App;

You can find the full code in the following GitHub repository:

View on GitHub

For more information on the Floating Action Button's functionality, explore the following resources: