> For the complete documentation index, see [llms.txt](https://webix.gitbook.io/webix-jet/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://webix.gitbook.io/webix-jet/part-iii-practical-tasks/creating-complex-widgets.md).

# Creating Complex Widgets

To create simple and medium-sized widgets that enclose some third party library components or a few Webix widgets, you can use [webix.protoUI()](https://docs.webix.com/desktop__custom_component.html). Custom widgets must be based on **webix.ui.view**, while custom layouts must be based on **webix.ui.layout** and have the layout configuration defined in the **$init** method.

For complex cases, when you want to create a widget with multiple layouts, dynamic views, complex data, etc., it is better to use Webix Jet.

## How to Create

Create a Jet app and convert it into a new widget with **webix.protoUI()** with **webix.ui.jetapp** as the base:

```javascript
// sources/newwidget.js
import {JetApp} from "webix-jet";
export default class NewWidgetApp extends JetApp {
    constructor(){
        const defaults = {
            id		: APPNAME,
            version	: VERSION,
			debug	: !PRODUCTION,
			router	: EmptyRouter,
            start	: "/top/start"
        };
        super({ ...defaults, ...config });
    }
}

// this!
if (!BUILD_AS_MODULE){
    webix.ready(() => new MyApp().render() );

webix.protoUI({
    name:"new-widget",
    app: NewWidgetApp
}, webix.ui.jetapp);
```

Later this widget can be used like an ordinary Webix widget (included on a page, in Webix layout, resized, etc.):

```javascript
webix.ui({
    rows:[
        { view:"toolbar", elements:[...] },
        {
            cols:[ { menu }, { view:"new-widget" } ]
        }
    ]
});
```

## Very Important

If you plan to use Jet app as a widget, keep in mind a few things:

*1. **Do not use** any hard-coded **"id"** values*.

This will prevent initializing more than one instance of the widget, because the IDs will be no longer unique. Instead, use **localId** and locate widgets inside the view with [this.$$()](/webix-jet/api/jetview-api.md#this-usdusd).

*2. Use **services** instead of **models** for data loading*.

Models are shared between all instances of a widget, so a change in the data of one instance of the widget will reflect in all other instances. A common use-case will be to have all instances with separate states and unique data models.

Instead of importing a model as usual:

```javascript
import {data} from "models/records";
```

modify the model in such a way, that a new DataCollection should be created for every instance:

```javascript
// models/records.js
export function records(){
    const data = new webix.DataCollection({
        url:"data/records.php"
    });
    return { data };
}
```

Then import the model and set a service that will create a new DataCollection when necessary:

```javascript
// app.js
import {JetApp} from "webix-jet";
import {records} from "models/records";

export default class MyApp extends JetApp {
    constructor(config){
        super(config);
        this.setService("records", records());
    }
}
...
```

Later any view inside the widget can get a new copy of data model with the help of the service:

```javascript
// views/myview.js
import {JetView} from "webix-jet";
export default class MyView extends JetView {
    ...
    init(){
        this.data = this.app.getService("records").data;
    }
}
```
