diff --git a/src/components/library-item/library-item.css b/src/components/library-item/library-item.css
index 760153eaedebf041aca9d35e60bf9450056ce8de..79aebf79693435b0183591f64c6797967f1fb07d 100644
--- a/src/components/library-item/library-item.css
+++ b/src/components/library-item/library-item.css
@@ -201,42 +201,3 @@
 [dir="rtl"] .coming-soon-text {
     transform: translate(calc(-2 * $space), calc(2 * $space));
 }
-
-.play-button {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-
-    overflow: hidden;  /* Mask the icon animation */
-    width: 2.5rem;
-    height: 2.5rem;
-    background-color: $sound-primary;
-    color: $ui-white;
-    border-radius: 50%;
-    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
-    user-select: none;
-    cursor: pointer;
-    transition: all 0.15s ease-out;
-}
-
-.play-button {
-    position: absolute;
-    top: .5rem;
-    z-index: auto;
-}
-
-.play-button:focus {
-    outline: none;
-}
-
-.play-icon {
-  width: 50%;
-}
-
-[dir="ltr"] .play-button {
-    left: .5rem;
-}
-
-[dir="rtl"] .play-button {
-    right: .5rem;
-}
diff --git a/src/components/library-item/library-item.jsx b/src/components/library-item/library-item.jsx
index f63f92d39e45bc30fff1902fc306ef558990abc0..504be2b66949531daf7e829f5808ab2fa04f8e33 100644
--- a/src/components/library-item/library-item.jsx
+++ b/src/components/library-item/library-item.jsx
@@ -3,18 +3,12 @@ import PropTypes from 'prop-types';
 import React from 'react';
 
 import Box from '../box/box.jsx';
+import PlayButton from '../play-button/play-button.jsx';
 import styles from './library-item.css';
 import classNames from 'classnames';
 
 import bluetoothIconURL from './bluetooth.svg';
 import internetConnectionIconURL from './internet-connection.svg';
-import playIcon from './icon--play.svg';
-import stopIcon from './icon--stop.svg';
-
-const preventClick = e => {
-    e.stopPropagation();
-    e.preventDefault();
-};
 
 /* eslint-disable react/prefer-stateless-function */
 class LibraryItemComponent extends React.PureComponent {
@@ -140,19 +134,11 @@ class LibraryItemComponent extends React.PureComponent {
                 </Box>
                 <span className={styles.libraryItemName}>{this.props.name}</span>
                 {this.props.showPlayButton ? (
-                    <div
-                        aria-label="Play"
-                        className={styles.playButton}
-                        onClick={preventClick}
-                        onMouseDown={this.props.isPlaying ? this.props.onStop : this.props.onPlay}
-                        onMouseLeave={this.props.isPlaying ? this.props.onStop : null}
-                    >
-                        <img
-                            className={styles.playIcon}
-                            draggable={false}
-                            src={this.props.isPlaying ? stopIcon : playIcon}
-                        />
-                    </div>
+                    <PlayButton
+                        isPlaying={this.props.isPlaying}
+                        onPlay={this.props.onPlay}
+                        onStop={this.props.onStop}
+                    />
                 ) : null}
             </Box>
         );
diff --git a/src/components/library/library.jsx b/src/components/library/library.jsx
index f2c8e770b2e6d7069cfae5546a13cf68fd49c654..259e922ff3bcc03b880a037de7030b2b1fe9ed24 100644
--- a/src/components/library/library.jsx
+++ b/src/components/library/library.jsx
@@ -71,10 +71,19 @@ class LibraryComponent extends React.Component {
         this.props.onRequestClose();
     }
     handleTagClick (tag) {
-        this.setState({
-            filterQuery: '',
-            selectedTag: tag.toLowerCase()
-        });
+        if (this.state.playingItem === null) {
+            this.setState({
+                ilterQuery: '',
+                selectedTag: tag.toLowerCase()
+            });
+        } else {
+            const playingId = this.state.playingItem;
+            this.setState({
+                filterQuery: '',
+                playingItem: null,
+                selectedTag: tag.toLowerCase()
+            }, this.props.onItemMouseLeave(this.getFilteredData()[[playingId]]));
+        }
     }
     handleMouseEnter (id) {
         // don't restart if mouse over already playing item
@@ -99,10 +108,19 @@ class LibraryComponent extends React.Component {
         }
     }
     handleFilterChange (event) {
-        this.setState({
-            filterQuery: event.target.value,
-            selectedTag: ALL_TAG.tag
-        });
+        if (this.state.playingItem === null) {
+            this.setState({
+                filterQuery: event.target.value,
+                selectedTag: ALL_TAG.tag
+            });
+        } else {
+            const playingId = this.state.playingItem;
+            this.setState({
+                filterQuery: event.target.value,
+                playingItem: null,
+                selectedTag: ALL_TAG.tag
+            }, this.props.onItemMouseLeave(this.getFilteredData()[[playingId]]));
+        }
     }
     handleFilterClear () {
         this.setState({filterQuery: ''});
diff --git a/src/components/library-item/icon--play.svg b/src/components/play-button/icon--play.svg
similarity index 100%
rename from src/components/library-item/icon--play.svg
rename to src/components/play-button/icon--play.svg
diff --git a/src/components/library-item/icon--stop.svg b/src/components/play-button/icon--stop.svg
similarity index 100%
rename from src/components/library-item/icon--stop.svg
rename to src/components/play-button/icon--stop.svg
diff --git a/src/components/play-button/play-button.css b/src/components/play-button/play-button.css
new file mode 100644
index 0000000000000000000000000000000000000000..fbc901e66ca32b8c54911315bfedc270ac068fd8
--- /dev/null
+++ b/src/components/play-button/play-button.css
@@ -0,0 +1,42 @@
+
+@import "../../css/colors.css";
+@import "../../css/units.css";
+
+.play-button {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+
+    overflow: hidden;  /* Mask the icon animation */
+    width: 2.5rem;
+    height: 2.5rem;
+    background-color: $sound-primary;
+    color: $ui-white;
+    border-radius: 50%;
+    font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
+    user-select: none;
+    cursor: pointer;
+    transition: all 0.15s ease-out;
+}
+
+.play-button {
+    position: absolute;
+    top: .5rem;
+    z-index: auto;
+}
+
+.play-button:focus {
+    outline: none;
+}
+
+.play-icon {
+  width: 50%;
+}
+
+[dir="ltr"] .play-button {
+    left: .5rem;
+}
+
+[dir="rtl"] .play-button {
+    right: .5rem;
+}
diff --git a/src/components/play-button/play-button.jsx b/src/components/play-button/play-button.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..8071ce849c62b349417be8b305f8f7cd9bd8be17
--- /dev/null
+++ b/src/components/play-button/play-button.jsx
@@ -0,0 +1,148 @@
+import PropTypes from 'prop-types';
+import React from 'react';
+import classNames from 'classnames';
+import bindAll from 'lodash.bindall';
+
+import {defineMessages, injectIntl, intlShape} from 'react-intl';
+
+import styles from './play-button.css';
+
+import playIcon from './icon--play.svg';
+import stopIcon from './icon--stop.svg';
+
+const messages = defineMessages({
+    play: {
+        id: 'gui.playButton.play',
+        description: 'Title of the button to start playing the sound',
+        defaultMessage: 'Play'
+    },
+    stop: {
+        id: 'gui.playButton.stop',
+        description: 'Title of the button to stop the sound',
+        defaultMessage: 'Stop'
+    }
+});
+
+class PlayButton extends React.Component {
+    constructor (props) {
+        super(props);
+        bindAll(this, [
+            'handleClick',
+            'handleMouseDown',
+            'handleMouseEnter',
+            'handleMouseLeave',
+            'handleTouchStart',
+            'setButtonRef'
+        ]);
+        this.state = {
+            touchStarted: false
+        };
+    }
+    getDerivedStateFromProps (props, state) {
+        // if touchStarted is true and it's not playing, the sound must have ended.
+        // reset the touchStarted state to allow the sound to be replayed
+        if (state.touchStarted && !props.isPlaying) {
+            return {
+                touchStarted: false
+            };
+        }
+        return null; // nothing changed
+    }
+    componentDidMount () {
+        // Touch start
+        this.buttonRef.addEventListener('touchstart', this.handleTouchStart);
+    }
+    componentWillUnmount () {
+        this.buttonRef.removeEventListener('touchstart', this.handleTouchStart);
+    }
+    handleClick (e) {
+        //  stop the click from propagating out of the button
+        e.stopPropagation();
+    }
+    handleMouseDown (e) {
+        // prevent default (focus) on mouseDown
+        e.preventDefault();
+        if (this.props.isPlaying) {
+            // stop sound and reset touch state
+            this.props.onStop();
+            if (this.state.touchstarted) this.setState({touchStarted: false});
+        } else {
+            this.props.onPlay();
+            if (this.state.touchstarted) {
+                // started on touch, but now clicked mouse
+                this.setState({touchStarted: false});
+            }
+        }
+    }
+    handleTouchStart (e) {
+        if (this.props.isPlaying) {
+            // If playing, stop sound, and reset touch state
+            e.preventDefault();
+            this.setState({touchStarted: false});
+            this.props.onStop();
+        } else {
+            // otherwise start playing, and set touch state
+            e.preventDefault();
+            this.setState({touchStarted: true});
+            this.props.onPlay();
+        }
+    }
+    handleMouseEnter (e) {
+        // start the sound if it's not already playing
+        e.preventDefault();
+        if (!this.props.isPlaying) {
+            this.props.onPlay();
+        }
+    }
+    handleMouseLeave () {
+        // stop the sound unless it was started by touch
+        if (this.props.isPlaying && !this.state.touchstarted) {
+            this.props.onStop();
+        }
+    }
+    setButtonRef (ref) {
+        this.buttonRef = ref;
+    }
+    render () {
+        const {
+            className,
+            intl,
+            isPlaying,
+            onPlay, // eslint-disable-line no-unused-vars
+            onStop // eslint-disable-line no-unused-vars
+        } = this.props;
+        const label = isPlaying ?
+            intl.formatMessage(messages.stop) :
+            intl.formatMessage(messages.play);
+
+        return (
+            <div
+                aria-label={label}
+                className={classNames(styles.playButton, className, {
+                    [styles.playing]: isPlaying
+                })}
+                ref={this.setButtonRef}
+                onClick={this.handleClick}
+                onMouseDown={this.handleMouseDown}
+                onMouseEnter={this.handleMouseEnter}
+                onMouseLeave={this.handleMouseLeave}
+            >
+                <img
+                    className={styles.playIcon}
+                    draggable={false}
+                    src={isPlaying ? stopIcon : playIcon}
+                />
+            </div>
+        );
+    }
+}
+
+PlayButton.propTypes = {
+    className: PropTypes.string,
+    intl: intlShape,
+    isPlaying: PropTypes.bool.isRequired,
+    onPlay: PropTypes.func.isRequired,
+    onStop: PropTypes.func.isRequired
+};
+
+export default injectIntl(PlayButton);
diff --git a/src/containers/library-item.jsx b/src/containers/library-item.jsx
index 75f6b2998ea7ec67ebbe913bd32193952f605871..8881a57cc0a77eedd12613469dab3a4b4621c704 100644
--- a/src/containers/library-item.jsx
+++ b/src/containers/library-item.jsx
@@ -39,7 +39,9 @@ class LibraryItem extends React.PureComponent {
         e.preventDefault();
     }
     handleFocus (id) {
-        this.handleMouseEnter(id);
+        if (!this.props.showPlayButton) {
+            this.handleMouseEnter(id);
+        }
     }
     handleKeyPress (e) {
         if (e.key === ' ' || e.key === 'Enter') {
@@ -48,30 +50,32 @@ class LibraryItem extends React.PureComponent {
         }
     }
     handleMouseEnter () {
-        this.props.onMouseEnter(this.props.id);
-        if (this.props.icons && this.props.icons.length) {
-            this.stopRotatingIcons();
-            this.setState({
-                isRotatingIcon: true
-            }, this.startRotatingIcons);
+        // only show hover effects on the item if not showing a play button
+        if (!this.props.showPlayButton) {
+            this.props.onMouseEnter(this.props.id);
+            if (this.props.icons && this.props.icons.length) {
+                this.stopRotatingIcons();
+                this.setState({
+                    isRotatingIcon: true
+                }, this.startRotatingIcons);
+            }
         }
     }
     handleMouseLeave () {
-        this.props.onMouseLeave(this.props.id);
-        if (this.props.icons && this.props.icons.length) {
-            this.setState({
-                isRotatingIcon: false
-            }, this.stopRotatingIcons);
+        // only show hover effects on the item if not showing a play button
+        if (!this.props.showPlayButton) {
+            this.props.onMouseLeave(this.props.id);
+            if (this.props.icons && this.props.icons.length) {
+                this.setState({
+                    isRotatingIcon: false
+                }, this.stopRotatingIcons);
+            }
         }
     }
-    handlePlay (e) {
-        e.stopPropagation(); // To prevent from bubbling back to handleClick
-        e.preventDefault();
+    handlePlay () {
         this.props.onMouseEnter(this.props.id);
     }
-    handleStop (e) {
-        e.stopPropagation(); // To prevent from bubbling back to handleClick
-        e.preventDefault();
+    handleStop () {
         this.props.onMouseLeave(this.props.id);
     }
     startRotatingIcons () {