Skip to the content
Documentation
Help Start
Reading in:
  • German: 9,059 of 9,059 pages
About the help in other languages
All help pages

CSS and JavaScript in an extension

Load stylesheets and scripts the way the kernel expects: design.ini lists, ezscript_require and ezcss_require, the packer and its cache, CSP-safe scripts, no version queries.

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/help/extension-development/part-3-extension-developer/css-and-javascript-in-an-extension.md

On this page

CSS and JavaScript in an extension

Part 3, chapter 23. An extension's look and behavior in the browser come from files in its design: stylesheets/ and javascript/. They are loaded through settings and bundled by the ezjscore packer, never written into templates. This chapter shows the ways to load them and the rules a Content Security Policy imposes.

Files

extension/mysite_hello/design/standard/stylesheets/mysite_hello.css
extension/mysite_hello/design/standard/javascript/mysite_hello.js
extension/mysite_hello/design/admin/stylesheets/mysite_hello_admin.css

Load on every page: design.ini lists

extension/mysite_hello/settings/design.ini.append.php (the expqueue extension does exactly this for its admin files):

<?php /* #?ini charset="utf-8"?

[ExtensionSettings]
DesignExtensions[]=mysite_hello

[StylesheetSettings]
FrontendCSSFileList[]=mysite_hello.css
BackendCSSFileList[]=mysite_hello_admin.css

[JavaScriptSettings]
FrontendJavaScriptList[]=mysite_hello.js

*/ ?>
ListLoaded by
FrontendCSSFileList[], FrontendJavaScriptList[]site designs (their pagelayout calls ezcss_load and ezscript_load with these lists)
BackendCSSFileList[], BackendJavaScriptList[]the administration designs
CSSFileList[], JavaScriptList[]deprecated: both; use the two lists above
AdminComponentCSSFileList[]the administration's own shared components; extensions add to BackendCSSFileList[] instead, as design.ini says

The file names are paths below stylesheets/ or javascript/ of a design base; the packer finds them through the design chain.

Load on one page: require

When only one template needs a file, ask for it there:

{ezscript_require( 'mysite_hello.js' )}
{ezcss_require( 'mysite_hello.css' )}

The page head prints the required files with the rest (the pagelayout's ezscript_load and ezcss_load collect them). The cjw_newsletter and cjw_themes_jumper extensions use this for scripts that only some pages need.

The packer

ezjscore combines and compresses the listed files into one stylesheet and one script per page type, stores them under the cache, and gives them a name with the modification time ([Packer] AppendLastModifiedTime=enabled in ezjscore.ini), so browsers fetch a new copy after a change. Consequences:

  • Never add ?v=... to an asset link. The time in the name already does it.
  • After changing a stylesheet or script, clear the packer cache and the template block cache (the admin pagelayout keeps the link in a cache block): php bin/php/ezcache.php --clear-id=ezjscore-packer,template-block, or ./console exp:velocity deploy --packer.
  • While developing, [TemplateSettings] DevelopmentMode=enabled (or [eZJSCore] Packer=disabled in ezjscore.ini) serves the files one by one, which is easier to debug.

Scripts that work under a Content Security Policy

The administration sends a Content Security Policy that allows scripts only from files of the site (and a per-request nonce). So:

Not allowedInstead
<script>...</script> in a templatea file in javascript/, loaded as above
onclick="...", onsubmit="...", any on...=a data-* attribute, and a listener in your file
href="javascript:..."a button with a data-* attribute
eval(), new Function(), string timersnormal functions
style="...", <style>a class, styled in your stylesheet

The expqueue extension's expqueue_confirm.js is a complete example: the template's form carries data-a4-confirm="<question>", and the script, loaded through BackendJavaScriptList[], listens for submit:

(function ( window, document ) {
    'use strict';
    document.addEventListener( 'submit', function ( e ) {
        var form = e.target;
        if ( !form || !form.hasAttribute || !form.hasAttribute( 'data-a4-confirm' ) )
            return;
        if ( !window.confirm( form.getAttribute( 'data-a4-confirm' ) ) )
            e.preventDefault();
    } );
})( window, document );

(Shortened from the real file, which also defers to admin4's own handler.) Values go from template to script through data attributes, escaped: data-name="{$name|wash}".

jQuery and expui

The administration runs jQuery 4 and the Exp namespace of the expui extension; YUI was removed. admin4 and admin4l load neither on every page: a script in BackendJavaScriptList[] runs without them, and a template whose script needs jQuery or an exp:: module requests it, outside every cache-block ({ezscript_require( array( 'exp::core::shared', 'exp::io', 'myextension.js' ) )}); a jQuery plugin the older admin designs need on every page goes into ClassicBackendJavaScriptList[]. Use those rather than bringing your own copy of a library; see admin4 and admin4l without jQuery, The expui JavaScript API and From old jQuery to jQuery 4.

Styling admin pages

In the administration, reuse the shared component classes (.a4-card, .a4-btn, .a4-table ...) and the design tokens before writing CSS of your own; see Admin pages in the admin4 style.

Become an Exponential Partner

Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.

Something wrong on this page? Report an error

Documentation license

This documentation is free documentation, licensed under the GNU Free Documentation License 1.3 or later.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x