diff --git a/assets/images/camera.svg b/assets/images/camera.svg
new file mode 100644
index 000000000000..65c5e9301417
--- /dev/null
+++ b/assets/images/camera.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 20 20" style="enable-background:new 0 0 20 20;" xml:space="preserve">
+<path d="M17.5,5H15l-1.1-1.1c0,0-0.1-0.1-0.4-0.1h-7C6.2,3.8,6.1,3.9,6,4L5,5H2.5C1.8,5,1.2,5.6,1.2,6.2v9.2c0,1.1,0.9,2,2,2h13.5
+	c1.1,0,2-0.9,2-2V6.2C18.8,5.6,18.2,5,17.5,5z M10,13.8c-1.4,0-2.5-1.1-2.5-2.5S8.6,8.8,10,8.8s2.5,1.1,2.5,2.5S11.4,13.8,10,13.8z"
+	/>
+</svg>
diff --git a/assets/images/gallery.svg b/assets/images/gallery.svg
new file mode 100644
index 000000000000..b79d2010c02f
--- /dev/null
+++ b/assets/images/gallery.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+	 viewBox="0 0 20 20" style="enable-background:new 0 0 20 20;" xml:space="preserve">
+<path d="M18.1,3.8H1.9C1.5,3.8,1.2,4,1.2,4.4v12.5c0,0.4,0.2,0.6,0.6,0.6h16.2c0.4,0,0.6-0.2,0.6-0.6V4.4C18.8,4,18.5,3.8,18.1,3.8z
+	 M14.5,15H4.8c-0.5,0-0.8-0.5-0.6-0.9l2.5-5.4c0.2-0.5,0.9-0.5,1.1,0l2.2,4.9l1.9-2.5c0.2-0.4,0.8-0.4,1,0L15,14
+	C15.2,14.4,15,15,14.5,15z M15,8.8c-0.8,0-1.2-0.5-1.2-1.2s0.5-1.2,1.2-1.2s1.2,0.5,1.2,1.2S15.8,8.8,15,8.8z"/>
+</svg>
diff --git a/src/components/AttachmentPicker/AttachmentPickerPropTypes.js b/src/components/AttachmentPicker/AttachmentPickerPropTypes.js
new file mode 100644
index 000000000000..a14643396f92
--- /dev/null
+++ b/src/components/AttachmentPicker/AttachmentPickerPropTypes.js
@@ -0,0 +1,25 @@
+import PropTypes from 'prop-types';
+
+const propTypes = {
+    /**
+     * A renderProp with the following interface
+     *
+     * @example
+     * <AttachmentPicker>
+     * {({openPicker}) => (
+     *     <Button
+     *         onPress={() => {
+     *             openPicker({
+     *                 onPicked: (file) => {
+     *                     // Display or upload File
+     *                 },
+     *             });
+     *         }}
+     *     />
+     * )}
+     * </AttachmentPicker>
+     * */
+    children: PropTypes.func.isRequired,
+};
+
+export default propTypes;
diff --git a/src/components/AttachmentPicker/index.js b/src/components/AttachmentPicker/index.js
index 3f2b648f57ef..425e04d9ca72 100644
--- a/src/components/AttachmentPicker/index.js
+++ b/src/components/AttachmentPicker/index.js
@@ -1,32 +1,12 @@
 import React from 'react';
-import PropTypes from 'prop-types';
-
-const propTypes = {
-    children: PropTypes.func.isRequired,
-};
+import propTypes from './AttachmentPickerPropTypes';
 
 /**
  * This component renders a function as a child and
  * returns a "show attachment picker" method that takes
  * a callback. This is the web/mWeb/desktop version since
- * on iOS Safari we must append a hidden input to the DOM
- * and listen to onChange event. When the show method is
- * called an attachment
- *
- * @example
- * <AttachmentPicker>
- * {({openPicker}) => (
- *     <Button
- *         onPress={() => {
- *             openPicker({
- *                 onPicked: (file) => {
- *                     // Display or upload File
- *                 },
- *             });
- *         }}
- *     />
- * )}
- * </AttachmentPicker>
+ * on a Browser we must append a hidden input to the DOM
+ * and listen to onChange event.
  */
 class AttachmentPicker extends React.Component {
     render() {
diff --git a/src/components/AttachmentPicker/index.native.js b/src/components/AttachmentPicker/index.native.js
index 379c8697e3e4..085a4061ce29 100644
--- a/src/components/AttachmentPicker/index.native.js
+++ b/src/components/AttachmentPicker/index.native.js
@@ -1,20 +1,27 @@
 /**
  * The react native image/document pickers work for iOS/Android, but we want to wrap them both within AttachmentPicker
  */
-import {Alert, Linking} from 'react-native';
+import React, {Component} from 'react';
+import {Alert, Linking, View} from 'react-native';
 import RNImagePicker from 'react-native-image-picker';
 import RNDocumentPicker from 'react-native-document-picker';
-import PropTypes from 'prop-types';
+import basePropTypes from './AttachmentPickerPropTypes';
+import styles from '../../styles/styles';
+import Popover from '../Popover';
+import MenuItem from '../MenuItem';
+import {Camera, Gallery, Paperclip} from '../Icon/Expensicons';
+import withWindowDimensions, {windowDimensionsPropTypes} from '../withWindowDimensions';
+
+const propTypes = {
+    ...basePropTypes,
+    ...windowDimensionsPropTypes,
+};
 
 /**
  * See https://github.com/react-native-community/react-native-image-picker/blob/master/docs/Reference.md#options
  * for ImagePicker configuration options
  */
 const imagePickerOptions = {
-    title: 'Select an Attachment',
-    takePhotoButtonTitle: 'Take Photo',
-    chooseFromLibraryButtonTitle: 'Choose from Gallery',
-    customButtons: [{name: 'Document', title: 'Choose Document'}],
     storageOptions: {
         skipBackup: true,
     },
@@ -28,54 +35,76 @@ const documentPickerOptions = {
 };
 
 /**
- * Launch the DocumentPicker. Results are in same format as ImagePicker, so we can pass the repsonse to the
- * callback as is.
+ * Inform the users when they need to grant camera access and guide them to settings
+ */
+function showPermissionsAlert() {
+    Alert.alert(
+        'Camera Permission Required',
+        'Expensify.cash does not have access to your camera, please enable the permission and try again.',
+        [
+            {
+                text: 'Cancel',
+                style: 'cancel',
+            },
+            {
+                text: 'Settings',
+                onPress: () => Linking.openSettings(),
+            },
+        ],
+        {cancelable: false},
+    );
+}
+
+/**
+ * A generic handling when we don't know the exact reason for an error
  *
- * @param {Object} callback
  */
-function showDocumentPicker(callback) {
-    RNDocumentPicker.pick(documentPickerOptions).then((results) => {
-        callback(results);
-    }).catch((error) => {
+function showGeneralAlert() {
+    Alert.alert(
+        'Attachment Error',
+        'An error occurred while selecting an attachment, please try again',
+    );
+}
+
+/**
+ * Launch the DocumentPicker. Results are in the same format as ImagePicker
+ *
+ * @returns {Promise<DocumentPickerResponse>}
+ */
+function showDocumentPicker() {
+    return RNDocumentPicker.pick(documentPickerOptions).catch((error) => {
         if (!RNDocumentPicker.isCancel(error)) {
+            showGeneralAlert(error.message);
             throw error;
         }
     });
 }
 
 /**
- * Launch the AttachmentPicker. We display the ImagePicker first, as the document option is displayed as a
- * custom ImagePicker list item.
+ * Common image picker handling
  *
- * @param {Object} callback
+ * @param {function} imagePickerFunc - RNImagePicker.launchCamera or RNImagePicker.launchImageLibrary
+ * @returns {Promise<ImagePickerResponse>}
  */
-function show(callback) {
-    RNImagePicker.showImagePicker(imagePickerOptions, (response) => {
-        if (response.error) {
-            if (response.error === 'Camera permissions not granted') {
-                Alert.alert(
-                    // eslint-disable-next-line max-len
-                    'ExpensifyCash does not have access to your camera. To enable access, tap Settings and turn on Camera.',
-                    '',
-                    [
-                        {
-                            text: 'Cancel',
-                            style: 'cancel',
-                        },
-                        {
-                            text: 'Settings',
-                            onPress: () => Linking.openURL('app-settings:'),
-                        },
-                    ],
-                    {cancelable: false},
-                );
+function showImagePicker(imagePickerFunc) {
+    return new Promise((resolve, reject) => {
+        imagePickerFunc(imagePickerOptions, (response) => {
+            if (response.error) {
+                switch (response.error) {
+                    case 'Camera permissions not granted':
+                    case 'Permissions weren\'t granted':
+                        showPermissionsAlert();
+                        break;
+                    default:
+                        showGeneralAlert(response.error);
+                        break;
+                }
+
+                reject(new Error(`Error during attachment selection: ${response.error}`));
             }
-            console.debug(`Error during attachment selection: ${response.error}`);
-        } else if (response.customButton) {
-            showDocumentPicker(callback);
-        } else if (!response.didCancel) {
-            callback(response);
-        }
+
+            resolve(response);
+        });
     });
 }
 
@@ -94,43 +123,128 @@ function getDataForUpload(fileData) {
     };
 }
 
-const propTypes = {
-    children: PropTypes.func.isRequired,
-};
-
 /**
  * This component renders a function as a child and
  * returns a "show attachment picker" method that takes
- * a callback. This is the web/mWeb/desktop version since
- * on iOS Safari we must append a hidden input to the DOM
- * and listen to onChange event. When the show method is
- * called an attachment
- *
- * @example
- * <AttachmentPicker>
- * {({openPicker}) => (
- *     <Button
- *         onPress={() => {
- *             openPicker({
- *                 onPicked: (file) => {
- *                     // Display or upload File
- *                 },
- *             });
- *         }}
- *     />
- * )}
- * </AttachmentPicker>
- *
- * @returns {Function}
+ * a callback. This is the ios/android implementation
+ * opening a modal with attachment options
  */
-const AttachmentPicker = ({children}) => children({
-    openPicker: ({onPicked}) => {
-        show((response) => {
-            onPicked(getDataForUpload(response));
+class AttachmentPicker extends Component {
+    constructor(...args) {
+        super(...args);
+
+        this.state = {
+            isVisible: false,
+            result: null,
+            onPicked: () => {},
+        };
+
+        this.menuItemData = [
+            {
+                icon: Camera,
+                text: 'Take Photo',
+                pickAttachment: () => showImagePicker(RNImagePicker.launchCamera),
+            },
+            {
+                icon: Gallery,
+                text: 'Choose from Gallery',
+                pickAttachment: () => showImagePicker(RNImagePicker.launchImageLibrary),
+            },
+            {
+                icon: Paperclip,
+                text: 'Choose Document',
+                pickAttachment: showDocumentPicker,
+            },
+        ];
+
+        this.setResult = this.setResult.bind(this);
+        this.close = this.close.bind(this);
+        this.completeAttachmentSelection = this.completeAttachmentSelection.bind(this);
+    }
+
+    /**
+     * Store the selected attachment mapped to an appropriate file interface
+     *
+     * @param {ImagePickerResponse|DocumentPickerResponse} attachment
+     */
+    setResult(attachment) {
+        if (attachment && !attachment.didCancel && !attachment.error) {
+            const result = getDataForUpload(attachment);
+            this.setState({result});
+        }
+    }
+
+    /**
+     * Triggers the `onPicked` callback with the selected attachment
+     */
+    completeAttachmentSelection() {
+        if (this.state.result) {
+            this.state.onPicked(this.state.result);
+        }
+    }
+
+    /**
+     * Opens the attachment modal
+     *
+     * @param {function} onPicked A callback that will be called with the selected attachment
+     */
+    open(onPicked) {
+        this.setState({
+            isVisible: true,
+            result: null,
+            onPicked,
         });
-    },
-});
+    }
+
+    /**
+     * Closes the attachment modal
+     */
+    close() {
+        this.setState({isVisible: false});
+    }
+
+    /**
+     * Call the `children` renderProp with the interface defined in propTypes
+     *
+     * @returns {React.ReactNode}
+     */
+    renderChildren() {
+        return this.props.children({
+            openPicker: ({onPicked}) => this.open(onPicked),
+        });
+    }
+
+    render() {
+        return (
+            <>
+                <Popover
+                    onClose={this.close}
+                    isVisible={this.state.isVisible}
+                    anchorPosition={styles.createMenuPosition}
+                    onModalHide={this.completeAttachmentSelection}
+                >
+                    <View style={this.props.isSmallScreenWidth ? {} : styles.createMenuContainer}>
+                        {
+                            this.menuItemData.map(({icon, text, pickAttachment}) => (
+                                <MenuItem
+                                    key={text}
+                                    icon={icon}
+                                    title={text}
+                                    onPress={() => pickAttachment()
+                                        .then(this.setResult)
+                                        .then(this.close)
+                                        .catch(console.error)}
+                                />
+                            ))
+                        }
+                    </View>
+                </Popover>
+                {this.renderChildren()}
+            </>
+        );
+    }
+}
 
 AttachmentPicker.propTypes = propTypes;
 AttachmentPicker.displayName = 'AttachmentPicker';
-export default AttachmentPicker;
+export default withWindowDimensions(AttachmentPicker);
diff --git a/src/components/Icon/Expensicons.js b/src/components/Icon/Expensicons.js
index fbc964a95bcf..d40bcc347ed3 100644
--- a/src/components/Icon/Expensicons.js
+++ b/src/components/Icon/Expensicons.js
@@ -25,6 +25,8 @@ import Wallet from '../../../assets/images/wallet.svg';
 import Lock from '../../../assets/images/lock.svg';
 import ArrowRight from '../../../assets/images/arrow-right.svg';
 import Upload from '../../../assets/images/upload.svg';
+import Camera from '../../../assets/images/camera.svg';
+import Gallery from '../../../assets/images/gallery.svg';
 
 export {
     BackArrow,
@@ -54,4 +56,6 @@ export {
     Lock,
     ArrowRight,
     Upload,
+    Camera,
+    Gallery,
 };
diff --git a/src/pages/home/report/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose.js
index 85eb443286c1..42879452601e 100644
--- a/src/pages/home/report/ReportActionCompose.js
+++ b/src/pages/home/report/ReportActionCompose.js
@@ -60,6 +60,7 @@ class ReportActionCompose extends React.Component {
         this.triggerSubmitShortcut = this.triggerSubmitShortcut.bind(this);
         this.submitForm = this.submitForm.bind(this);
         this.setIsFocused = this.setIsFocused.bind(this);
+        this.focus = this.focus.bind(this);
         this.comment = props.comment;
 
         this.state = {
@@ -73,7 +74,7 @@ class ReportActionCompose extends React.Component {
     componentDidUpdate(prevProps) {
         // When any modal goes from visible to hidden, bring focus to the compose field
         if (prevProps.modal.isVisible && !this.props.modal.isVisible) {
-            this.setIsFocused(true);
+            this.focus();
         }
     }
 
@@ -84,9 +85,6 @@ class ReportActionCompose extends React.Component {
      */
     setIsFocused(shouldHighlight) {
         this.setState({isFocused: shouldHighlight});
-        if (shouldHighlight && this.textInput) {
-            this.textInput.focus();
-        }
     }
 
     /**
@@ -99,7 +97,7 @@ class ReportActionCompose extends React.Component {
     }
 
     /**
-     * Updates the visiblity state of the menu
+     * Updates the visibility state of the menu
      *
      * @param {Boolean} isMenuVisible
      */
@@ -107,6 +105,15 @@ class ReportActionCompose extends React.Component {
         this.setState({isMenuVisible});
     }
 
+    /**
+     * Focus the composer text input
+     */
+    focus() {
+        if (this.textInput) {
+            this.textInput.focus();
+        }
+    }
+
     /**
      * Save our report comment in Onyx. We debounce this method in the constructor so that it's not called too often
      * to update Onyx and re-render this component.
@@ -208,6 +215,10 @@ class ReportActionCompose extends React.Component {
                                                 onPress={(e) => {
                                                     e.preventDefault();
                                                     this.setMenuVisibility(true);
+
+                                                    /* Keep last focus inside the input so that focus is restored
+                                                     on modal close. Otherwise breaks modal 2 modal transition */
+                                                    this.focus();
                                                 }}
                                                 style={styles.chatItemAttachButton}
                                                 underlayColor={themeColors.componentBG}
@@ -223,11 +234,11 @@ class ReportActionCompose extends React.Component {
                                                         icon: Paperclip,
                                                         text: 'Upload Photo',
                                                         onSelected: () => {
-                                                            setTimeout(() => {
-                                                                openPicker({
-                                                                    onPicked: file => displayFileInModal({file}),
-                                                                });
-                                                            }, 10);
+                                                            openPicker({
+                                                                onPicked: (file) => {
+                                                                    displayFileInModal({file});
+                                                                },
+                                                            });
                                                         },
                                                     },
                                                 ]}
