Customizing Swift
Dynamicweb Swift is built for versatility but it is also a standard solution – and sometimes you need something custom to make the customer happy. This section will teach you how to approach customizations to Swift and hopefully help you avoid some common pitfalls.
Please note that this section requires a good understanding of templating in Dynamicweb – e.g. designs, templates, viewmodels, and a general proficiency with front-end development.
Built on Bootstrap 5
Swift is built using Bootstrap 5 – and we’ve taken care to only use Bootstrap whenever possible, with very little custom code for areas already handled by Bootstrap.
The only area where we really differ from stock Bootstrap 5 is on how we handle fonts (Branding) and colors (Themes), where we don’t fully use the Bootstrap 5 primary and secondary color (both set to gray) and basic font settings, and where the branding and theme choices take priority. This has been done to make the solution more end-user friendly and design-oriented.
Bootstrap 5 also features a collection of neat Javascript modules – we’ve included them all in swift.js, as the footprint is very small. This saves you from deciding on a project-to-project basis what to include; everything Bootstrap 5 should just work out of the box and you don’t need to include bootstrap.js manually.
Template Structure
All frontend code for Swift is found in the Swift design folder which can be found under /Files/Templates/Designs/Swift.
As you may know, the Swift-design is built for the Visual Editor – our WYSIWYG editor for creating website content – and as such the content is modular and based on item types with specific purposes and consists of:
- A set of item types for pages with specific functions – e.g. content pages, cart pages, product catalog pages, etc.
- A set of item types for various kinds of paragraphs – for creating features, navigations, search fields, product sliders, etc.
Each item type has a template associated with it – for pages these are placed in the root of the Design-folder, for paragraphs they are placed inside a /Paragraphs subfolder. When customizing Swift, these are the templates you will be working with – which is good news, as they are all of a manageable size and quite simple to work with.
If you’re familiar with standard Dynamicweb, please note that these folders also contain templates for types of content not normally placed here, e.g. the product list and product details pages. This is because ecommerce content on Swift is rendered in a slightly unusual way – see the setup section for more information.
Some templates are placed elsewhere:
- Newsletters: Files/Templates/Designs/Swift/Swift_Newsletter
- Customer Center: Files/Templates/Designs/Swift/ UserManagement and Files/Templates/Designs/Swift/eCom/CustomerExperienceCenter
- Checkout & Cart: Files/Templates/Designs/Swift/eCom7/CartV2
Customizing Content
There are basically two paths to take when it comes to customizing Swift content:
- You can copy an existing item type and the associated template, rename them, and make them your own. This is the recommended method, as it makes it easier to upgrade down the line without having to manually merge customizations. We recommend adding a _Custom suffix to the item type and template, as this makes it easy to see which content is custom and which is standard.
- You can do your customizations directly in the system templates. This is sometimes the best approach, especially if your modifications will be very extensive across most parts of the Swift design. It comes at a cost, of course – any upgrades or bugfixes will have to be manually merged to your custom templates.
No matter which path you take you should consider closely how you approach adding new functionality to a template or an item. How will the content editor work with it? As a rule of thumb, keep the system consistent – if working with the new content type feels like working with the existing content type your editors will know what to expect.
For instance, almost all paragraph types share the same settings for styling – i.e. Theme, Spacing and Title size – so when adding a new content type you should strongly consider including them. You should also strongly consider creating presets for the content type, as they make it much easier for an editor to work with the new type.
Custom Columns
Most of Swift is built using columns – item-based paragraphs with specific purposes – such as content columns and ecommerce columns. The general idea is that a column is only available where it makes sense, which helps reduce complexity for designers and editors when creating content.
If the standard columns don’t quite cut it it’s pretty easy to create a customized column type:
- Go to Settings > Item Types > Swift and copy the item type of the column type you want to customize
- Name the copy –We recommend that you simply add a _Custom suffix to the system column name, as it makes it easy to identy customizations down the line
- Modify the item type as you please – add or remove fields, create settings, etc.
- Save
If you do this from the backend you will notice that an item type definition file – ItemType_youritemtypename.xml – is created in the System/Items folder. If you’re copying the item type definition file directly and editing the XML you’re creating this file yourself, of course.
To make sure you can use the custom column type:
- Open the item type under which you want to use it – e.g. the Page item type or the Header item type
- Set the custom item type as an allowed child under the item type restrictions.
- Save
Finally, create a template for the customized item type:
- Go to /Templates/Designs/Swift/Paragraph and find the template matching the item type you copied
- Copy this template file and rename it – If you name it after the system name of item type it will automatically be used when creating an item based on the type
- Modify the template to do the things you want to do
- Save
Please note that if you’re customizing highly specialized or technical columns – e.g. the columns used I the checkout flow – you will likely need to copy and customize a series of helper templates in addition to the base template, e.g. DeliveryUser.cshtml or Helpers/ShippingMethods.cshtml. Since the checkout flow is such an important part of a solution please don’t hesistate to use the Swift Forum if you have any questions.
Custom Rows
Swift ships with a set of grid rows which are used to define the overall layout of a page – and in most cases they should be sufficient. If not, though, it’s not hard to create a custom row. As with columns the easiest approach is to copy and modify an existing row:
- Go to Settings > Item Types > Swift > Grid and copy the item type you want to customize
- Name the copy – we recommend simply adding a _Custom prefix to the system name, as this makes it easy to identify custom content down the line
- Make your changes
- Save
Next you want to include the row in the Swift grid definitions:
- Open the definition file - Files/Templates/Designs/Swift/Grid/Page/RowDefinitions.json
- Add a new element for your custom row
- Save
To make sure the new row can be used:
- Go to Settings > Item Types > Swift > Page and open the restrictions modal
- Select your row as an allowed child
- Save
Finally, create a template for the custom row:
- Go to /Templates/Designs/Swift/Grid/Page/Rowtemplates and find the template matching the item type you copied
- Copy this template file and rename it – the name must match the template name defined in RowDefinitions.json
- Modify the template to do the things you want to do
- Save
Please note that the RowDefinitions.json file may be overwritten if you upgrade to a newer version of Swift down the line – make a note of your changes and make sure they are manually merged at a later date if relevant.
Custom CSS
Adding and using custom CSS on Swift is easy – but to make it easier to upgrade a solution down the line we recommend that you don’t add a reference directly to the master page. Instead you should create a custom .cshtml with the reference and include it:
- Go to /Files/Templates/Designs/Swift/Components/Custom
- Create a new .cshtml file – you could call it HeaderIncludes.cshtml
- Open the file and add a reference to the custom css file - there's a default custom.css file under /Swift/Assets/CSS
- Open the Swift website settings and scroll to the Master Layout section
- Select the .cshtml file you created and save
Then, when a pageview is rendered the contents of the included file is merged with the header file before the page is rendered.
CSS Variables
CSS Variables are great because they make it possible to customize styling without having to recompile the Scss project. Since Swift is built on Bootstrap 5, you have access to all the CSS variables available there – see the Bootstrap documentation for more information.
Additionally, we expose all the properties of the Branding and Themes settings as css variables
- Branding variables can be used directly on the body element, as you would normally do when working with CSS variables.
- Themes work a little differently, as they are infinitely nestable and can be used in the exact same manner on any element. It’s easy to overrule the CSS variables on themes as long as you do it directly on the elements that actually have a theme – but you most likely won’t have any reason to do this as you already have full control of the CSS variables when you create the themes.
JavaScript
Just like the developers behind Bootstrap, we prefer to use HTML and CSS over JavaScript, as this makes the code much more accessible to developers of different experience levels while simultaneously removing a source of complexity from our codebase.
But of course there are circumstances where there’s no way around JavaScript – so Swift contains a small collection of JavaScript modules (delivered as modules from Bootstrap) for your convenience. All of these are designed in the same way, so if you learn to use one you’ve learned how to use the others.
Here’s a description of each included module – most of them are very similar as their purpose is to:
- Make an asynchronous call
- Add a preloader
- Receive the request.
Cart.js
This module contains a single public method – swift.Cart.Update(event) – which is used to submit the add-to-cart form via fetch when an Add to cart button is clicked. For an improved user experience we add a preloader while waiting for the response. If the request was a success we get a response with an updated cart quantity, then all elements with the class js-cart-qty are updated with the new quantity by replacing the innerHTML.
If you want to add new properties to the Add to cart method simply add fields to the form – no js or json feed required.
Pageupdater.js
This module is a general purpose module for executing asynchronous updates to page content. We use it primarily on checkout pages where selecting e.g. a country requires updates to other parts of the page such as the payment providers available. Instead of updating the whole page we add a preloader and replace the content when the request is done.
Like the other async updaters in Swift, the page updater replaces the inner markup + data with new markup and data from the request – no json feed or javascript required. This keeps the code and setup very accessible, and in most cases the developer need only know HTML, CSS & a little Dynamicweb to build great solutions with async elements.
Productlist.js
This module is a product list-specific module for executing asynchronous updates to a product list page. It follows the design of Pageupdater.js, but also features product list specific functionality like clearing facet selections. It works as all the other async updaters in Swift – by replacing the inner markup + data with new markup + data from the request.
To use productlist.js to update content, wrap the area that does the update in a form element and choose where the update should be rendered – you have these settings available as data-attributes:
- data-response-target-element – ID for the element where the result should be rendered
- data-preloader – inline or overlay
- data-update-url – boolean for if the url should be updated
To trigger an update add this call to an element inside the form: swift.ProductList.Update(event). To add something new to the request add it through fields in the form. Please note that any parameter which should be remembered after the update should be added to each request, e.g. you should always add a hidden field containing the page size.
For examples on how to use this module see Files\Templates\Designs\Swift\Paragraph\Swift_ProductListGridView.cshtml.
Scroll.js
This script is used to handle things which we want to happen on scroll. We use it to change themes and/or hide specific rows in the header, if requested.
Sliders.js
This module is used to ensure that slider with multiple columns per slide look great no matter the context they are placed in, e.g. by making sure a slider placed inside a 1/3 column shows fewer columns on each slide than it does when placed inside a full width column. Sliders.js extends TinySlider.
Typeahead.js
This module is used to deliver typeahead suggestions when a user types something in a search field. The main inspiration behind this implementation is the Google search field.
Typeahead.js depends on a very specific markup setup, which can be seen in Files/Templates/Designs/Swift/Paragraphs/Swift_SearchField.cshtml. If you need to extend or customize the typeahead search field we recommend that you copy this template and use it as a starting point for your customizations. Pay special attention to elements with classes starting with js- as these are required by typeahead.js.
The module works by sending a request to a special page (Content > Swift tools > Services > Search results) which contains the data for the dropdown, and then replaces the content of the element with the js-async-fetch-placeholder class with the fetched content. The content for the search result service is rendered by the Files/Templates/Designs/Swift/eCom/ProductCatalog/ ProductSearchDropdownResponse.cshtml template.
Variantselector.js
This module is used to render variant selectors – an area which is often implemented in quite a complex manner and can be a source of many headaches. Our implementation is pretty lightweight. It contains only one public method – swift.Variantselector.OptionClick(event) – which is called when an option is clicked.
To create a custom design using e.g. dropdowns you can use the same js- classes used on e.g. the SwiftProductDetailsInfo.cshtml template.
Here’s an overview of the “internal” methods – this will help you understand what’s going on when using this module:
- ToggleActiveState
This method is used to set states on variant options – active, inactive or no state. When an option is clicked we clear all active states on options in the same group. If the option clicked was inactive we clear ALL active states, effectively resetting the selector. Finally, we add the active state to the option clicked. - UpdateAllVariants
This state is used to calculate which variant options are possible, then sets the inactive state on all options and calls the IsOptionAvailable for each option in each group. If the option is available we remove the inactive state. - IsOptionAvailable
This method is used to calculate if a specific variant option is available, primarily by looking at the currently selected options. - CheckSelectionComplete
This method is used to determine whether a selection has been made for each variant group – if it has it updates the page and makes the Add to cart button available.