docs/contributing/ui_guidelines.md
Wagtail’s user interface is built with:
Wagtail is meant to be used on a wide variety of devices and browsers. Supported browser / device versions include:
| Browser | Device/OS | Version(s) |
|---|---|---|
| Mobile Safari | iOS Phone | Last 2: 17, 18 |
| Mobile Safari | iOS Tablet | Last 2: 17, 18 |
| Chrome | Android | Last 2 |
| Chrome | Desktop | Last 2 |
| MS Edge | Windows | Last 2 |
| Firefox | Desktop | Latest |
| Firefox ESR | Desktop | Latest: 140 |
| Safari | macOS | Last 3: 16, 17, 18 |
We aim for Wagtail to work in those environments. Our development standards ensure that the site is usable on other browsers and will work on future browsers.
Unsupported browsers / devices include:
| Browser | Device/OS | Version(s) |
|---|---|---|
| Stock browser | Android | All |
| IE | Desktop | All |
| Safari | Windows | All |
(accessibility_targets)=
We want to make Wagtail accessible for users of a wide variety of assistive technologies. The specific standard we aim for is WCAG2.1, AA level. Here are specific assistive technologies we aim to test for, and ultimately support:
We aim for Wagtail to work in those environments. Our development standards ensure that the site is usable with other assistive technologies. In practice, testing with assistive technology can be a daunting task that requires specialized training – here are tools we rely on to help identify accessibility issues, to use during development and code reviews:
Wagtail’s administration interface isn’t fully accessible at the moment. We actively work on fixing issues both as part of ongoing maintenance and bigger overhauls. To learn about known issues, check out:
The audit also states which parts of Wagtail have and haven’t been tested, how issues affect WCAG 2.1 compliance, and the likely impact on users.
We use djhtml for formatting and Curlylint for linting. See .
data- attributes for JavaScript behavior.id first, then class, then any data- or other attributes with Stimulus data-controller first.We use Prettier for formatting and Stylelint for linting. See .
rems for font-size, because they offer absolute control over text. Additionally, unit-less line-height is preferred because it does not inherit a percentage value of its parent element, but instead is based on a multiplier of the font-size.w- prefix for all styles intended to be reusable by Wagtail site implementers.Most of our styles are combined into a single main stylesheet, core.css. This is the recommended approach for all new styles, to reduce potential style clashes, and encourage reuse of utilities and component styles between views. Imports within core.scss are structured according to ITCSS. There are two major exceptions to the ITCSS structure:
vendor/ is imported in the order it was loaded in before adding in the main stylesheet, to avoid compatibility issues. If possible, those styles should be converted to components and loaded further down the cascade.layouts/ are imported at the very end of the file, matching how styles were previously loaded across multiple stylesheets. If possible, those styles should be converted to components or utilities and loaded further up the cascade.When creating new styles, always prefer components, adding a new stylesheet in the components folder and importing it in core.scss.
For all of our styles, we use:
normalize.css as a CSS reset.box-sizing: border-box, with elements always inheriting the box-sizing of their parent.--w-direction-factor CSS variable, set to 1 by default and -1 for RTL languages, to allow reversing of calculations of physical values (transforms, background positions) and mirroring of icons and visuals with directional elements like arrows.--w-density-factor CSS variable, to let users control the information density of the UI. Set to 1 by default, and lower or higher values to reduce or increase the spacing and size of UI elements.We use Tailwind to manage our design tokens via its theme, and generate CSS utilities. It is configured in tailwind.config.js, with a base configuration intended to be reusable in other projects.
Wagtail uses most of Tailwind’s core plugins, with an override for them to create Logical properties and values styles while still using Tailwind’s default utility and design token names.
With utility classes, we recommend to:
typography.js.We keep our Sass usage to a minimum, preferring verbose vanilla CSS over advanced Sass syntax. Here are specific Sass features to completely avoid:
@extend. Leads to unexpected cascading of styles.And Sass features to use with caution:
&) interpolation. Only use interpolation in class names sparingly, so we can more easily search for styles across the project.calc functions for math operations rather than Sass.Also known as Windows High Contrast mode, or Contrast Themes. This is a feature of Windows for users to override websites’ styles with their own, so text is more readable. We intend to fully support it in all of our styles. Here are recommended practices:
@media (forced-colors: active) should only be used when there is no simpler alternative. Write CSS for WHCM support from the get-go rather than with sweeping overrides.forced-color-adjust: none. It compromises compatibility with a wide range of custom themes, and should only be needed if a component relies on a specific color hue to work (which is an anti-pattern).We use Prettier for formatting and ESLint for linting. See .
(ui_guidelines_stimulus)=
Wagtail uses Stimulus as a lightweight framework to attach interactive behavior to DOM elements via data- attributes.
Stimulus is a lightweight framework that allows developers to create interactive UI elements in a simple way. It makes it easy to do small-scale reactivity via changes to data attributes and does not require developers to 'init' things everywhere, unlike JQuery. It also provides an alternative to using inline script tag usage and window globals which reduces complexity in the codebase.
Stimulus is our preferred library for simple client-side interactivity. It’s a good fit when:
Wagtail’s admin interface also leverages jQuery for similar scenarios. This is considered legacy and will eventually be removed. For new features, carefully consider whether existing jQuery code should be reused, or whether a rebuild with Stimulus is more appropriate.
First think of how to name the controller. Keep it concise, one or two words ideally. Then,
client/src/controllers folder, along with its tests (see ) and Storybook stories.connect, initialize).disconnect lifecycle method.microtick) so will require a await Promise or similar to check for the changes in JSDom.this.identifier if adjusting attributes. This way the controller can be used easily with a changed identifier or extended by other classes in the future.This is an area of active improvement for Wagtail, with ongoing discussions.
trimmed attribute on blocktranslate tags to prevent unnecessary whitespace from being added to the translation strings.We support right-to-left languages, and in particular viewing the Wagtail admin interface in a horizontally mirrored layout. Here are guidelines to guarantee support:
--w-direction-factor variable equal to 1 or -1 so the value reverses based on the dir attribute of the element or page.[dir='rtl'] style if there is no other way to write styles.Make sure to also reverse the direction of any position calculation in JavaScript, as there is no support of logical values in DOM APIs (x-axis offsets always from the left).
We use inline SVG elements for Wagtail’s icons, for performance and so icons can be styled with CSS. View for information on how icons are set up for Wagtail users.
Icons are SVG files in the Wagtail admin template folder.
When adding or updating an icon,
viewBox attribute, and remove width and height attributes.id attribute with a prefix of icon- and the icon name matching the file name. Keep the icon as named from its source if possible.<!--! Icon license -->. For Font Awesome, we want: <!--! [icon name] ([icon style]): Font Awesome [version] -->. For example, <!--! triangle-exclamation (solid): Font Awesome Pro 6.4.0 -->.register_icons hook, in alphabetical order.wagtail_icons_table.txt.class="icon--directional" attribute.Images in Wagtail's admin interface are displayed using a consistent set of patterns and components. We use the {% image %} template tag for rendering images with automatic resizing.
max- resize rules for consistent image sizes. In the CMS, we only use max-165x165 and max-800x600 to improve performance. Further resizing can be done with CSS.loading="lazy" attribute where appropriate, in particular when a view would display more than one image.alt attribute, so the image tag defaults to using the image description or title.show-transparency CSS class so users can visualize any transparent area of the visuals.(styleguide)=
Developers working on the Wagtail UI or creating new UI components may wish to test their work against our Styleguide, which is provided as the contrib module "wagtailstyleguide".
To install the styleguide module on your site, add it to the list of INSTALLED_APPS in your settings:
INSTALLED_APPS = (
# ...
'wagtail.contrib.styleguide',
# ...
)
This will add a 'Styleguide' item to the Settings menu in the admin.
At present the styleguide is static: new UI components must be added to it manually, and there are no specific hooks into it for other modules to use. It will include the output of the hook for any custom edit forms JavaScript that may be used.
We hope to support specific styleguide hooks in the future.
The styleguide doesn't currently provide examples of all the core interface components; notably the Page, Document, Image and Snippet chooser interfaces are not currently represented.
(pattern_library)=
Wagtail’s UI component library is built with Storybook and django-pattern-library. To run it locally,
export DJANGO_SETTINGS_MODULE=wagtail.test.settings_ui
# Assumes the current environment contains a valid installation of Wagtail for local development.
./wagtail/test/manage.py migrate
./wagtail/test/manage.py createcachetable
./wagtail/test/manage.py runserver 0:8000
# In a separate terminal:
npm run storybook
The last command will start Storybook at http://localhost:6006/. It will proxy specific requests to Django at http://localhost:8000 by default. Use the TEST_ORIGIN environment variable to use a different port for Django: TEST_ORIGIN=http://localhost:9000 npm run storybook.