> For the complete documentation index, see [llms.txt](https://omalab.gitbook.io/guide/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://omalab.gitbook.io/guide/engineering-wiki/front-end/how-to-create-ui-components.md).

# How to create UI components

The page describes how to create a new UI component.

A fully functional example of source code you can find [here](https://github.com/omalab/oma/commit/03847e519214dafa672954e0c4e1fed4370b8d98)

## Steps

### Create a component class

Create a class inherited from`ApplicationComponent`under`app/components/`. By convention a class for a component must end in "Component". Add`#initialize`method to the class.

```
    def initialize(template, model)
      super template

      @model = model
    end
```

**Tips**

* It is better if namespaces of a component and a related controller are similar. It is not required but it simplifies stuff.
* it is encouraged to create a related presenter class as a counterpart of a UI component. In this case a presenter is responsible for fetching data, including optimization concerns. At the same moment a component is responsible for: 1) rendering data, including formatting 2) handling details of WEB UI (for example how to translate names of request params to attributes of a presenter)

**Example**: [component class](https://github.com/omalab/oma/blob/03847e519214dafa672954e0c4e1fed4370b8d98/app/components/keyword_tag/pre_association_form_component.rb)

### Create a view partial for a component

Create a partial file (/^\_\*.html.erb$/) under`app/views/components`. A file-path to just created view have to mimic namespacing of the component. For example if we have`Foo::Bar::BazComponent`, we have to create`app/views/components/foo/bar/_baz.html.erb`.

**Example**:[partial](https://github.com/omalab/oma/blob/03847e519214dafa672954e0c4e1fed4370b8d98/app/views/components/keyword_tag/_pre_association_form.html.erb)

### Instantiate a component object

Instantiate a component object using`ApplicationController#new_component`method:

```
  @baz = new_component(::Foo::Bar::BazComponent, @some_presenter)
```

**Example**: [instantiation](https://github.com/omalab/oma/blob/03847e519214dafa672954e0c4e1fed4370b8d98/app/controllers/keyword_tag/pre_associations_controller.rb#L9)

### Call #render

Render your component using inherited`#render`method:

```
<%= @baz.render %>
```

**Example**: [call render](https://github.com/omalab/oma/blob/03847e519214dafa672954e0c4e1fed4370b8d98/app/views/keyword_tag/pre_associations/new.html.erb)

### Add JavaScript support (optional)

If your component depends on JS functionality, you should perform a few additional steps.

Mix`JsAware`module to your component.

```
module Foo
  module Bar
    class BazComponent < ApplicationComponent
      include JsAware
      ...
```

Create JS file under`app/javascripts/main/components/`using the same approach to "namespacing" like for the view partial:`app/javascripts/main/components/foo/bar/baz.js`

A javascript object for a component should have`init`method. Th method is call right after component is rendered.

```
window.foo = window.foo || {}
window.foo.bar = window.foo.bar || {}

window.foo.bar.Baz = (function () {
  var c = {};

  c.init = function (_opts) {
    $('.baz-time').html(new Date().toString())
  }

  return c;
})();
```

Add newly created JS file to grunt.js. It is preferable to use wildcards:

```
'app/javascripts/main/components/foo/bar/*.js'
```

Recompile javascript (run`grunt`console command).

**Example**: [js file](https://github.com/omalab/oma/blob/03847e519214dafa672954e0c4e1fed4370b8d98/app/javascripts/main/components/keyword_tag/pre_association_form.js\),\[grung]\(https://github.com/omalab/oma/blob/03847e519214dafa672954e0c4e1fed4370b8d98/grunt.js#L119)

*Basically that's it. We just created a new UI component.*


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://omalab.gitbook.io/guide/engineering-wiki/front-end/how-to-create-ui-components.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
