Angular Floating Action Button - Getting Started
jQuery
Angular
Vue
React
The Floating Action Button (FAB) is the primary action button on a screen that is displayed in front of all screen content. The FAB can execute an action or open a stack of two to five related actions (speed dial).
There should be only one FAB on a screen, but its action(s) can be different for different screens. For more details on the FAB concept and best practices, refer to the following topic: Material Design Guidelines.
In DevExtreme, the FAB is implemented as a container that collects and stores SpeedDialAction components.
From this tutorial, you will learn how to create a single- or multi-action FAB and alter action sets during screen transitions.
jQuery
Code examples in this tutorial use icons from the Ionicons library. If you are going to replicate the examples in your application, reference the Ionicons stylesheet within in the <head>
section of your page:
<link rel="stylesheet" href="https://unpkg.com/ionicons@4.6.3/dist/css/ionicons.min.css">
Angular
Code examples in this tutorial use icons from the Ionicons library. If you are going to replicate the examples in your application, install the ionicons
npm package:
npm install ionicons@4 --save
Vue
Code examples in this tutorial use icons from the Ionicons library. If you are going to replicate the examples in your application, install the ionicons
npm package:
npm install ionicons@4 --save
React
Code examples in this tutorial use icons from the Ionicons library. If you are going to replicate the examples in your application, install the ionicons
npm package:
npm install ionicons@4 --save
Single Action
A single-action FAB represents the primary action of a screen. According to the guidelines, this action should be constructive, such as, create, share, explore, or edit, as in the following example:
To create a single-action FAB, add one SpeedDialAction to your page and specify its onClick and icon properties. Other properties are optional, but we also specify a hint.
To position the FAB, use the floatingActionButtonConfig.position property in the GlobalConfig object.
Refer to the GitHub repository for the code that configures the example above and illustrates the described techniques.
Multiple Actions (Speed Dial)
The FAB can open a menu with several related actions (speed dial).
To create a FAB that opens a speed dial, add multiple SpeedDialAction components to a page, each with an individual icon and onClick event handler. The actions are sorted according to their indexes.
FAB parameters are configured in the floatingActionButtonConfig object. Use it to change the FAB's position, maximum number of actions, icons in the open and close states, and other parameters.
Refer to the GitHub repository for the code that configures the example above and shows how to set the described properties.
Handle Screen Transitions
Different screens use different FABs because a FAB should perform or contain only actions that can be performed on a particular screen. The DevExtreme TabPanel is used to emulate switching between screens.
jQuery
To implement this behavior, change the visible property of each SpeedDialAction when the screen is switched. Set this property to true if an action can be performed on the current screen. Otherwise, set it to false.
Angular
To implement this behavior, you can place the actions in separate components if the components have different URLs. No further configuration is required in this case.
The approach is different if the components have the same URL, or actions are in the same component. Change the visible property of each SpeedDialAction when the screen is switched. Set this property to true if an action can be performed on the current screen. Otherwise, set it to false.
Vue
To implement this behavior, you can place the actions in separate components if the components have different URLs. No further configuration is required in this case.
The approach is different if the components have the same URL, or actions are in the same component. Change the visible property of each SpeedDialAction when the screen is switched. Set this property to true if an action can be performed on the current screen. Otherwise, set it to false.
React
To implement this behavior, you can place the actions in separate components if the components have different URLs. No further configuration is required in this case.
The approach is different if the components have the same URL, or actions are in the same component. Change the visible property of each SpeedDialAction when the screen is switched. Set this property to true if an action can be performed on the current screen. Otherwise, set it to false.
The following code shows the TabPanel configuration and an empty switchSDA
function. This function controls the actions' visibility when it is implemented later.
jQuery
$(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/24.2.3/css/dx.material.blue.light.css"> <script type="text/javascript" src="https://cdn3.devexpress.com/jslib/24.2.3/js/dx.all.js"></script> <!-- Custom icons by Ionicons --> <link rel="stylesheet" href="https://unpkg.com/ionicons@4.6.3/dist/css/ionicons.min.css"> <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
<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; }
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { AppComponent } from './app.component'; import { DxTabPanelModule, DxSpeedDialActionModule } from 'devextreme-angular'; @NgModule({ declarations: [ AppComponent ], imports: [ BrowserModule, DxTabPanelModule, DxSpeedDialActionModule ], providers: [ ], bootstrap: [AppComponent] }) export class AppModule { }
{ // ... "projects": { "ng-app": { // ... "architect": { "build": { "options": { // ... "styles": [ "node_modules/devextreme/dist/css/dx.material.blue.light.css", // Custom icons by Ionicons "node_modules/ionicons/dist/css/ionicons.css", "src/styles.css" ], // ... }, // ... }, // ... } }, // ... }, // ... }
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> import 'devextreme/dist/css/dx.material.blue.light.css'; // Custom icons by Ionicons import 'ionicons/dist/css/ionicons.css'; import DxTabPanel, { DxItem } from 'devextreme-vue/tab-panel'; export default { components: { DxTabPanel, DxItem, }, methods: { switchSDAs(e) { // 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
import React from 'react'; import 'devextreme/dist/css/dx.material.blue.light.css'; // Custom icons by Ionicons import 'ionicons/dist/css/ionicons.css'; import './App.css'; import TabPanel, { Item } from 'devextreme-react/tab-panel'; class App extends React.Component { switchSDAs(e) { // To be implemented } render() { return ( <div id="app-container"> <TabPanel onSelectionChanged={this.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 adds four SpeedDialActions to the page, but only the "Edit" action is visible at launch. The switchSDA
function changes the actions' visibility based on the selected tab:
jQuery
$(function() { // TabPanel is configured here // ... DevExpress.config({ floatingActionButtonConfig: { icon: "icon ion-md-share", position: { my: "right bottom", at: "right bottom", of: "#app-container", offset: "-16 -16" } } }); const editAction = $("#action-edit").dxSpeedDialAction({ hint: "Edit", icon: "icon ion-md-create", onClick: function() { showNotification("Edit is clicked") } }).dxSpeedDialAction("instance"); const copyAction = $("#action-copy").dxSpeedDialAction({ hint: "Copy to clipboard", icon: "icon ion-md-copy", visible: false, onClick: function() { showNotification("Copied to clipboard") } }).dxSpeedDialAction("instance"); const mailAction = $("#action-mail").dxSpeedDialAction({ hint: "Send by email", icon: "icon ion-md-mail", visible: false, onClick: function() { showNotification("Sent by email") } }).dxSpeedDialAction("instance"); const facebookAction = $("#action-facebook").dxSpeedDialAction({ hint: "Share on Facebook", icon: "icon ion-logo-facebook", 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
<div id="app-container"> <!-- TabPanel is configured here --> <!-- ... --> <dx-speed-dial-action hint="Edit" icon="icon ion-md-create" [visible]="currentTab === 'Edit tab'" (onClick)="showNotification('Edit is clicked')"> </dx-speed-dial-action> <dx-speed-dial-action hint="Copy to clipboard" icon="icon ion-md-copy" [visible]="currentTab === 'Share tab'" (onClick)="showNotification('Copied to clipboard')"> </dx-speed-dial-action> <dx-speed-dial-action hint="Send by email" icon="icon ion-md-mail" [visible]="currentTab === 'Share tab'" (onClick)="showNotification('Sent by email')"> </dx-speed-dial-action> <dx-speed-dial-action hint="Share on Facebook" icon="icon ion-logo-facebook" [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: 'icon ion-md-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
<template> <div id="app-container"> <!-- TabPanel is configured here --> <DxSpeedDialAction hint="Edit" icon="ion ion-md-create" :visible="currentTab === 'Edit tab'" @click="showNotification('Edit is clicked')" /> <DxSpeedDialAction hint="Copy to clipboard" icon="ion ion-md-copy" :visible="currentTab === 'Share tab'" @click="showNotification('Copied to clipboard')" /> <DxSpeedDialAction hint="Send by email" icon="ion ion-md-mail" :visible="currentTab === 'Share tab'" @click="showNotification('Sent by email')" /> <DxSpeedDialAction hint="Share on Facebook" icon="ion ion-logo-facebook" :visible="currentTab === 'Share tab'" @click="showNotification('Shared on Facebook')" /> </div> </template> <script> // ... import DxSpeedDialAction from 'devextreme-vue/speed-dial-action'; import notify from 'devextreme/ui/notify'; import config from 'devextreme/core/config'; config({ floatingActionButtonConfig: { icon: 'icon ion-md-share', position: { my: 'right bottom', at: 'right bottom', of: '#app-container', offset: '-16 -16' } } }); export default { components: { // ... DxSpeedDialAction }, data() { return { currentTab: 'Edit tab' } }, methods: { switchSDAs(e) { this.currentTab = e.addedItems[0].title; }, showNotification(message) { notify({ message: message, position: { my: 'left bottom', at: 'left bottom', of: '#app-container', offset: '16 -16' }, minWidth: null, width: 320 * 0.7 }, "info", 1000); } } } </script> <style> /* ... */ </style>
React
// ... import SpeedDialAction from 'devextreme-react/speed-dial-action'; import config from 'devextreme/core/config'; import notify from 'devextreme/ui/notify'; class App extends React.Component { constructor(props) { super(props); config({ floatingActionButtonConfig: { icon: 'icon ion-md-share', position: { my: 'right bottom', at: 'right bottom', of: '#app-container', offset: '-16 -16' } } }); this.state = { currentTab: 'Edit tab' } this.switchSDAs = this.switchSDAs.bind(this); } switchSDAs(e) { this.setState({ currentTab: e.addedItems[0].title }); } render() { return ( <div id="app-container"> {/* TabPanel is configured here */} <SpeedDialAction hint="Edit" icon="icon ion-md-create" visible={this.state.currentTab === 'Edit tab'} onClick={() => showNotification('Edit is clicked')} /> <SpeedDialAction hint="Copy to clipboard" icon="icon ion-md-copy" visible={this.state.currentTab === 'Share tab'} onClick={() => showNotification('Copied to clipboard')} /> <SpeedDialAction hint="Send by email" icon="icon ion-md-mail" visible={this.state.currentTab === 'Share tab'} onClick={() => showNotification('Sent by email')} /> <SpeedDialAction hint="Share on Facebook" icon="icon ion-logo-facebook" visible={this.state.currentTab === 'Share tab'} onClick={() => showNotification('Shared on Facebook')} /> </div> ); } } function showNotification(message) { notify({ message: message, position: { my: 'left bottom', at: 'left bottom', of: '#app-container', offset: '16 -16' }, minWidth: null, width: 320 * 0.7 }, 'info', 1000); } export default App;
You can find the full code in the following GitHub repository: getting-started-with-floating-action-button-screen-transitions.
For more information on the Floating Action Button's functionality, explore the following resources:
If you have technical questions, please create a support ticket in the DevExpress Support Center.