# Page Object Elements

Elements can have different types.

## Element types

If a component has an HTML element that you need in the page object, declare an element as an object in an `elements` array.
You can put an element object in an `elements` array at the root, inside a shadow, or nested inside a basic element.

These are the element types:

- [Basic element](/grammar/page-object-elements#basic-elements) represents standard HTML element like anchor or div and should be added only if it’s needed for user interactions or to scope other elements.
- [Custom element](/grammar/page-object-elements#custom-elements) represents a nested/child component, and therefore has a `type` property that references another page object that matches this nested/child component.
- [Container element](/grammar/page-object-elements#container-elements) represents `slot` or `lwr-dynamic` that can act as a container to inject other components whose types are unknown to the component developer.
- [Frame element](/grammar/page-object-elements#frame-elements) represents a frame or an iframe.

An element has properties.

- Each element type has `name`, `type`, and `selector` properties.
- Each element type can be marked as `public`.
- If it takes time for the element to load, use an explicit wait using the `wait` property.
- If the page object needs to wait on the element to load, use the `load` property. This element cannot have arguments.
- Any element type can be marked as [nullable](/docs/platform/utam/guide/nullable-vs-ispresent.md).

There are limitations for different elment types:

- Frame cannot have nested elements.
- Only basic or custom elements can have a [filter](/docs/platform/utam/references/utam-grammar/element-filters.md).

## Basic Elements

A basic element can have these properties:

- `name` (Required) String. The element name, which UTAM uses in the getter method name. The value must be unique within the JSON file.

- `type` (Optional) A String for a single type or an array of strings. A list of the types of user interaction that this basic element supports. If omitted, it defaults to a base element type, which supports the methods listed in the Base Element Actions table in [actions](/grammar/basic-actions#base-element-actions).

  To allow more interaction, add one or more of these values to the type array:

  - `actionable` Exposes the methods listed in the [Actionable Type Actions table](/docs/platform/utam/references/utam-grammar/basic-actions.md#actionable-type-actions).
  - `clickable` Exposes the methods listed in the [Clickable Type Actions table](/docs/platform/utam/references/utam-grammar/basic-actions.md#clickable-type-actions).
  - `editable` Exposes the methods listed in the [Editable Type Actions table](/docs/platform/utam/references/utam-grammar/basic-actions.md#editable-type-actions).
  - `draggable` Exposes the methods listed in the [Draggable Type Actions table](/docs/platform/utam/references/utam-grammar/basic-actions.md#draggable-type-actions).
  - `touchable` Exposes the methods for mobile device interactions listed in the [Touchable Type Actions table](/grammar/basic-actions#touchable-type-actions).

- `selector` (Required) Object. Locates the element inside its immediate parent. See [Selector properties](/docs/platform/utam/references/utam-grammar/element-selectors.md#selector-properties).

- `filter` (Optional) Object. Picks an element from a list or filters a list at run time. See [Element Filters](/docs/platform/utam/references/utam-grammar/element-filters.md).

- `nullable` (Optional, default is `false`). Boolean. If set to `true` and the element can't be found inside its parent, the getter method returns `null`. If set to `false`, an error is thrown if the element isn't found. For examples, see [Guide: Nullable Versus isPresent](/guide/presence).

- `public` (Optional, default is `false`) Boolean. If set to `true`, UTAM generates a public method that returns an instance of the element with the given type. The name of the getter is generated automatically from the `name` property as `get<Name>` (the value of the `name` property is capitalized).

- `wait` (Optional, default is `false`) Boolean. If set to `true`, UTAM generates a public method that [waits for the element](/docs/platform/utam/references/utam-grammar/page-object-elements.md#wait-for-an-element).

- `load` (Optional, default is `false`) Boolean. If set to `true`, UTAM generates a private method that [waits for the element](/docs/platform/utam/references/utam-grammar/page-object-elements.md#load-an-element) and automatically adds it to the [beforeLoad](/grammar/before-load) method of the page object.

- `shadow` (Optional) Object. A shadow boundary. Contains only an `elements` property, which is a nested tree of objects.

- `elements` (Optional) Array. Contains a nested tree of element objects that are located inside this basic element.

```json
{
  "elements": [
    {
      "name": "myElement",
      "type": ["clickable", "editable"],
      "public": true,
      "selector": {
        "css": ".element"
      },
      "elements": []
    }
  ]
}
```

If an element has one basic type only, it can be defined as a string instead an array of strings. For example, this root element has the `actionable` type only:

```json
{
  "exposeRootElement": true,
  "type": "actionable"
}
```

UTAM generates a public method that returns an instance of the element to interact with.

Java:

```java
public MyElementElement getMyElement() {
    // return element
}
```

JavaScript:

```js
//declaration
getMyElement(): Promise<_BaseUtamElement>;

// implementation
async getMyElement() {
    const driver = this.driver;
    const root = await this.getRootElement();
    let element = await _utam_get_myElement(driver, root, );
    return new _ActionableUtamElement(driver, element);
}
```

## Custom Elements

A custom element has the same properties as a [basic element](#basic-elements), except that the `type` property is required and must reference another page object.

- `type` (Required) String. A reference to a UTAM page object. The format is:

  ```
  <package name>/pageObjects/<component namespace>/<page object name>
  ```

  For JavaScript, the `<package name>` and the `<page object name>` are required and can include only alphanumeric characters and dashes. The path between these segments is optional. Each path segment can contain only alphanumeric characters (no dashes).

  For Java, the `<package name>` must start with `utam-` and the `/pageObjects/` segment is required. The `<page object name>` must be a valid class name (it can't include dashes). It can start with a lowercase character, because the compiler transforms it to uppercase.

  For Java, the UTAM compiler transforms the `type` value to match Java syntax rules.

  - `<package name>`: transform `-` into `.`
  - Path: transform `/` into `.`; transform uppercase characters into lowercase.
  - `<page object name>`: transform lowercase first letter to uppercase, because Java class names always start with an uppercase character.

    ```java
    // JSON
    "type": "utam-navex/pageObjects/one/navigationBar"

    // UTAM compiler transforms to:
    utam.navex.pageobjects.one.NavigationBar
    ```

This example declares a custom element called `todo-item`, which lives in the `utam-tutorial` package.

```json
{
  "root": true,
  "selector": { "css": "body" },
  "elements": [
    {
      "name": "todoApp",
      "type": "utam-tutorial/todoApp",
      "selector": { "css": "example-todo-app" },
      "public": true,
      "shadow": {
        "elements": [
          {
            "name": "todoItem",
            "selector": { "css": "example-todo-item" },
            "public": true,
            "type": "utam-tutorial/todoItem"
          }
        ]
      }
    }
  ]
}
```

:::important
Elements should only be nested inside custom element if it mimics component code. In most cases custom element only references another page object type and everything is encapsulated inside the page object.
:::

The generated `getTodoItem()` method returns an object scoped inside its parent element.

JavaScript:

```js
getTodoApp(): Promise<_ActionableUtamElement>;
getTodoItem(): Promise<_todoItem>;
```

## Container Elements

There are certain requirements to declare a container element for a slot. For more information, see the guidelines in the [slots guide](/docs/platform/utam/guide/slots.md).

Let's look at an example where we would need to declare a container element.
For example, here is a component that has a placeholder for content in an output field. In component source code, a placeholder is a `slot`.

```html
<template>
    <div class="slds-form-element__control">
        <span
            class={computedOutputFieldContainerClass}
            oninlineeditbehavioroverride={handleInlineEditBehaviorOverride}>
            <!-- slot for a field -->
            <slot name="outputField"></slot>
        </span>
    </div>
</template>
```

In this case, declare an element with `"type": "container"`. The compiler generates a method with a parameter for the type of the component being loaded.

A container element has these properties:

- `name` (Required) String. An element name that's unique to this JSON file.
- `type` (Required) String. The value must be `container`.
- `public` (Optional, default is `false`) Boolean. Must be set to `true` so that UTAM generates a public method.
- `selector` (Optional, default is `"css": ":scope > *:first-child"`). A [selector](/docs/platform/utam/references/utam-grammar/element-selectors.md#selector-properties) injected as a root for the container content.
- `nullable` (Optional, default is `false`). Boolean. If set to `true` and the element can't be found inside its parent, the getter method returns `null`. If set to `false`, an error is thrown if the element isn't found. For examples, see [Guide: Nullable Versus isPresent](/guide/presence).
- `wait` (Optional, default is `false`) Boolean. If set to `true`, UTAM generates a public method that [waits for the element](/docs/platform/utam/references/utam-grammar/page-object-elements.md#wait-for-an-element).
- `shadow` (Optional) Object. A shadow boundary. Contains only an `elements` property, which is a nested tree of objects.
- `elements` (Optional) Array. Contains a nested tree of element objects that are located inside this basic element.

As with any other element, if there's a `#shadow-root` between the basic element and the nested container element, enclose the container element in a `shadow` object. Note that slots are usualy **not** inside shadow root.

Most containers would not have a hardcoded selector because content is unknown, except for named slots. If a selector is omitted, a default CSS selector of `:scope > *:first-child` will be used in the generated code.

For our example, the container element is:

```json
{
  "elements": [
    {
      "name": "outputFieldContent",
      "type": "container",
      "public": true,
      "selector": {
        "css": "[slot='outputField']"
      }
    }
  ]
}
```

UTAM generates this JavaScript code.

```js
async function _utam_get_outputFieldContent(driver, root) {
    let _element = root;
    const _locator = core.By.css("[slot='outputField']");
    return _element.findElement(_locator);
}

async getOutputFieldContent(ContainerCtor) {
        const driver = this.driver;
        const root = await this.getRootElement();
        let element = await _utam_get_outputFieldContent(driver, root, );
        element = new ContainerCtor(driver, element);
        return element;
}
```

From the test, we can load any page object inside our container.

```js
const textFieldPageObject = await myPageObject.getOutputFieldContent(TextField);
```

If the selector inside the container is marked with `"returnAll": true`, the generated container method returns an array (in JavaScript) or a list (in Java) of objects.

### Elements nested inside container

Container can have nested elements if it mimics component code, for example when source component provides default content of the slot. In most cases container does not have nested elements.

For example if component has following code that puts default content inside slot:

```html
<template if:false="{showThankYou}">
  <slot>
    <div class="form-icon">
      <lightning-icon icon-name="utility:form"></lightning-icon>
    </div>
  </slot>
</template>
```

then UTAM Page Object can have following nested element:

```json
{
  "name": "content",
  "type": "container",
  "public": true,
  "elements": [
    {
      "name": "utilityIcon",
      "selector": { "css": "lightning-icon" },
      "public": true,
      "type": "utam-lightning/pageObjects/icon"
    }
  ]
}
```

## Frame Elements

To load a frame or an iframe, use a frame element with the following properties:

- `name` (Required) String. The element name, which UTAM uses in the getter method name. The value must be unique within the JSON file.
- `type` (Required) String. Set to `frame` and extends Basic element type.
- `public` (Optional, default is `false`) Boolean. If set to `true`, UTAM generates a public method that returns an instance of the element with the given type. The name of the getter is generated automatically from the `name` property as `get<Name>` (the value of the `name` property is capitalized).
- `selector` (Required) Object. Locates the element inside its immediate parent. See [Selector properties](/docs/platform/utam/references/utam-grammar/element-selectors.md#selector-properties). Note that `returnAll` inside a selector isn't allowed for a frame.
- `nullable` (Optional, default is `false`). Boolean. If set to `true` and the element can't be found inside its parent, the getter method returns `null`. If set to `false`, an error is thrown if the element isn't found. For examples, see [Guide: Nullable Versus isPresent](/guide/presence).
- `wait` (Optional, default is `false`) Boolean. If set to `true`, UTAM generates a public method that [waits for the element](/docs/platform/utam/references/utam-grammar/page-object-elements.md#wait-for-an-element).
- `load` (Optional, default is `false`) Boolean. If set to `true`, UTAM generates a private method that [waits for the element](/docs/platform/utam/references/utam-grammar/page-object-elements.md#load-an-element) and automatically adds it to the [beforeLoad](/grammar/before-load) method of the page object.

Here's an example of a frame element:

```json
{
  "name": "myPublicFrame",
  "public": true,
  "type": "frame",
  "selector": {
    "css": "iframe"
  }
}
```

The generated code returns an object of the special `FrameElement` type that can be used as a parameter in methods to switch between frames.

## Wait for an element

If an element has `wait` set to `true`, UTAM generates a public method that waits for the element with the name `waitFor<ElementName>`.
The method uses [predicate syntax](/grammar/explicit-waits#grammar) and wraps the invocation of the element getter into a fluent wait.

For example for the following element:

```json
{
  "name": "mySlowElement",
  "selector": {
    "css": ".slow"
  },
  "wait": true
}
```

The generated JavaScript code is:

```js
async waitForMySlowElement() {
    const _result0 = await this.waitFor(async () => {
        const _result0 = await this.__getMySlowElement();
        return _result0;
    });
    return _result0;
}
```

If marked as `public`, the element will have both public getter and `waitFor` methods.

## Load an element

If an element has `load` set to `true`, UTAM generates a private method that waits for the element with the name `waitFor<ElementName>`.
The method uses [predicate syntax](/grammar/explicit-waits#grammar) and wraps the invocation of the element getter into a fluent wait.
This wait method is then automatically invoked in the page object's [beforeLoad](/grammar/before-load) method.

For example for the following element:

```json
{
  "name": "mySlowElement",
  "selector": {
    "css": ".slow"
  },
  "load": true
}
```

The generated JavaScript code is:

```js
async __waitForMySlowElement() {
    const _result0 = await this.waitFor(async () => {
        const _result0 = await this.__getMySlowElement();
        return _result0;
    });
    return _result0;
}

async __beforeLoad__() {
    await this.__waitForMySlowElement();
}

```

:::note
If the `wait` property for this element is also set to true, the `waitFor<ElementName>` method will also be public.
Additionally, `load` can't be set to true for an element with arguments or a container element.
:::
