Developing widgets in MVC

MVC widgets in Kentico represent reusable components that can easily be manipulated by content editors and other non-technical users. Widgets and the Kentico page builder feature give said non-technical users more power and flexibility when adjusting page content, in addition to basic editing of text and images. By working with widgets, users can decide which components are placed on pages and where.

To examine sample widgets, explore the implementation of the pre-defined widgets on the Dancing Goat MVC sample site.

This page describes how to create widgets as an MVC site developer. You can find information about:

Implementing widgets

In its simplest form, a widget is just a controller that returns HTML. According to the MVC best practices, the controller works together with one or more models and partial views.

Configurable widgets

You can also develop widgets with properties, which allow content editors to adjust the widget content or behavior directly in the Kentico administration interface. For information about this more advanced scenario, see Defining widget properties in MVC.

Example of widget development

To see a scenario with full code samples which will guide you through the process of developing a simple widget, visit Example - Developing a widget in MVC.

Models

Implement the view models used to pass data from the widget controller to the partial views according to the general MVC best practices.

For widgets with configurable properties, you also need to create an additional model class that represents the widget properties and passes their values to the controller. See Defining widget properties in MVC to learn more.

It is recommended to store widget models in the ~/Models/Widgets/<widget name> folder.

Controllers

Implement the widget controller:

  • Inherit from the WidgetController class (available in the Kentico.PageBuilder.Web.Mvc namespace).

  • Implement the default Index action which is used to retrieve the widget markup. The action must return the widget's HTML content, typically a partial view. The implementation of the action depends on the purpose of the widget.

    Do not disable POST requests for the Index action

    POST requests cannot be disabled for the Index action (e.g., by using the HttpGet attribute). POST requests to the Index action are used in the page builder feature.

    Accessing the widget's page

    If you need to access or modify the page containing the currently processed widget, call the GetPage method (provided by the WidgetController base class). The method returns a TreeNode object representing the given page.

    // Gets the page where the currently processed widget is placed
    CMS.DocumentEngine.TreeNode page = GetPage();

It is recommended to store widget controllers in the ~/Controllers/Widgets folder.

Partial views

Prepare partial views that define the output of the widget according to the general MVC best practices.

It is recommended to store widget views in the ~/Views/Shared/Widgets folder.

Registering widgets

Register widgets by adding an assembly attribute to the controller. Specify the following required attribute parameters:

  • Identifier – the unique identifier of the widget. We recommend using a unique prefix in your widget identifiers to prevent conflicts when deploying widgets to other projects, for example matching your company's name.
  • Controller type – the type of the widget controller class.
  • Display name – the name used to identify the widget when displayed in the Kentico administration interface.
[assembly: RegisterWidget("CompanyName.Widgets.NumberWidget", typeof(NumberWidgetController), "Selected number")]

Additionally, you can specify the following optional attribute parameters:

  • Description – the description of the widget displayed as a tooltip.
  • IconClass – the font icon class displayed when viewing the widgets in the widget list.
[assembly: RegisterWidget("CompanyName.Widgets.NumberWidget", typeof(NumberWidgetController), "Selected number", Description = "Displays a message including a selected number.", IconClass = "icon-one")]

Localizing widget metadata

To allow content editors to experience the page builder in their preferred UI culture, you can localize the display names and descriptions of widgets.

Adding scripts and styles for widgets

To add JavaScript and CSS styles required by your page builder widgets, place script and stylesheet files into sub-folders under the ~/Content/Widgets directory of your MVC project (you may need to create the Widgets directory). Use sub-folders that match the identifiers of individual widgets, or a Shared sub-folder for assets used by mutliple widgets.

The system automatically creates bundles containing all .js and .css files located under ~/Content/Widgets. The bundles are then linked on all pages with page builder editable areas.

The same bundles also contain script and stylesheet files added for sections in the ~/Content/Sections directory and inline property editors in the ~/Content/InlineEditors directory (inline editor scripts and styles are only included in the administration bundles, which are linked when pages are displayed in Edit mode within the Pages application of Kentico).

CSS notes

  • Only use the ~/Content/Widgets directory to add basic styles that are required for the widget to render correctly. Any site-specific styles that finalize the live site design of the widget should be handled separately within the given site's main stylesheet.
  • To avoid potential conflicts between styles from other third-party components, we recommend adding a unique prefix to your CSS classes and identifiers (for example #CompanyName-mid-button), or employ similar measures to ensure their uniqueness.
  • Do not make any assumptions about the relative order of the source CSS in the resulting bundles – individual stylesheet files contained in the bundle may or may not precede each other.

Initializing widget scripts

In many cases, you will need to initialize your scripts from the views of widgets (for example if you need to call a function on page load or register an event listener). For most types of page or element events, you can use HTML Event Attributes of elements in your views.

For scripts that you want to run on page load, you need to consider the following:

  • The bundles containing your main scripts are added at the end of the HTML document's body tag, so they are not available in the widget code during the page load process. A solution is to run the initialization script during the DOMContentLoaded event.
  • Widgets in the page builder interface may be added dynamically after the page is loaded. In this case, the DOMContentLoaded event has already occurred and will not fire again.

For example, the following script demonstrates how to reliably call a custom function on page load:

if (document.readyState === "loading") {
    // Calls the function during the 'DOMContentLoaded' event, after the HTML document has been completely loaded
    document.addEventListener("DOMContentLoaded", function () {
        customFunction();
    });
} else { 
    // Calls the function directly in cases where the widget is rendered dynamically after 'DOMContentLoaded' has occurred
    customFunction();
}

This approach ensures that the initialization script runs correctly when the widget is displayed on the live site, as well as in the page builder interface.

Note: Apart from initialization code, avoid linking or executing scripts directly within widget views – this could lead to duplicated scripts on pages that contain multiple instances of the same widget.


Was this page helpful?