diff --git a/homeassistant/components/panel_custom.py b/homeassistant/components/panel_custom.py
index 473d44f3b55156194feb21c825f2cdd77fbf28d9..4659578ae27e9d37a0a3a8d6554dedb9d560d76e 100644
--- a/homeassistant/components/panel_custom.py
+++ b/homeassistant/components/panel_custom.py
@@ -4,7 +4,6 @@ Register a custom front end panel.
 For more details about this component, please refer to the documentation at
 https://home-assistant.io/components/panel_custom/
 """
-import asyncio
 import logging
 import os
 
@@ -21,27 +20,33 @@ CONF_SIDEBAR_ICON = 'sidebar_icon'
 CONF_URL_PATH = 'url_path'
 CONF_CONFIG = 'config'
 CONF_WEBCOMPONENT_PATH = 'webcomponent_path'
+CONF_JS_URL = 'js_url'
+CONF_EMBED_IFRAME = 'embed_iframe'
+CONF_TRUST_EXTERNAL_SCRIPT = 'trust_external_script'
 
 DEFAULT_ICON = 'mdi:bookmark'
+LEGACY_URL = '/api/panel_custom/{}'
 
 PANEL_DIR = 'panels'
 
 CONFIG_SCHEMA = vol.Schema({
-    DOMAIN: vol.All(cv.ensure_list, [{
-        vol.Required(CONF_COMPONENT_NAME): cv.slug,
+    DOMAIN: vol.All(cv.ensure_list, [vol.Schema({
+        vol.Required(CONF_COMPONENT_NAME): cv.string,
         vol.Optional(CONF_SIDEBAR_TITLE): cv.string,
         vol.Optional(CONF_SIDEBAR_ICON, default=DEFAULT_ICON): cv.icon,
         vol.Optional(CONF_URL_PATH): cv.string,
-        vol.Optional(CONF_CONFIG): cv.match_all,
+        vol.Optional(CONF_CONFIG): dict,
         vol.Optional(CONF_WEBCOMPONENT_PATH): cv.isfile,
-    }])
+        vol.Optional(CONF_JS_URL): cv.string,
+        vol.Optional(CONF_EMBED_IFRAME, default=False): cv.boolean,
+        vol.Optional(CONF_TRUST_EXTERNAL_SCRIPT, default=False): cv.boolean,
+    })])
 }, extra=vol.ALLOW_EXTRA)
 
 _LOGGER = logging.getLogger(__name__)
 
 
-@asyncio.coroutine
-def async_setup(hass, config):
+async def async_setup(hass, config):
     """Initialize custom panel."""
     success = False
 
@@ -52,17 +57,39 @@ def async_setup(hass, config):
         if panel_path is None:
             panel_path = hass.config.path(PANEL_DIR, '{}.html'.format(name))
 
-        if not os.path.isfile(panel_path):
+        custom_panel_config = {
+            'name': name,
+            'embed_iframe': panel[CONF_EMBED_IFRAME],
+            'trust_external': panel[CONF_TRUST_EXTERNAL_SCRIPT],
+        }
+
+        if CONF_JS_URL in panel:
+            custom_panel_config['js_url'] = panel[CONF_JS_URL]
+
+        elif not await hass.async_add_job(os.path.isfile, panel_path):
             _LOGGER.error('Unable to find webcomponent for %s: %s',
                           name, panel_path)
             continue
 
-        yield from hass.components.frontend.async_register_panel(
-            name, panel_path,
+        else:
+            url = LEGACY_URL.format(name)
+            hass.http.register_static_path(url, panel_path)
+            custom_panel_config['html_url'] = LEGACY_URL.format(name)
+
+        if CONF_CONFIG in panel:
+            # Make copy because we're mutating it
+            config = dict(panel[CONF_CONFIG])
+        else:
+            config = {}
+
+        config['_panel_custom'] = custom_panel_config
+
+        await hass.components.frontend.async_register_built_in_panel(
+            component_name='custom',
             sidebar_title=panel.get(CONF_SIDEBAR_TITLE),
             sidebar_icon=panel.get(CONF_SIDEBAR_ICON),
             frontend_url_path=panel.get(CONF_URL_PATH),
-            config=panel.get(CONF_CONFIG),
+            config=config
         )
 
         success = True
diff --git a/tests/components/test_panel_custom.py b/tests/components/test_panel_custom.py
index d33221da2a7af2aba5c9f5e1e9a6d72bc5d7583d..596aa1b3c0b25c6ee047e931800165a0254286eb 100644
--- a/tests/components/test_panel_custom.py
+++ b/tests/components/test_panel_custom.py
@@ -1,23 +1,11 @@
 """The tests for the panel_custom component."""
-import asyncio
 from unittest.mock import Mock, patch
 
-import pytest
-
 from homeassistant import setup
 from homeassistant.components import frontend
 
-from tests.common import mock_component
-
-
-@pytest.fixture(autouse=True)
-def mock_frontend_loaded(hass):
-    """Mock frontend is loaded."""
-    mock_component(hass, 'frontend')
 
-
-@asyncio.coroutine
-def test_webcomponent_custom_path_not_found(hass):
+async def test_webcomponent_custom_path_not_found(hass):
     """Test if a web component is found in config panels dir."""
     filename = 'mock.file'
 
@@ -33,45 +21,96 @@ def test_webcomponent_custom_path_not_found(hass):
     }
 
     with patch('os.path.isfile', Mock(return_value=False)):
-        result = yield from setup.async_setup_component(
+        result = await setup.async_setup_component(
             hass, 'panel_custom', config
         )
         assert not result
         assert len(hass.data.get(frontend.DATA_PANELS, {})) == 0
 
 
-@asyncio.coroutine
-def test_webcomponent_custom_path(hass):
+async def test_webcomponent_custom_path(hass):
     """Test if a web component is found in config panels dir."""
     filename = 'mock.file'
 
     config = {
         'panel_custom': {
-            'name': 'todomvc',
+            'name': 'todo-mvc',
             'webcomponent_path': filename,
             'sidebar_title': 'Sidebar Title',
             'sidebar_icon': 'mdi:iconicon',
             'url_path': 'nice_url',
-            'config': 5,
+            'config': {
+                'hello': 'world',
+            }
         }
     }
 
     with patch('os.path.isfile', Mock(return_value=True)):
         with patch('os.access', Mock(return_value=True)):
-            result = yield from setup.async_setup_component(
+            result = await setup.async_setup_component(
                 hass, 'panel_custom', config
             )
             assert result
 
             panels = hass.data.get(frontend.DATA_PANELS, [])
 
-            assert len(panels) == 1
+            assert panels
             assert 'nice_url' in panels
 
             panel = panels['nice_url']
 
-            assert panel.config == 5
+            assert panel.config == {
+                'hello': 'world',
+                '_panel_custom': {
+                    'html_url': '/api/panel_custom/todo-mvc',
+                    'name': 'todo-mvc',
+                    'embed_iframe': False,
+                    'trust_external': False,
+                },
+            }
             assert panel.frontend_url_path == 'nice_url'
             assert panel.sidebar_icon == 'mdi:iconicon'
             assert panel.sidebar_title == 'Sidebar Title'
-            assert panel.path == filename
+
+
+async def test_js_webcomponent(hass):
+    """Test if a web component is found in config panels dir."""
+    config = {
+        'panel_custom': {
+            'name': 'todo-mvc',
+            'js_url': '/local/bla.js',
+            'sidebar_title': 'Sidebar Title',
+            'sidebar_icon': 'mdi:iconicon',
+            'url_path': 'nice_url',
+            'config': {
+                'hello': 'world',
+            },
+            'embed_iframe': True,
+            'trust_external_script': True,
+        }
+    }
+
+    result = await setup.async_setup_component(
+        hass, 'panel_custom', config
+    )
+    assert result
+
+    panels = hass.data.get(frontend.DATA_PANELS, [])
+
+    assert panels
+    assert 'nice_url' in panels
+
+    panel = panels['nice_url']
+
+    assert panel.config == {
+        'hello': 'world',
+        '_panel_custom': {
+            'js_url': '/local/bla.js',
+            'name': 'todo-mvc',
+            'embed_iframe': True,
+            'trust_external': True,
+        }
+    }
+    assert panel.frontend_url_path == 'nice_url'
+    assert panel.sidebar_icon == 'mdi:iconicon'
+    assert panel.sidebar_title == 'Sidebar Title'