DevExtreme v24.2 is now available.

Explore our newest features/capabilities and share your thoughts with us.

Your search did not match any results.

React Popup - Overview

This example demonstrates how to show and hide the Popup component, populate it with content, specify its position and other settings.

To see step-by-step instructions on how to get started with the DevExtreme Popup component, refer to the following tutorial: Getting Started with Popup.

DevExtreme Accessibility Compliance
DevExtreme component libraries meet a variety of WCAG and Section 508 compliance standards. To assess this demo’s accessibility level, click the Run AXE® Validation button to launch the AXE® web accessibility evaluation tool.
All trademarks or registered trademarks are property of their respective owners. AXE® Terms of Use
The overall accessibility level of your application depends on the Popup features used.
Backend API
import React, { useCallback, useMemo, useState } from 'react'; import { Popup, Position, ToolbarItem } from 'devextreme-react/popup'; import notify from 'devextreme/ui/notify'; import { EmployeeItem, EmployeeItemProps } from './EmployeeItem.tsx'; import { employees } from './data.ts'; const defaultCurrentEmployee: Partial<EmployeeItemProps['employee']> = {}; export default function App() { const [currentEmployee, setCurrentEmployee] = useState(defaultCurrentEmployee); const [popupVisible, setPopupVisible] = useState(false); const [positionOf, setPositionOf] = useState(''); const showInfo = useCallback((employee: EmployeeItemProps['employee']) => { setCurrentEmployee(employee); setPositionOf(`#image${employee.ID}`); setPopupVisible(true); }, [setCurrentEmployee, setPositionOf, setPopupVisible]); const hideInfo = useCallback(() => { setCurrentEmployee({}); setPopupVisible(false); }, [setCurrentEmployee, setPopupVisible]); const sendEmail = useCallback(() => { const message = `Email is sent to ${currentEmployee.FirstName} ${currentEmployee.LastName}`; notify( { message, position: { my: 'center top', at: 'center top', }, }, 'success', 3000, ); }, [currentEmployee]); const showMoreInfo = useCallback(() => { const message = `More info about ${currentEmployee.FirstName} ${currentEmployee.LastName}`; notify( { message, position: { my: 'center top', at: 'center top', }, }, 'success', 3000, ); }, [currentEmployee]); const getInfoButtonOptions = useMemo(() => ({ text: 'More info', onClick: showMoreInfo, }), [showMoreInfo]); const getEmailButtonOptions = useMemo(() => ({ icon: 'email', stylingMode: 'contained', text: 'Send', onClick: sendEmail, }), [sendEmail]); const getCloseButtonOptions = useMemo(() => ({ text: 'Close', stylingMode: 'outlined', type: 'normal', onClick: hideInfo, }), [hideInfo]); const getItems = useCallback(() => employees.map((employee) => ( <li key={employee.ID}> <EmployeeItem employee={employee} showInfo={showInfo} /> </li> )), [showInfo]); return ( <div id="container"> <div className="header">Employees</div> <ul>{getItems()}</ul> <Popup visible={popupVisible} onHiding={hideInfo} dragEnabled={false} hideOnOutsideClick={true} showCloseButton={false} showTitle={true} title="Information" container=".dx-viewport" width={300} height={280} > <Position at="bottom" my="center" of={positionOf} collision="fit" /> <ToolbarItem widget="dxButton" toolbar="top" locateInMenu="always" options={getInfoButtonOptions} /> <ToolbarItem widget="dxButton" toolbar="bottom" location="before" options={getEmailButtonOptions} /> <ToolbarItem widget="dxButton" toolbar="bottom" location="after" options={getCloseButtonOptions} /> <p> Full Name:&nbsp; <span>{currentEmployee.FirstName}</span>&nbsp; <span>{currentEmployee.LastName}</span> </p> <p> Birth Date: <span>{currentEmployee.BirthDate}</span> </p> <p> Address: <span>{currentEmployee.Address}</span> </p> <p> Hire Date: <span>{currentEmployee.HireDate}</span> </p> <p> Position: <span>{currentEmployee.Position}</span> </p> </Popup> </div> ); }
import React, { useCallback, useMemo, useState } from 'react'; import { Popup, Position, ToolbarItem } from 'devextreme-react/popup'; import notify from 'devextreme/ui/notify'; import { EmployeeItem } from './EmployeeItem.js'; import { employees } from './data.js'; const defaultCurrentEmployee = {}; export default function App() { const [currentEmployee, setCurrentEmployee] = useState(defaultCurrentEmployee); const [popupVisible, setPopupVisible] = useState(false); const [positionOf, setPositionOf] = useState(''); const showInfo = useCallback( (employee) => { setCurrentEmployee(employee); setPositionOf(`#image${employee.ID}`); setPopupVisible(true); }, [setCurrentEmployee, setPositionOf, setPopupVisible], ); const hideInfo = useCallback(() => { setCurrentEmployee({}); setPopupVisible(false); }, [setCurrentEmployee, setPopupVisible]); const sendEmail = useCallback(() => { const message = `Email is sent to ${currentEmployee.FirstName} ${currentEmployee.LastName}`; notify( { message, position: { my: 'center top', at: 'center top', }, }, 'success', 3000, ); }, [currentEmployee]); const showMoreInfo = useCallback(() => { const message = `More info about ${currentEmployee.FirstName} ${currentEmployee.LastName}`; notify( { message, position: { my: 'center top', at: 'center top', }, }, 'success', 3000, ); }, [currentEmployee]); const getInfoButtonOptions = useMemo( () => ({ text: 'More info', onClick: showMoreInfo, }), [showMoreInfo], ); const getEmailButtonOptions = useMemo( () => ({ icon: 'email', stylingMode: 'contained', text: 'Send', onClick: sendEmail, }), [sendEmail], ); const getCloseButtonOptions = useMemo( () => ({ text: 'Close', stylingMode: 'outlined', type: 'normal', onClick: hideInfo, }), [hideInfo], ); const getItems = useCallback( () => employees.map((employee) => ( <li key={employee.ID}> <EmployeeItem employee={employee} showInfo={showInfo} /> </li> )), [showInfo], ); return ( <div id="container"> <div className="header">Employees</div> <ul>{getItems()}</ul> <Popup visible={popupVisible} onHiding={hideInfo} dragEnabled={false} hideOnOutsideClick={true} showCloseButton={false} showTitle={true} title="Information" container=".dx-viewport" width={300} height={280} > <Position at="bottom" my="center" of={positionOf} collision="fit" /> <ToolbarItem widget="dxButton" toolbar="top" locateInMenu="always" options={getInfoButtonOptions} /> <ToolbarItem widget="dxButton" toolbar="bottom" location="before" options={getEmailButtonOptions} /> <ToolbarItem widget="dxButton" toolbar="bottom" location="after" options={getCloseButtonOptions} /> <p> Full Name:&nbsp; <span>{currentEmployee.FirstName}</span>&nbsp; <span>{currentEmployee.LastName}</span> </p> <p> Birth Date: <span>{currentEmployee.BirthDate}</span> </p> <p> Address: <span>{currentEmployee.Address}</span> </p> <p> Hire Date: <span>{currentEmployee.HireDate}</span> </p> <p> Position: <span>{currentEmployee.Position}</span> </p> </Popup> </div> ); }
import React, { useCallback } from 'react'; import { Button } from 'devextreme-react/button'; export interface EmployeeItemProps { employee: { ID: number; FirstName: string; LastName: string; Prefix: string; Position: string; Picture: string; BirthDate: string; HireDate: string; Notes: string; Address: string; }; showInfo: any; } export function EmployeeItem(props: EmployeeItemProps) { const showInfo = useCallback(() => { props.showInfo(props.employee); }, [props]); return ( <React.Fragment> <img alt={`${props.employee.FirstName} ${props.employee.LastName}`} src={ props.employee.Picture } id={ `image${props.employee.ID}` } /><br /> <i>{props.employee.FirstName} {props.employee.LastName}</i><br /> <Button className="button-info" text="Details" onClick={showInfo} /> </React.Fragment> ); }
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.tsx'; ReactDOM.render( <App />, document.getElementById('app'), );
export const employees = [{ ID: 7, FirstName: 'Sandra', LastName: 'Johnson', Prefix: 'Mrs.', Position: 'Controller', Picture: '../../../../images/employees/06.png', BirthDate: '1974/11/15', HireDate: '2005/05/11', Notes: "Sandra is a CPA and has been our controller since 2008. She loves to interact with staff so if you've not met her, be certain to say hi.\r\n\r\nSandra has 2 daughters both of whom are accomplished gymnasts.", Address: '4600 N Virginia Rd.', }, { ID: 10, FirstName: 'Kevin', LastName: 'Carter', Prefix: 'Mr.', Position: 'Shipping Manager', Picture: '../../../../images/employees/07.png', BirthDate: '1978/01/09', HireDate: '2009/08/11', Notes: 'Kevin is our hard-working shipping manager and has been helping that department work like clockwork for 18 months.\r\n\r\nWhen not in the office, he is usually on the basketball court playing pick-up games.', Address: '424 N Main St.', }, { ID: 11, FirstName: 'Cynthia', LastName: 'Stanwick', Prefix: 'Ms.', Position: 'HR Assistant', Picture: '../../../../images/employees/08.png', BirthDate: '1985/06/05', HireDate: '2008/03/24', Notes: 'Cindy joined us in 2008 and has been in the HR department for 2 years. \r\n\r\nShe was recently awarded employee of the month. Way to go Cindy!', Address: '2211 Bonita Dr.', }, { ID: 30, FirstName: 'Kent', LastName: 'Samuelson', Prefix: 'Dr.', Position: 'Ombudsman', Picture: '../../../../images/employees/02.png', BirthDate: '1972/09/11', HireDate: '2009/04/22', Notes: 'As our ombudsman, Kent is on the front-lines solving customer problems and helping our partners address issues out in the field. He is a classically trained musician and is a member of the Chamber Orchestra.', Address: '12100 Mora Dr', }];
window.exports = window.exports || {}; window.config = { transpiler: 'ts', typescriptOptions: { module: 'system', emitDecoratorMetadata: true, experimentalDecorators: true, jsx: 'react', }, meta: { 'react': { 'esModule': true, }, 'typescript': { 'exports': 'ts', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, 'openai': { 'esModule': true, }, }, paths: { 'npm:': 'https://unpkg.com/', 'bundles:': '../../../../bundles/', 'externals:': '../../../../bundles/externals/', }, defaultExtension: 'js', map: { 'ts': 'npm:plugin-typescript@8.0.0/lib/plugin.js', 'typescript': 'npm:typescript@4.2.4/lib/typescript.js', 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'react': 'npm:react@17.0.2/umd/react.development.js', 'react-dom': 'npm:react-dom@17.0.2/umd/react-dom.development.js', 'prop-types': 'npm:prop-types/prop-types.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@3.4.4/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign', 'devextreme': 'npm:devextreme@link:../../packages/devextreme/artifacts/npm/devextreme/cjs', 'devextreme-react': 'npm:devextreme-react@link:../../packages/devextreme-react/npm/cjs', 'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.5/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.54/dist/dx-gantt.js', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.12', 'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js', 'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js', 'inferno-hydrate': 'npm:inferno-hydrate/dist/inferno-hydrate.min.js', 'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js', 'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js', 'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js', 'devextreme-cldr-data': 'npm:devextreme-cldr-data@1.0.3', // SystemJS plugins 'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js', // Prettier 'prettier/standalone': 'npm:prettier@2.8.8/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js', }, packages: { 'devextreme': { defaultExtension: 'js', }, 'devextreme-react': { main: 'index.js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/localization/messages': { format: 'json', defaultExtension: 'json', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:@devextreme/runtime@3.0.12/inferno/package.json', ], babelOptions: { sourceMaps: false, stage0: true, react: true, }, }; System.config(window.config);
import React, { useCallback } from 'react'; import { Button } from 'devextreme-react/button'; export function EmployeeItem(props) { const showInfo = useCallback(() => { props.showInfo(props.employee); }, [props]); return ( <React.Fragment> <img alt={`${props.employee.FirstName} ${props.employee.LastName}`} src={props.employee.Picture} id={`image${props.employee.ID}`} /> <br /> <i> {props.employee.FirstName} {props.employee.LastName} </i> <br /> <Button className="button-info" text="Details" onClick={showInfo} /> </React.Fragment> ); }
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.js'; ReactDOM.render(<App />, document.getElementById('app'));
export const employees = [ { ID: 7, FirstName: 'Sandra', LastName: 'Johnson', Prefix: 'Mrs.', Position: 'Controller', Picture: '../../../../images/employees/06.png', BirthDate: '1974/11/15', HireDate: '2005/05/11', Notes: "Sandra is a CPA and has been our controller since 2008. She loves to interact with staff so if you've not met her, be certain to say hi.\r\n\r\nSandra has 2 daughters both of whom are accomplished gymnasts.", Address: '4600 N Virginia Rd.', }, { ID: 10, FirstName: 'Kevin', LastName: 'Carter', Prefix: 'Mr.', Position: 'Shipping Manager', Picture: '../../../../images/employees/07.png', BirthDate: '1978/01/09', HireDate: '2009/08/11', Notes: 'Kevin is our hard-working shipping manager and has been helping that department work like clockwork for 18 months.\r\n\r\nWhen not in the office, he is usually on the basketball court playing pick-up games.', Address: '424 N Main St.', }, { ID: 11, FirstName: 'Cynthia', LastName: 'Stanwick', Prefix: 'Ms.', Position: 'HR Assistant', Picture: '../../../../images/employees/08.png', BirthDate: '1985/06/05', HireDate: '2008/03/24', Notes: 'Cindy joined us in 2008 and has been in the HR department for 2 years. \r\n\r\nShe was recently awarded employee of the month. Way to go Cindy!', Address: '2211 Bonita Dr.', }, { ID: 30, FirstName: 'Kent', LastName: 'Samuelson', Prefix: 'Dr.', Position: 'Ombudsman', Picture: '../../../../images/employees/02.png', BirthDate: '1972/09/11', HireDate: '2009/04/22', Notes: 'As our ombudsman, Kent is on the front-lines solving customer problems and helping our partners address issues out in the field. He is a classically trained musician and is a member of the Chamber Orchestra.', Address: '12100 Mora Dr', }, ];
<!DOCTYPE html> <html lang="en"> <head> <title>DevExtreme Demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.2.3/css/dx.light.css" /> <link rel="stylesheet" type="text/css" href="styles.css" /> <script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script> <script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script> <script type="text/javascript" src="config.js"></script> <script type="text/javascript"> System.import("./index.tsx"); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"></div> </div> </body> </html>
.header { font-size: 34px; text-align: center; } #container { padding: 10px; } #container ul { list-style-type: none; text-align: center; } #container ul li { display: inline-block; width: 160px; margin: 10px; } #container ul li img { width: 100px; } .button-info { margin: 10px; } .dx-popup-content p { margin-bottom: 10px; margin-top: 0; }

Show and Hide the Popup

Bind the visible property to a Boolean variable (popupVisible in this demo). Next, implement the showInfo(employee) method to set this Boolean variable to true. This causes the Popup to appear. To close a Popup, choose one of the following options:

  • Built-in close button
    Enable the showCloseButton property to display the Close button in a Popup's top toolbar.

  • Custom close button
    This demo shows how to add custom buttons to a Popup. One of these buttons uses an onClick handler to set the popupVisible variable to false, causing the Popup to disappear. Refer to the next section (Configure the Popup) to learn how you can populate a popup with custom controls.

  • On outside click
    Enable the hideOnOutsideClick property to allow users to hide the Popup by clicking outside the component.

Configure the Popup

The Popup inner area is divided into three parts:

  • Top toolbar

    • Predefined
      Set showTitle to true and use the title property to specify the caption. The Close button will appear if you do not disable the showCloseButton property.

    • Custom
      Add toolbarItems markup and set each item's toolbar property to top. If you want to display an item in the overflow menu, as shown in this demo, set the item's locateInMenu property to always. You can also assign never to this property to keep the item outside the overflow menu, or you can assign auto to hide the item in the menu if the Popup's width decreases.

  • Content
    To populate the Popup with content, add markup inside the component.

  • Bottom toolbar
    To enable the bottom toolbar, declare toolbarItems in the markup as shown in this demo. Set each item's toolbar property to bottom. To learn more about toolbar configuration, refer to the following tutorial: Getting Started with Toolbar

Resize and Position

To specify Popup size, use the height and width properties.

In this demo, each Popup's location is relative to the image. The code specifies the my, at, and of properties of the position object. The configuration in the demo reads as follows: "place my center side at the bottom side of the #image${employee.ID} element."

Use the container property to select the container in which you want to render the Popup. If you set the container property to an element on the page, the shading applies to this element.

Turn on the dragEnabled option to allow users to move a Popup around the page.