Description
Opening this issue to propose the officially endorsed and documented method for embedding custom, local CSS and JavaScript in Dash apps.
This development for this issue has been sponsored by an organization. Many thanks!
If your company or organization would like to sponsor development, please reach out.
Background: In Dash, HTML tags and higher-level components are embedded in the App by assigning the app.layout
property to a nested hierarchy of Dash components (e.g. the components in the dash-core-components
or the dash-html-components
library). These components are serialized as JSON and then rendered client-side with React.js. On page load, Dash serves a very minimal HTML string which includes the blank container for rendering the app within, the component library's JavaScript and CSS, and a few meta HTML tags like the page title and the encoding (see
Lines 293 to 318 in 6a1809f
This architecture doesn't work well for embedding custom JavaScript scripts and CSS Stylesheets because these scripts and stylesheets usually need to be included in the HTML that is served on page load.
We will support user-supplied JavaScript and CSS through two enhancements:
Enhancement 1 - Automatic
- This "automatic" method will template in all stylesheets (CSS) and scripts (JavaScript) that are included in a
static
folder - These links will be included in alphabetical order
- These links will be included after the component library's stylesheets and scripts
- The server route (
/static/<path:string>
) for serving these files will be configured automatically by Dash
This method will be what most Dash users will use. It's very easy to use and easy to document ("To include custom CSS, just place your CSS files in static
folder. Dash will take care of the rest"). Since the files will be templated alphabetically, the user can control the order (if necessary) by prefixing ordered numbers to the files (e.g. 1-loading.css
, 2-app.css
).
With this method, we'll be able to add custom CSS processing middleware like minifying CSS or creating cache-busting URLs completely automatically.
If the user needs more control over the placement of these files, they can use the method in "Enhancement 2 - Manual Override".
Enhancement 2 - Manual Override
Currently on page load, Dash serves this HTML string:
Lines 293 to 318 in 6a1809f
This enhancement will make this overridable:
- The user will assign a HTML string or a function that returns an HTML string to a property on the
app
object (e.g.app.index
). - This HTML string will include several predefined template variable names that will correspond to the stylesheets and scripts that Dash needs to include to render the component libraries.
- The user can include extra meta tags in their template or even include other HTML around their Dash app container.
Here is an example:
def custom_index():
return '''
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta description="This is my dash app">
<title>My Custom Dash App</title>
<link ref="stylesheet" href="/static/my-custom-css-normalize.css">
{dash_renderer_css_bundle}
{dash_component_css_bundles}
<link ref="stylesheet" href="/static/my-component-css-override.css">
</head>
<body>
<div>
My Custom Header
</div>
<div id="react-entry-point">
<div class="_dash-loading">
Loading...
</div>
</div>
</body>
<footer>
<script type="javascript" src="/static/my-custom-javascript-bundle.js">
{dash_renderer_javascript_bundle}
{dash_component_javascript_bundles}
<script type="javascript" src="/static/my-custom-javascript-override.js">
</footer>
</html>
'''
app.index = custom_index
The following items will be required in creating an index string:
- The
dash_component_css_bundles
,dash_component_javascript_bundles
,dash_renderer_css_bundle
,dash_renderer_javascript_bundle
template names. Dash will look for these names and fill them in with the appropriate component CSS and JavaScript on page load. - A
<div/>
with anid
react-entry-point
. Dash's front-end will render the app within thisdiv
once the JavaScript has been evaluated.
Note the level of customizability in this solution:
- The user has full control over the location of the custom JS and CSS files with respect to the auto-templated CSS and JavaScript files
- The user can include custom meta tags in the
<head/>
. In the example, see the custom<title/>
and custom<meta/>
description. - The user can include custom HTML around their Dash app container (see the
<div/>
withMy Custom Header
) - The user can omit the templated tags if they want to supply their own front-end JavaScript bundles. This ties in nicely with the "Custom JavaScript Hooks" requirement: if the user adds their own hooks to a custom
dash-renderer
build, they could remove the defaultdash_renderer
template variable and include their own version. - If the tags depend on the URL of the page, they could program in different values that depend on the
flask.request.url
variable.