diff --git a/config/toc-docs.yaml b/config/toc-docs.yaml
index 2430f488..842efdbc 100644
--- a/config/toc-docs.yaml
+++ b/config/toc-docs.yaml
@@ -66,6 +66,18 @@ Plugins:
ajax/javascript-api: "JavaScript API"
ajax/extras: "Extra Features"
+Snowboard:
+ icon: "icon-bolt"
+ pages:
+ snowboard/introduction: "Introduction"
+ snowboard/migration-guide: "Migration Guide"
+ snowboard/handlers: "Serverside Event Handlers"
+ snowboard/request: "AJAX Requests (JavaScript API)"
+ snowboard/data-attributes: "AJAX Requests (Data Attributes API)"
+ snowboard/extras: "Extra Features"
+ snowboard/utilities: "Utilities"
+ snowboard/plugin-development: "Plugin Development"
+
Database:
icon: "icon-hdd"
pages:
@@ -113,6 +125,7 @@ Console:
console/setup-maintenance: "Setup & Maintenance"
console/plugin-management: "Plugin Management"
console/theme-management: "Theme Management"
+ console/asset-compilation: "Asset Compilation (Mix)"
console/scaffolding: "Scaffolding"
console/utilities: "Utilities"
diff --git a/console-asset-compilation.md b/console-asset-compilation.md
new file mode 100644
index 00000000..471b5345
--- /dev/null
+++ b/console-asset-compilation.md
@@ -0,0 +1,203 @@
+# Asset Compilation (Mix)
+
+- [Introduction](#introduction)
+- [Requirements](#requirements)
+- [Registering a package](#registering-packages)
+ - [Automatic registration](#automatic-registration)
+ - [Registering plugin packages](#registering-plugins)
+ - [Registering theme packages](#registering-themes)
+- [Mix configuration](#mix-configuration)
+- [Examples](#examples)
+- [Commands](#commands)
+ - [Install Node dependencies](#mix-install)
+ - [List registered Mix packages](#mix-list)
+ - [Compile a Mix package](#mix-compile)
+ - [Watch a Mix package](#mix-watch)
+
+
+## Introduction
+
+Winter brings first-class support for handling Node-based compilation for frontend assets through the Mix commands. The comamnds use the [Laravel Mix](https://laravel-mix.com/) wrapper, a user-friendly and simple interface for setting up compilation of multiple types of frontend assets through Webpack and various libraries.
+
+
+### Requirements
+
+To take advantage of Mix asset compilation, you must have Node and the Node package manager (NPM) installed in your development environment. This will be dependent on your operating system - please review the [Download NodeJS](https://nodejs.org/en/download/) page for more information on installing Node.
+
+[Laravel Mix](https://laravel-mix.com/) should also be present in the `package.json` file for any packages that will be using it (either in `dependencies` or a `devDependencies`) but if it is not specified in the project's `package.json` file then it can be optionally automatically added when running the [`mix:install`](#mix-install) command.
+
+
+## Registering a package
+
+Registering for asset compilation through Mix is very easy. Automatic registration should meet your needs most of the time, and if not there are several methods available to manually register Mix packages.
+
+
+### Automatic registration
+
+By default, Winter will scan all available and enabled modules, plugins and themes for the presence of a `winter.mix.js` file under each extension's root folder (i.e. `modules/system/winter.mix.js`, `plugins/myauthor/myplugin/winter.mix.js`, or `themes/mytheme/winter.mix.js`).
+
+If the `winter.mix.js` file is found, it will be automatically registered as a package with an automatically generated package name, and will show up when running the Mix commands. Most of the time, this should be all you need to do in order to get started with Laravel Mix asset compilation in Winter CMS.
+
+
+### Registering plugins
+
+To register frontend assets to be compiled through Mix in your plugin, simply return an array with the package names as the keys and the package paths relative to the plugin's directory as the values to register from your [`Plugin.php`](../plugin/registration) registration file's `registerMixPackages()` method. See below example.
+
+```php
+public function registerMixPackages()
+{
+ return [
+ 'custom-package-name' => 'assets/js/build.mix.js',
+ ];
+}
+```
+
+
+### Registering themes
+
+Registration of asset compilation of themes is even easier, and can be done by adding a `mix` definition to your [theme information file](../themes/development#theme-information) (`theme.yaml`).
+
+```yaml
+name: "Winter CMS Demo"
+description: "Demonstrates the basic concepts of the frontend theming."
+author: "Winter CMS"
+homepage: "https://wintercms.com"
+code: "demo"
+
+mix:
+ : winter.mix.js
+```
+
+The `mix` definition takes any number of registered packages as a YAML object, with the key being the name of the package as a kebab-case string and the location of your `winter.mix.js` file relative to the theme's root directory.
+
+For example, if you want to register two packages called `demo-theme-style` and `demo-theme-shop` located in the assets folder, you would use the following definition:
+
+```yaml
+name: "Winter CMS Demo"
+description: "Demonstrates the basic concepts of the frontend theming."
+author: "Winter CMS"
+homepage: "https://wintercms.com"
+code: "demo"
+
+mix:
+ demo-theme-style: assets/style/winter.mix.js
+ demo-theme-shop: assets/shop/winter.mix.js
+```
+
+
+## Mix configuration
+
+The Mix configuration file (`winter.mix.js`) is a configuration file that manages the configuration of Laravel Mix itself. In conjunction with the `package.json` file that defines your dependencies, this file defines how Laravel Mix will compile your assets.
+
+You can [review examples](https://laravel-mix.com/docs/6.0/examples) or the [full Mix API](https://laravel-mix.com/docs/6.0/api) at the [Laravel Mix website](https://laravel-mix.com).
+
+Your `winter.mix.js` file must include Mix as a requirement, and must also define the public path to the current directory, as follows:
+
+```js
+const mix = require('laravel-mix');
+
+// For assets in the current directory
+// mix.setPublicPath(__dirname);
+
+// For assets in a /assets subdirectory
+mix.setPublicPath(__dirname + '/assets');
+
+// Your mix configuration below
+```
+
+### Paths
+
+When the `winter.mix.js` file is evaluated, regardless of where you ran `mix:compile` from, the working directory is set to the parent directory of the `winter.mix.js` file. That means that any relative paths used in the configuration will be relative to the current directory of the `winter.mix.js` file.
+
+>**NOTE:** Winter's [path symbols](../services/helpers#path-symbols) are also supported in the `winter.mix.js` file.
+
+
+## Examples
+
+Here are some examples of installing common frontend libraries for use with the asset compilation.
+
+### Tailwind CSS
+
+For themes that wish to use Tailwind CSS, include the `tailwindcss`, `postcss` and `autoprefixer` dependencies in your `package.json` file.
+
+```bash
+# Inside the project root folder
+npm install --save-dev tailwindcss postcss autoprefixer
+
+# Run the Tailwind initialisation
+npx taildwindcss init
+```
+
+This will create a Tailwind configuration file (`tailwind.config.js`) inside your theme that you may [configure](https://tailwindcss.com/docs/installation) to your specific theme's needs.
+
+Then, add a `winter.mix.js` configuration file that will compile Tailwind as needed:
+
+```js
+const mix = require('laravel-mix');
+mix.setPublicPath(__dirname);
+
+// Render Tailwind style
+mix.postCss('assets/css/base.css', 'assets/css/theme.css', [
+ require('postcss-import'),
+ require('tailwindcss'),
+]);
+```
+
+In the example above, we have a base CSS file that contains the Tailwind styling - `assets/css/base.css` - that will compile to a final compiled CSS file in `assets/css/theme.css`.
+
+Your theme will now be ready for Tailwind CSS development.
+
+
+## Commands
+
+### Install Node dependencies
+
+```bash
+php artisan mix:install [-p ] [--npm ]
+```
+
+The `mix:install` command will install Node dependencies for all registered Mix packages.
+
+This command will add each registered package to the `workspaces.packages` property of your root `package.json` file and then run and display the results of `npm install` from your project root to install all of the dependencies for all of the registered packages at once.
+
+You can optionally provide a `-p` or `--package` flag to install dependencies for one or more packages. To define multiple packages, simply add more `-p` flags to the end of the command.
+
+If the command is run with a `-p` or `--package` flag and the provided package name is not already registered and the name matches a valid module, plugin, or theme package name (modules are prefixed with `module-$moduleDirectory`, themes are prefixed with `theme-$themeDirectory`, and plugins are simply `Author.Plugin`) then a `winter.mix.js` file will be automatically generated for that package and will be included in future runs of any mix commands through the [automatic registration](#automatic-registration) feature.
+
+The `--npm` flag can also be provided if you have a custom path to the `npm` program. If this is not provided, the system will try to guess where `npm` is located.
+
+### List registered Mix packages
+
+```bash
+php artisan mix:list
+```
+
+The `mix:list` command will list all registered Mix packages found in the Winter installation. This is useful for determining if your plugin or theme is correctly registered.
+
+The command will list all packages, as well as the directory for the asset and the configuration file that has been defined during registration.
+
+### Compile a Mix packages
+
+```bash
+php artisan mix:compile [-p ] [-f|--production] [-- ]
+```
+
+The `mix:compile` command compiles all registered Mix packages, running each package through Laravel Mix for compilation.
+
+By specifying the `-p` flag, you can compile one or more selected packages. To define multiple packages, simply add more `-p` flags to the end of the command.
+
+By default, all packages are built in "development" mode. If you wish to compile in "production" mode, which may include more optimisations for production sites, add the `-f` or `--production` flag to the command.
+
+The command will generate a report of all compiled files and their final size once complete.
+
+If you wish to pass extra options to the Webpack CLI, for special cases of compilation, you can add `--` to the end of the command, followed by [any parameters](https://webpack.js.org/api/cli/) as per the Webpack CLI options.
+
+### Watch a Mix package
+
+```bash
+php artisan mix:watch [-f|--production] [-- ]
+```
+
+The `mix:watch` command is similar to the the `mix:compile` command, except that it remains active and watches for any changes made to files that would be affected by your compilation. When any changes are made, a compile is automatically executed. This is useful for development in allowing you to quickly make changes and review them in your browser.
+
+With this command, only one package can be provided and watched at any one time.
\ No newline at end of file
diff --git a/console-introduction.md b/console-introduction.md
index 5a670e8d..73a6cdca 100644
--- a/console-introduction.md
+++ b/console-introduction.md
@@ -63,6 +63,11 @@ Command | Description
[`theme:use`](../console/theme-management#theme-use) | Switches Winter to the given theme.
[`theme:remove`](../console/theme-management#theme-install) | Removes a theme.
[`theme:sync`](../console/theme-management#theme-sync) | Synchronises a theme between the filesystem and the database, if you use the [Database Templates](../cms/themes#database-driven-themes) feature.
+**Asset compilation (Mix)** |
+[`mix:install`](../console/asset-compilation#mix-install) | Install Node dependencies for registered Mix packages.
+[`mix:list`](../console/asset-compilation#mix-list) | Lists all registered Mix packages.
+[`mix:compile`](../console/asset-compilation#mix-compile) | Compiles one or more Mix packages.
+[`mix:watch`](../console/asset-compilation#mix-watch) | Watches changes within a Mix package and automatically compiles the package on any change.
**Scaffolding** |
[`create:theme`](../console/scaffolding#create-theme) | Create a theme.
[`create:plugin`](../console/scaffolding#create-plugin) | Create a plugin.
diff --git a/snowboard-data-attributes.md b/snowboard-data-attributes.md
new file mode 100644
index 00000000..af623de3
--- /dev/null
+++ b/snowboard-data-attributes.md
@@ -0,0 +1,100 @@
+# AJAX Requests (Data Attributes API)
+
+- [Introduction](#introduction)
+- [Available Data Attributes](#available-attributes)
+- [Usage Examples](#usage-examples)
+
+
+## Introduction
+
+The Data Attributes API is the simpler way of embedding AJAX functionality in your themes and plugins, and removes the need to be experienced with JavaScript. While the [JavaScript API](../snowboard/request) has had numerous changes from the original [AJAX framework](../ajax/introduction), the Data Attributes API has remain largely unchanged, despite being powered by the new Snowboard framework under the hood.
+
+It can be loaded by adding the following tag into your CMS Theme's page or layout:
+
+```twig
+{% snowboard request attr %}
+```
+
+> **NOTE:** As per the [Migration Guide](../snowboard/migration-guide), arbitrary JavaScript is no longer allowed through the Data Attributes API. Thus, the `data-request-before-update`, `data-request-success`, `data-request-error` and `data-request-complete` attributes are no longer supported. Please use the [JavaScript API](../snowboard/request) if you require this functionality.
+
+
+## Available Data Attributes
+
+Triggering an AJAX request from a valid element is as simple as adding the `data-request` attribute to that element. This generally should be done on a button, link, or form. You can also customize the AJAX request using the following attributes:
+
+
+
+
+Attribute | Description
+--------- | -----------
+`data-request` | Specifies the AJAX handler name to target for the request.
+`data-request-confirm` | Specifies the confirmation message to present to the user before proceeding with the request. If the user cancels, the request is not sent.
+`data-request-redirect` | Specifies a URL to redirect the browser to, if a successful AJAX response is received.
+`data-request-url` | Specifies the URL to send the AJAX request to. By default, this will be the current URL.
+`data-request-update` | Specifies a list of partials and page elements (CSS selectors) to update on a successful AJAX response. The format is as follows: `partial: selector, partial: selector`. Usage of quotes is required in most cases: `'partial': 'selector'`. If the selector is prepended with an `@` symbol, the content received from the server will be appended to the element. If the selector is prepended with a `^` symbol, the content will be prepended. Otherwise, received content will replace the original content in the element.
+`data-request-data` | Specifies additional data to send with the request to the server. The format is as follows: `'var': 'value', 'var2': 'new value'`. You may also specify this same attribute on any parent elements of the triggering element, and this data will be merged with the parent data (with the triggering data taking preference). It will also be merged with any form data, if this request triggers within a form.
+`data-request-form` | Specifies the form that the AJAX request will include its data from. If this is unspecified, the closest form will be used, or if the element itself is a form, then this will be used.
+`data-request-flash` | Specifies if flash messages will be accepted from the response.
+`data-request-files` | Specifies if file data will be included in the request. This will allow any file inputs in the form to work.
+`data-browser-validate` | Specifies if the in-built browser validation will be triggered. If present, the request will be cancelled if the browser validation fails.
+`data-track-input` | Specifies if an input will trigger an AJAX request anytime the input changes. An optional number can be specified in this attribute, which represents the amount of milliseconds between any change and the AJAX request triggering.
+
+
+When the `data-request` attribute is specified for an element, the element triggers an AJAX request when a user interacts with it. Depending on the type of element, the request is triggered on the following events:
+
+Element | Event
+------------- | -------------
+**Forms** | when the form is submitted.
+**Links, buttons** | when the element is clicked.
+**Text, number, and password fields** | when the text is changed and only if the `data-track-input` attribute is presented.
+**Dropdowns, checkboxes, radios** | when the element is selected.
+
+
+## Usage examples
+
+Trigger the `onCalculate` handler when the form is submitted. Update the element with the identifier "result" with the **calcresult** partial:
+
+```html
+
+```
diff --git a/snowboard-extras.md b/snowboard-extras.md
new file mode 100644
index 00000000..e120bf21
--- /dev/null
+++ b/snowboard-extras.md
@@ -0,0 +1,203 @@
+# Extra UI Features
+
+- [Introduction](#introduction)
+- [Loading indicator](#loader-stripe)
+- [Loading button](#loader-button)
+- [Flash messages](#ajax-flash)
+- [Form validation](#ajax-validation)
+ - [Throwing a validation error](#throw-validation-exception)
+ - [Displaying error messages](#error-messages)
+ - [Displaying errors with fields](#field-errors)
+ - [Usage examples](#usage-examples)
+
+
+## Introduction
+
+When using the Snowboard framework, you have the option to specify the `extras` flag which includes additional UI features. These features are often useful when working with AJAX requests in frontend CMS pages.
+
+```twig
+{% snowboard extras %}
+```
+
+
+## Loading indicator
+
+The loading indicator is a loading bar that is displayed on the top of the page when an AJAX request runs. The indicator hooks in to [global events](../snowboard/request#global-events) used by the Snowboard framework.
+
+When an AJAX request starts, the `ajaxPromise` event is fired. This displays the loading indicator at the top of the page. When this promise is resolved, the loading bar is removed.
+
+
+## Loading button
+
+When any element contains the `data-attach-loading` attribute, the CSS class `wn-loading` will be added to it during the AJAX request. This class will spawn a *loading spinner* on button and anchor elements using the `:after` CSS selector.
+
+```html
+
+
+
+ Do something
+
+```
+
+
+## Flash messages
+
+Specify the `data-request-flash` attribute on a form to enable the use of flash messages on successful AJAX requests.
+
+```html
+
+```
+
+Combined with use of the `Flash` facade in the event handler, a flash message will appear after the request finishes.
+
+```php
+function onSuccess()
+{
+ Flash::success('You did it!');
+}
+```
+
+When using AJAX Flash messages you should also ensure that your theme supports [standard flash messages](../markup/tag-flash) by placing the following code in your page or layout in order to render Flash messages that haven't been displayed yet when the page loads.
+
+```twig
+{% flash %}
+
+ {{ message }}
+
+{% endflash %}
+```
+
+
+## Form validation
+
+You may specify the `data-request-validate` attribute on a form to enable server-side validation features with fields and forms.
+
+```html
+
+```
+
+
+### Throwing a validation error
+
+In the server side AJAX handler, you may throw a [validation exception](../services/error-log#validation-exception) using the `ValidationException` class to make a field invalid. The exception should be provided an array, which states the field names for the keys, and the error messages for the values.
+
+```php
+function onSubmit()
+{
+ throw new ValidationException(['name' => 'You must give a name!']);
+}
+```
+
+> **NOTE**: You can also pass a [Validator](../services/validation) instance as the first argument of the exception instead, to use the in-built validation service.
+
+
+### Displaying error messages
+
+Inside the form, you may display the first error message by using the `data-validate-error` attribute on a container element. The content inside the container will be set to the error message and the element will be made visible.
+
+```html
+
+```
+
+To display multiple error messages, include an element with the `data-message` attribute. In this example the paragraph tag will be duplicated and set with content for each message that exists.
+
+```html
+
+
+
+```
+
+The `handleValidationErrors` callback, and the `ajaxValidationErrors` global event, that are available with the [Request API](../snowboard/request#global-events) allow you to fully customise the client-side validation handling. The `handleValidationErrors` callback can be used to control validation per request, while the `ajaxValidationErrors` global event can be used by [Snowboard plugins](../snowboard/plugin-development) to augment the client-side validation in a global fashion.
+
+
+### Displaying errors with fields
+
+Alternatively, you can show validation messages for individual fields by defining an element that uses the `data-validate-for` attribute, passing the field name as the value.
+
+```html
+
+
+
+
+
+```
+
+If the element is left empty, it will be populated with the validation text from the server. Otherwise you can specify any text you like and it will be displayed instead.
+
+```html
+
+ Oops.. phone number is invalid!
+
+```
+
+
+### Usage examples
+
+Below is a complete example of form validation. It calls the `onDoSomething` event handler that triggers a loading submit button, performs validation on the form fields, then displays a successful flash message.
+
+```html
+
+```
+
+The AJAX event handler looks at the POST data sent by the client and applies some rules to the validator. If the validation fails, a `ValidationException` is thrown, otherwise a `Flash::success` message is returned.
+
+```php
+function onDoSomething()
+{
+ $data = post();
+
+ $rules = [
+ 'name' => 'required',
+ 'email' => 'required|email',
+ ];
+
+ $validation = Validator::make($data, $rules);
+
+ if ($validation->fails()) {
+ throw new ValidationException($validation);
+ }
+
+ Flash::success('Jobs done!');
+}
+```
diff --git a/snowboard-handlers.md b/snowboard-handlers.md
new file mode 100644
index 00000000..3c67f8ad
--- /dev/null
+++ b/snowboard-handlers.md
@@ -0,0 +1,156 @@
+# Server-side Event Handlers
+
+- [Introduction](#introduction)
+ - [Calling a handler](#calling-handlers)
+ - [Generic handler](#generic-handler)
+- [Redirects in AJAX handlers](#redirects-in-handlers)
+- [Returning data from AJAX handlers](#returning-data-from-handlers)
+- [Throwing an AJAX exception](#throw-ajax-exception)
+- [Running code before handlers](#before-handler)
+
+
+## Introduction
+
+AJAX event handlers are PHP functions that can be defined in the page or layout [PHP section](../cms/themes#php-section) or inside [components](../cms/components) and are used to execute the server-side functionality of an AJAX request made by the [Request API](../snowboard/request) or [Data Attributes API](../snowboard/data-attributes).
+
+Handler method names should be specified with the `on` prefix, followed by the event name in PascalCase - for example, `onMyHandler` or `onCreatePost`.
+
+All handlers support the use of [updating partials](#updating-partials) as part of the AJAX response. This behavior can also be controlled via the `update` option in the [Request API](../snowboard/request) or the `data-request-update` attribute in the [Data Attributes API](../snowboard/data-attributes).
+
+```php
+function onSubmitContactForm()
+{
+ // AJAX handler functionality goes here
+}
+```
+
+If two handlers with the same name are defined in a page and layout together, the page handler will be executed. The handlers defined in [components](../cms/components) have the lowest priority.
+
+
+### Calling a handler
+
+Every AJAX request should specify a handler name. When the request is made, the server will search all the registered handlers and run the handler with the highest priority.
+
+```html
+
+
+
+
+
+```
+
+If two components register the same handler name, it is advised to prefix the handler with the [component short name or alias](../cms/components#aliases). If a component uses an alias of **mycomponent** the handler can be targeted with `mycomponent::onName`.
+
+```html
+
+```
+
+You should use the [`__SELF__`](../plugin/components#referencing-self) variable instead of the hard coded alias in order to support multiple instances of your component existing on the same page.
+
+```twig
+