diff --git a/public/app/features/playlist/PlaylistPage.test.tsx b/public/app/features/playlist/PlaylistPage.test.tsx
new file mode 100644
index 00000000000..3937c8580c1
--- /dev/null
+++ b/public/app/features/playlist/PlaylistPage.test.tsx
@@ -0,0 +1,83 @@
+import React from 'react';
+import { render, waitFor } from '@testing-library/react';
+import { PlaylistPage, PlaylistPageProps } from './PlaylistPage';
+import { locationService } from '../../../../packages/grafana-runtime/src';
+
+const fnMock = jest.fn();
+
+jest.mock('@grafana/runtime', () => ({
+  ...((jest.requireActual('@grafana/runtime') as unknown) as object),
+  getBackendSrv: () => ({
+    get: fnMock,
+  }),
+}));
+
+jest.mock('app/core/services/context_srv', () => ({
+  contextSrv: {
+    isEditor: true,
+  },
+}));
+
+function getTestContext(propOverrides?: object) {
+  const props: PlaylistPageProps = {
+    navModel: {
+      main: {
+        text: 'Playlist',
+      },
+      node: {
+        text: 'playlist',
+      },
+    },
+    route: {
+      path: '/playlists',
+      component: jest.fn(),
+    },
+    queryParams: { state: 'ok' },
+    match: { params: { name: 'playlist', sourceName: 'test playlist' }, isExact: false, url: 'asdf', path: '' },
+    history: locationService.getHistory(),
+    location: { pathname: '', hash: '', search: '', state: '' },
+  };
+
+  Object.assign(props, propOverrides);
+
+  return render();
+}
+
+describe('PlaylistPage', () => {
+  describe('when mounted without a playlist', () => {
+    it('page should load', () => {
+      fnMock.mockResolvedValue([]);
+      const { getByText } = getTestContext();
+      expect(getByText(/loading/i)).toBeInTheDocument();
+    });
+    it('then show empty list', async () => {
+      const { getByText } = getTestContext();
+      await waitFor(() => getByText('There are no playlists created yet'));
+    });
+  });
+  describe('when mounted with a playlist', () => {
+    it('page should load', () => {
+      fnMock.mockResolvedValue([
+        {
+          id: 0,
+          name: 'A test playlist',
+          interval: '10m',
+          items: [
+            { title: 'First item', type: 'dashboard_by_id', order: 1, value: '1' },
+            { title: 'Middle item', type: 'dashboard_by_id', order: 2, value: '2' },
+            { title: 'Last item', type: 'dashboard_by_tag', order: 2, value: 'Last item' },
+          ],
+        },
+      ]);
+      const { getByText } = getTestContext();
+      expect(getByText(/loading/i)).toBeInTheDocument();
+    });
+    it('then playlist title and buttons should appear on the page', async () => {
+      const { getByRole, getByText } = getTestContext();
+      await waitFor(() => getByText('A test playlist'));
+      expect(getByRole('button', { name: /Start playlist/i })).toBeInTheDocument();
+      expect(getByRole('link', { name: /Edit playlist/i })).toBeInTheDocument();
+      expect(getByRole('button', { name: /Delete playlist/i })).toBeInTheDocument();
+    });
+  });
+});
diff --git a/public/app/features/playlist/PlaylistPage.tsx b/public/app/features/playlist/PlaylistPage.tsx
index ccaae7c9cd8..69a11f8321f 100644
--- a/public/app/features/playlist/PlaylistPage.tsx
+++ b/public/app/features/playlist/PlaylistPage.tsx
@@ -1,32 +1,45 @@
 import React, { FC, useState } from 'react';
 import { connect, MapStateToProps } from 'react-redux';
-import { NavModel, SelectableValue, urlUtil } from '@grafana/data';
+import { NavModel } from '@grafana/data';
 import Page from 'app/core/components/Page/Page';
 import { StoreState } from 'app/types';
 import { GrafanaRouteComponentProps } from '../../core/navigation/types';
 import { getNavModel } from 'app/core/selectors/navModel';
 import { useAsync } from 'react-use';
-import { getBackendSrv, locationService } from '@grafana/runtime';
 import { PlaylistDTO } from './types';
-import { Button, Card, Checkbox, Field, LinkButton, Modal, RadioButtonGroup, VerticalGroup } from '@grafana/ui';
-import { contextSrv } from 'app/core/core';
+import { Button, Card, ConfirmModal, LinkButton } from '@grafana/ui';
+import { contextSrv } from 'app/core/services/context_srv';
 import PageActionBar from 'app/core/components/PageActionBar/PageActionBar';
 import EmptyListCTA from '../../core/components/EmptyListCTA/EmptyListCTA';
+import { deletePlaylist, getAllPlaylist } from './api';
+import { StartModal } from './StartModal';
 
 interface ConnectedProps {
   navModel: NavModel;
 }
 
-interface Props extends ConnectedProps, GrafanaRouteComponentProps {}
+export interface PlaylistPageProps extends ConnectedProps, GrafanaRouteComponentProps {}
 
-export const PlaylistPage: FC = ({ navModel }) => {
+export const PlaylistPage: FC = ({ navModel }) => {
   const [searchQuery, setSearchQuery] = useState('');
   const [startPlaylist, setStartPlaylist] = useState();
+  const [playlistToDelete, setPlaylistToDelete] = useState();
+  const [forcePlaylistsFetch, setForcePlaylistsFetch] = useState(0);
 
   const { value: playlists, loading } = useAsync(async () => {
-    return getBackendSrv().get('/api/playlists', { query: searchQuery }) as Promise;
-  });
+    return getAllPlaylist(searchQuery) as Promise;
+  }, [forcePlaylistsFetch]);
   const hasPlaylists = playlists && playlists.length > 0;
+  const onDismissDelete = () => setPlaylistToDelete(undefined);
+  const onDeletePlaylist = () => {
+    if (!playlistToDelete) {
+      return;
+    }
+    deletePlaylist(playlistToDelete.id).finally(() => {
+      setForcePlaylistsFetch(forcePlaylistsFetch + 1);
+      setPlaylistToDelete(undefined);
+    });
+  };
 
   let content = (
      = ({ navModel }) => {
                 Start playlist
               
               {contextSrv.isEditor && (
-                
-                  Edit playlist
-                
+                <>
+                  
+                    Edit playlist
+                  
+                  
+                >
               )}
             
           
@@ -61,7 +84,6 @@ export const PlaylistPage: FC = ({ navModel }) => {
       >
     );
   }
-
   return (
     
       
@@ -73,6 +95,16 @@ export const PlaylistPage: FC = ({ navModel }) => {
           />
         )}
         {content}
+        {playlistToDelete && (
+          
+        )}
         {startPlaylist &&  setStartPlaylist(undefined)} />}
       
     
@@ -84,52 +116,3 @@ const mapStateToProps: MapStateToProps = (state:
 });
 
 export default connect(mapStateToProps)(PlaylistPage);
-
-export interface StartModalProps {
-  playlist: PlaylistDTO;
-  onDismiss: () => void;
-}
-
-export const StartModal: FC = ({ playlist, onDismiss }) => {
-  const [mode, setMode] = useState(false);
-  const [autoFit, setAutofit] = useState(false);
-
-  const modes: Array> = [
-    { label: 'Normal', value: false },
-    { label: 'TV', value: 'tv' },
-    { label: 'Kiosk', value: true },
-  ];
-
-  const onStart = () => {
-    const params: any = {};
-    if (mode) {
-      params.kiosk = mode;
-    }
-    if (autoFit) {
-      params.autofitpanels = true;
-    }
-    locationService.push(urlUtil.renderUrl(`/playlists/play/${playlist.id}`, params));
-  };
-
-  return (
-    
-      
-        
-          
-        
-         setAutofit(e.currentTarget.checked)}
-        />
-      
-      
-        
-      
-    
-  );
-};
diff --git a/public/app/features/playlist/StartModal.tsx b/public/app/features/playlist/StartModal.tsx
new file mode 100644
index 00000000000..371eecb8bec
--- /dev/null
+++ b/public/app/features/playlist/StartModal.tsx
@@ -0,0 +1,54 @@
+import React, { FC, useState } from 'react';
+import { SelectableValue, urlUtil } from '@grafana/data';
+import { locationService } from '@grafana/runtime';
+import { PlaylistDTO } from './types';
+import { Button, Checkbox, Field, Modal, RadioButtonGroup, VerticalGroup } from '@grafana/ui';
+
+export interface StartModalProps {
+  playlist: PlaylistDTO;
+  onDismiss: () => void;
+}
+
+export const StartModal: FC = ({ playlist, onDismiss }) => {
+  const [mode, setMode] = useState(false);
+  const [autoFit, setAutofit] = useState(false);
+
+  const modes: Array> = [
+    { label: 'Normal', value: false },
+    { label: 'TV', value: 'tv' },
+    { label: 'Kiosk', value: true },
+  ];
+
+  const onStart = () => {
+    const params: any = {};
+    if (mode) {
+      params.kiosk = mode;
+    }
+    if (autoFit) {
+      params.autofitpanels = true;
+    }
+    locationService.push(urlUtil.renderUrl(`/playlists/play/${playlist.id}`, params));
+  };
+
+  return (
+    
+      
+        
+          
+        
+         setAutofit(e.currentTarget.checked)}
+        />
+      
+      
+        
+      
+    
+  );
+};
diff --git a/public/app/features/playlist/api.ts b/public/app/features/playlist/api.ts
index 2c588c10b4f..d7b6f2739a0 100644
--- a/public/app/features/playlist/api.ts
+++ b/public/app/features/playlist/api.ts
@@ -1,16 +1,20 @@
 import { getBackendSrv } from '@grafana/runtime';
 
-import { Playlist } from './types';
+import { Playlist, PlaylistDTO } from './types';
 import { dispatch } from '../../store/store';
 import { notifyApp } from '../../core/actions';
 import { createErrorNotification, createSuccessNotification } from '../../core/copy/appNotification';
 
 export async function createPlaylist(playlist: Playlist) {
-  await withErrorHandling(async () => await getBackendSrv().post('/api/playlists', playlist));
+  await withErrorHandling(() => getBackendSrv().post('/api/playlists', playlist));
 }
 
 export async function updatePlaylist(id: number, playlist: Playlist) {
-  await withErrorHandling(async () => await getBackendSrv().put(`/api/playlists/${id}`, playlist));
+  await withErrorHandling(() => getBackendSrv().put(`/api/playlists/${id}`, playlist));
+}
+
+export async function deletePlaylist(id: number) {
+  await withErrorHandling(() => getBackendSrv().delete(`/api/playlists/${id}`), 'Playlist deleted');
 }
 
 export async function getPlaylist(id: number): Promise {
@@ -18,10 +22,15 @@ export async function getPlaylist(id: number): Promise {
   return result;
 }
 
-async function withErrorHandling(apiCall: () => Promise) {
+export async function getAllPlaylist(query: string): Promise {
+  const result: PlaylistDTO[] = await getBackendSrv().get('/api/playlists/', { query });
+  return result;
+}
+
+async function withErrorHandling(apiCall: () => Promise, message = 'Playlist saved') {
   try {
     await apiCall();
-    dispatch(notifyApp(createSuccessNotification('Playlist saved')));
+    dispatch(notifyApp(createSuccessNotification(message)));
   } catch (e) {
     dispatch(notifyApp(createErrorNotification('Unable to save playlist', e)));
   }