# EntityPage

**Category:** Base Components/Pages/Entity Page

## Overview

### Introduction

The `EntityPage` component serves as a container that encapsulates the logic and layout structure for rendering an entity page. It provides a structured and organized way to display and manage information related to a specific entity.

Here's a breakdown of its main purposes:

1. **Appearance of the Entity Page**: The `EntityPage` component handles the overall layout and structure of the entity page. It defines how the page is organized, including title and subtitle, more actions dropdown, CTAs, content basic layout and widgets. Also, it is responsible for rendering loading skeletons, error state, displaying notifications and other.

2. **Handling Fetch**: The `EntityPage` component typically integrates with a fetch mechanism (e.g., an API call) to retrieve data related to the entity being displayed on the page. This integration is done through the `fetch` function passed as a prop to the [`useEntityPage`](./?path=/story/base-components-pages-entity-page-hooks-useentitypage--useentitypage) hook, allowing the component to retrieve the necessary data for rendering. You can use the [`useEntity`](./?path=/story/base-components-pages-entity-page-hooks-useentity--useentity)  to access a fetched entity.

3. **Handling Save and Validation Logic**: The [useForm](https://react-hook-form.com/docs/useform)  hook from [react-hook-form](https://react-hook-form.com/) is used to create a form object, and the `onSave` function passed as a prop to the [`useEntityPage`](./?path=/story/components-page-entitypage-hooks-useentitypage--useentitypage) hook, is triggered when the user initiates a save action.

4. **Easy integration with open platform capabilities**: Create a container in Dev Center, and Wix Patterns will automatically fetch and display the relevant plugins. Pass your `componentId` to the `componentId` prop of `EntityPage.Slots` to add widgets to an entity page, or to the `componentId` prop of [`MoreActions`](./?path=/story/features-actions-more-actions--moreactions) to extend the "More Actions" menu with extra items.

In summary, the ``EntityPage`` component and the associated [`useEntityPage`](./?path=/story/base-components-pages-entity-page-hooks-useentitypage--useentitypage) hook together provide a streamlined approach to rendering, fetching, saving, and validating data for a specific entity within an application.


---

### Demo

This comprehensive demo demonstrates all the key functionalities supported by `EntityPage`:

- Page designed with 2 sections: the main content using the [EntityPage.MainContent](./?path=/story/base-components-pages-entity-page--entitypage-maincontent) component and the additional content using the [EntityPage.AdditionalContent](./?path=/story/base-components-pages-entity-page--entitypage-additionalcontent) component.

- [MoreActions](./?path=/story/base-components-pages-entity-page--entitypage-header#More_Actions), offering a more actions menu with inline actions and additional actions that are extended using `containerId`, alongside [EntityPage.Slots](./?path=/story/base-components-pages-entity-page--entitypage-slots) which enable the broadening of your UI with a variety of Cards.

- Integration with current widgets such as [CustomFieldsWidget](./?path=/story/base-components-pages-entity-page--entitypage-customfieldswidget) and [TagsWidget](./?path=/story/base-components-pages-entity-page--entitypage-tagswidget), linked to the page's state, enables their use in conjunction with the page's isDirty state.

- A save and validation process that ensures required fields are filled.

Explore the [Examples](./?path=/story/components-page-entitypage--entitypage&tab=Examples) section for a clearer understanding of the various states of the entity state, and examine each sub-component to see their available states and examples.


```tsx
import React from 'react';
import {
  CustomFieldsWidget,
  EntityPage,
  EntityPageState,
  MoreActions,
  TagsWidget,
  useEntity,
  useEntityPage,
  useEntityPageContext,
} from '@wix/patterns';
import { useController, useForm } from '@wix/patterns/form';
import { ExtendedFields, Tags } from '@wix/patterns/core';
import {
  Box,
  Card,
  FormField,
  Input,
  Text,
  Checkbox,
} from '@wix/design-system';
import { InvoiceSmall } from '@wix/wix-ui-icons-common';

interface MyEntity {
  id?: string;
  name?: string;
  booleanField?: boolean;
  createdDate?: Date;
  updatedDate?: Date;
  extendedFields?: ExtendedFields;
  tags?: Tags;
}

interface FormFields {
  name?: string;
  booleanField?: boolean;
}

function FullExample() {
  const form = useForm<FormFields>();
  const state: EntityPageState<MyEntity> = useEntityPage<MyEntity, FormFields>({
    parentPageId: 'YOUR_PARENT_PAGE_ID',
    form,
    onSave: ({ widgetsFormData: { extendedFields, tags } }) =>
      new Promise((res) => {
        window.setTimeout(() => {
          const formValues = form.getValues();

          const updatedEntity: MyEntity = {
            ...state.entity,
            ...formValues,
            extendedFields,
            tags,
          };

          console.log('updated entity:', updatedEntity);

          if (state.entity?.id) {
            console.log('update request');
          } else {
            console.log('create request');
          }

          res({ updatedEntity });
        }, 1000);
      }),
    saveErrorToast: (e) => 'Failed to save',
    fetch: () =>
      new Promise((res) => {
        window.setTimeout(
          () =>
            res({
              entity: {
                id: 'id',
                name: 'Entity Name',
                booleanField: true,
                createdDate: new window.Date(),
                updatedDate: new window.Date(),
                extendedFields: {
                  namespaces: {
                    _user_fields: {
                      datetime: '2023-05-31T21:00:00.000Z',
                      date: '1990-06-13',
                      shortText: 'Hello world!',
                      longText: 'Hello world! '.repeat(15),
                      checkbox: true,
                      decimal: 3.14,
                      integer: 43,
                      url: 'https://www.wix.com/',
                    },
                  },
                },
                tags: { privateTags: { tagIds: [] } },
              },
            }),
          500,
        );
      }),
  });

  // Usually we will extract this component to a separate file
  const MainContent = () => {
    const pageState = useEntityPageContext<MyEntity, FormFields>();

    const name = useController({
      name: 'name',
      control: pageState.form.control,
      defaultValue: pageState.entity?.name,
      rules: { required: { value: true, message: 'This field is required!' } },
    });

    const booleanField = useController({
      name: 'booleanField',
      control: pageState.form.control,
      defaultValue: pageState.entity?.booleanField,
    });

    return (
      <Card.Content>
        <Box gap="SP2" direction="vertical">
          <FormField label="Name">
            <Input
              dataHook="name-input"
              status={name.fieldState.invalid ? 'error' : undefined}
              statusMessage={name.fieldState.error?.message}
              inputRef={name.field.ref}
              value={name.field.value}
              onChange={name.field.onChange}
              onBlur={name.field.onBlur}
            />
          </FormField>
          <FormField label="Boolean Field">
            <Checkbox
              dataHook="boolean-field-checkbox"
              checked={booleanField.field.value}
              onChange={booleanField.field.onChange}
            >
              Use boolean field
            </Checkbox>
          </FormField>
        </Box>
      </Card.Content>
    );
  };

  const entity = useEntity<MyEntity, FormFields>(state);

  return (
    <EntityPage state={state}>
      <EntityPage.Header
        title={{ text: entity?.name ?? '' }}
        subtitle={{
          text: `id: ${entity?.id}`,
          learnMore: {
            url: 'https://www.wix.com/',
            label: 'My custom learn more', // Defaults to "Learn more"
          },
        }}
        moreActions={
          <MoreActions
            containerId="cd910877-1bb2-445e-822a-aa04a342c2f5"
            items={[
              [
                {
                  biName: 'open-subscriptions',
                  text: 'Open Subscriptions',
                  prefixIcon: <InvoiceSmall />,
                  onClick: () => {
                    console.log('Open Subscriptions');
                  },
                },
              ],
            ]}
          />
        }
      />
      <EntityPage.Content>
        <EntityPage.MainContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Main Content Card" />
            <Card.Divider />
            <MainContent />
          </EntityPage.Card>
          <CustomFieldsWidget
            fqdn="wix.patterns.dummyservice.v1.dummy_entity"
            dataHook="demo-custom-fields-widget"
            extendedFields={entity?.extendedFields}
          />
        </EntityPage.MainContent>
        <EntityPage.AdditionalContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Side Content Card" />
            <Card.Divider />
            <Card.Content>
              <Box gap="SP2" direction="vertical">
                <Text>Stretched to 4/12 of available space.</Text>
              </Box>
            </Card.Content>
          </EntityPage.Card>
          <EntityPage.Slots containerId="cd910877-1bb2-445e-822a-aa04a342c2f5" />
          <TagsWidget
            fqdn="wix.patterns.dummyservice.v1.dummy_entity"
            dataHook="demo-tags-widget"
            entityTypeName="My Entity"
            entityId={entity?.id}
            initialTags={entity?.tags}
          />
        </EntityPage.AdditionalContent>
      </EntityPage.Content>
    </EntityPage>
  );
}
```

## Examples

### Variations

### Basic

This example demonstrates a basic usage of the `EntityPage`.

```tsx
import React from 'react';
import {
  EntityPage,
  EntityPageState,
  useEntity,
  useEntityPage,
} from '@wix/patterns';
import { useForm } from '@wix/patterns/form';
import { Box, Card, Text } from '@wix/design-system';

interface MyEntity {
  id: string;
  name?: string;
  createdAt: Date;
  updatedAt: Date;
}

interface FormValues {
  name?: string;
}

function Basic() {
  const form = useForm<FormValues>();
  const state: EntityPageState<MyEntity, FormValues> = useEntityPage<
    MyEntity,
    FormValues
  >({
    parentPageId: '',
    form,
    onSave: async () => {
      const formValues = form.getValues();

      return Promise.resolve({
        updatedEntity: {
          ...state.entity,
          ...formValues,
        } as MyEntity,
      });
    },
    saveErrorToast: (e) => 'Failed to save',
    fetch: () =>
      Promise.resolve({
        entity: {
          id: 'id',
          name: 'Entity Name',
          createdAt: new window.Date(),
          updatedAt: new window.Date(),
        },
      }),
  });

  const entity = useEntity<MyEntity, FormValues>(state);

  return (
    <EntityPage state={state}>
      <EntityPage.Header title={{ text: entity?.name ?? '' }} />
      <EntityPage.Content>
        <EntityPage.MainContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Name Card" />
            <Card.Divider />
            <Card.Content>
              <Box gap="SP2" direction="vertical">
                <Text>{entity?.name}</Text>
              </Box>
            </Card.Content>
          </EntityPage.Card>
        </EntityPage.MainContent>
      </EntityPage.Content>
    </EntityPage>
  );
}
```

---

### 2 Columns

This example illustrates the use of both main and additional content.

```tsx
import React from 'react';
import {
  EntityPage,
  EntityPageState,
  useEntity,
  useEntityPage,
} from '@wix/patterns';
import { useForm } from '@wix/patterns/form';
import { Box, Card, Text } from '@wix/design-system';

interface MyEntity {
  id: string;
  name?: string;
  createdAt: Date;
  updatedAt: Date;
}

function TwoColumns() {
  const form = useForm();
  const state: EntityPageState<MyEntity> = useEntityPage<MyEntity>({
    parentPageId: '',
    form,
    onSave: () =>
      Promise.resolve({
        updatedEntity: {
          ...state.entity,
        } as MyEntity,
      }),
    saveErrorToast: (e) => 'Failed to save',
    fetch: () =>
      Promise.resolve({
        entity: {
          id: 'id',
          name: 'Entity Name',
          createdAt: new window.Date(),
          updatedAt: new window.Date(),
        },
      }),
  });

  const entity = useEntity<MyEntity>(state);

  return (
    <EntityPage state={state}>
      <EntityPage.Header title={{ text: entity?.name ?? '' }} />
      <EntityPage.Content>
        <EntityPage.MainContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Main Content Card" />
            <Card.Divider />
            <Card.Content>
              <Box gap="SP2" direction="vertical">
                <Text>Stretched to 8/12 of available space.</Text>
              </Box>
            </Card.Content>
          </EntityPage.Card>
        </EntityPage.MainContent>
        <EntityPage.AdditionalContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Side Content Card" />
            <Card.Divider />
            <Card.Content>
              <Box gap="SP2" direction="vertical">
                <Text>Stretched to 4/12 of available space.</Text>
              </Box>
            </Card.Content>
          </EntityPage.Card>
        </EntityPage.AdditionalContent>
      </EntityPage.Content>
    </EntityPage>
  );
}
```

---

### Loading

This sample illustrates the skeleton state of an entity page based on the provided structure.

```tsx
import React from 'react';
import { EntityPage, EntityPageState, useEntityPage } from '@wix/patterns';
import { useForm } from '@wix/patterns/form';
import { Box, Card, Text } from '@wix/design-system';

interface MyEntity {
  id: string;
  name?: string;
  createdAt: Date;
  updatedAt: Date;
}

interface FormFields {
  id: string;
  name?: string;
}

function Loading() {
  const form = useForm<FormFields>();
  const state: EntityPageState<MyEntity, FormFields> = useEntityPage<
    MyEntity,
    FormFields
  >({
    parentPageId: 'YOUR_PARENT_ID_HERE',
    form,
    onSave: () =>
      new Promise((resolve) => {
        const formValues = form.getValues();
        console.log('form values:', formValues);

        window.setTimeout(
          () =>
            resolve({
              updatedEntity: {
                ...state.entity,
                ...formValues,
              } as MyEntity,
            }),
          1000,
        );
      }),
    saveErrorToast: (e) => 'Failed to save',
    fetch: () =>
      new Promise((resolve) => {
        const dateToResolve = new window.Date(window.Date.now());
        // keep waiting :)
        if (dateToResolve.getFullYear() === 2500) {
          resolve({
            entity: {
              id: 'id',
              name: 'My Entity',
              createdAt: new window.Date(),
              updatedAt: new window.Date(),
            },
          });
        }
      }),
  });

  return (
    <EntityPage state={state}>
      <EntityPage.Header title={{ text: 'Entity Page' }} />
      <EntityPage.Content>
        <EntityPage.MainContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Card" />
            <Card.Divider />
            <Card.Content>
              <Box>
                <Text>Main Card #1</Text>
              </Box>
            </Card.Content>
          </EntityPage.Card>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Card" />
            <Card.Divider />
            <Card.Content>
              <Box>
                <Text>Main Card #2</Text>
              </Box>
            </Card.Content>
          </EntityPage.Card>
        </EntityPage.MainContent>
        <EntityPage.AdditionalContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Card" />
            <Card.Divider />
            <Card.Content>
              <Box>
                <Text>Side Card #1</Text>
              </Box>
            </Card.Content>
          </EntityPage.Card>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Card" />
            <Card.Divider />
            <Card.Content>
              <Box>
                <Text>Side Card #2</Text>
              </Box>
            </Card.Content>
          </EntityPage.Card>
        </EntityPage.AdditionalContent>
      </EntityPage.Content>
    </EntityPage>
  );
}
```

---

### Error on Fetch

This example demonstrates the error state when fetching an entity fails.

```tsx
import React from 'react';
import {
  EntityPage,
  EntityPageState,
  useEntity,
  useEntityPage,
} from '@wix/patterns';
import { useForm } from '@wix/patterns/form';
import { Box, Card, Text } from '@wix/design-system';

interface MyEntity {
  id: string;
  name?: string;
  createdAt: Date;
  updatedAt: Date;
}

function FetchError() {
  const form = useForm();
  const state: EntityPageState<MyEntity> = useEntityPage<MyEntity>({
    parentPageId: '',
    form,
    onSave: async () => {
      return Promise.resolve({
        updatedEntity: {
          ...state.entity,
        } as MyEntity,
      });
    },
    saveErrorToast: (e) => 'Failed to save',
    fetch: () =>
      new Promise((_, reject) =>
        window.setTimeout(() => reject(new Error('Something went wrong')), 1000),
      ),
  });

  const entity = useEntity<MyEntity>(state);

  return (
    <EntityPage state={state}>
      <EntityPage.Header title={{ text: entity?.name ?? '' }} />
      <EntityPage.Content>
        <EntityPage.MainContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Main Content Card" />
            <Card.Divider />
            <Card.Content>
              <Box gap="SP2" direction="vertical">
                <Text>Stretched to 8/12 of available space.</Text>
              </Box>
            </Card.Content>
          </EntityPage.Card>
        </EntityPage.MainContent>
        <EntityPage.AdditionalContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Side Content Card" />
            <Card.Divider />
            <Card.Content>
              <Box gap="SP2" direction="vertical">
                <Text>Stretched to 4/12 of available space.</Text>
              </Box>
            </Card.Content>
          </EntityPage.Card>
        </EntityPage.AdditionalContent>
      </EntityPage.Content>
    </EntityPage>
  );
}
```

---

### Error on Save

This example demonstrates the error toast when saving an entity fails.

```tsx
import React from 'react';
import {
  EntityPage,
  EntityPageState,
  useEntity,
  useEntityPage,
} from '@wix/patterns';
import { useForm } from '@wix/patterns/form';
import { Box, Card, Text } from '@wix/design-system';

interface MyEntity {
  id: string;
  name?: string;
  createdAt: Date;
  updatedAt: Date;
}

function SaveError() {
  const form = useForm();
  const state: EntityPageState<MyEntity> = useEntityPage<MyEntity>({
    parentPageId: '',
    form,
    onSave: () => Promise.reject(new Error('Something went wrong')),
    saveErrorToast: (e, { retry }) => ({
      message: 'oops.. unknown error',
      action: { text: 'Retry', onClick: retry },
    }),
    fetch: () =>
      Promise.resolve({
        entity: {
          id: 'id',
          name: 'Entity Name',
          createdAt: new window.Date(),
          updatedAt: new window.Date(),
        },
      }),
  });

  const entity = useEntity<MyEntity>(state);

  return (
    <EntityPage state={state}>
      <EntityPage.Header title={{ text: entity?.name ?? '' }} />
      <EntityPage.Content>
        <EntityPage.MainContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Card" />
            <Card.Divider />
            <Card.Content>
              <Box gap="SP2" direction="vertical">
                <Text>I'm a card</Text>
              </Box>
            </Card.Content>
          </EntityPage.Card>
        </EntityPage.MainContent>
      </EntityPage.Content>
    </EntityPage>
  );
}
```

---

### Overriding Save Button Text

This examples demonstrates how to use the `saveCta` prop to override the default **Save** button text.

```tsx
import React from 'react';
import {
  EntityPage,
  EntityPageState,
  useEntity,
  useEntityPage,
} from '@wix/patterns';
import { useForm } from '@wix/patterns/form';
import { Box, Card, Text } from '@wix/design-system';

interface MyEntity {
  id: string;
  name?: string;
  createdAt: Date;
  updatedAt: Date;
}

interface FormValues {
  name?: string;
}

function SaveCta() {
  const form = useForm<FormValues>();
  const state: EntityPageState<MyEntity, FormValues> = useEntityPage<
    MyEntity,
    FormValues
  >({
    parentPageId: 'YOUR_PARENT_PAGE_ID',
    form,
    onSave: async () => {
      const formValues = form.getValues();

      return Promise.resolve({
        updatedEntity: {
          ...state.entity,
          ...formValues,
        } as MyEntity,
      });
    },
    saveErrorToast: (e) => 'Failed to save',
    fetch: () =>
      Promise.resolve({
        entity: {
          id: 'id',
          name: 'Entity Name',
          createdAt: new window.Date(),
          updatedAt: new window.Date(),
        },
      }),
  });

  const entity = useEntity<MyEntity, FormValues>(state);

  return (
    <EntityPage
      state={state}
      actionsBarConfig={{ saveCta: { text: 'ACTIVATE' } }}
    >
      <EntityPage.Header title={{ text: entity?.name ?? '' }} />
      <EntityPage.Content>
        <EntityPage.MainContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Name Card" />
            <Card.Divider />
            <Card.Content>
              <Box gap="SP2" direction="vertical">
                <Text>{entity?.name}</Text>
              </Box>
            </Card.Content>
          </EntityPage.Card>
        </EntityPage.MainContent>
      </EntityPage.Content>
    </EntityPage>
  );
}
```

---

### Developer Examples

### Input initialization with useController

This demonstrates how to use [useController](https://react-hook-form.com/docs/usecontroller) with the default value set at the `Card.Content` level. Note that the `state.entity` value is initialized following the Card skeleton loader. To obtain the initial value, it must be accessed within the Card.Content child, as illustrated in the following example. Accessing it before or at a higher level will result in an `undefined` value.

```tsx
import React from 'react';
import {
  EntityPage,
  EntityPageState,
  useEntity,
  useEntityPage,
  useEntityPageContext,
} from '@wix/patterns';
import { useController, useForm } from '@wix/patterns/form';
import { Box, Card, FormField, Input } from '@wix/design-system';
import { CardContainerProps } from '../../../dist/types/components/CardContainer';

interface MyEntity {
  id: string;
  name?: string;
  createdAt: Date;
  updatedAt: Date;
}

interface FormValues {
  name?: string;
}

function useControllerExample() {
  const form = useForm<FormValues>();
  const state: EntityPageState<MyEntity, FormValues> = useEntityPage<
    MyEntity,
    FormValues
  >({
    parentPageId: '',
    form,
    onSave: async () => {
      const formValues = form.getValues();

      return Promise.resolve({
        updatedEntity: {
          ...state.entity,
          ...formValues,
        } as MyEntity,
      });
    },
    saveErrorToast: (e) => 'Failed to save',
    fetch: () =>
      Promise.resolve({
        entity: {
          id: 'id',
          name: 'Entity Name',
          createdAt: new window.Date(),
          updatedAt: new window.Date(),
        },
      }),
  });

  // Usually we will extract this component to a separate file
  const CardContent = () => {
    const pageState = useEntityPageContext<MyEntity, FormValues>();
    const name = useController({
      name: 'name',
      control: pageState.form.control,
      defaultValue: pageState.entity?.name,
      rules: {
        required: { value: true, message: 'This field is required!' },
      },
    });

    return (
      <Box gap="SP2" direction="vertical">
        <FormField label="Name">
          <Input
            dataHook="name-input"
            inputRef={name.field.ref}
            value={name.field.value}
            onChange={name.field.onChange}
            onBlur={name.field.onBlur}
          />
        </FormField>
      </Box>
    );
  };

  const entity = useEntity<MyEntity, FormValues>(state);

  return (
    <EntityPage state={state}>
      <EntityPage.Header title={{ text: entity?.name ?? '' }} />
      <EntityPage.Content>
        <EntityPage.MainContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Name Card" />
            <Card.Divider />
            <Card.Content>
              <CardContent />
            </Card.Content>
          </EntityPage.Card>
        </EntityPage.MainContent>
      </EntityPage.Content>
    </EntityPage>
  );
}
```

---

### Input initialization with Controller

This demonstrates how to use [Controller](https://react-hook-form.com/docs/usecontroller/controller) where you can easily access the entity by using `useEntity`. This method allows for accessing the entity much earlier in the process. As a result, the default value will be dynamically updated as soon as the entity itself is updated, as shown in the example below.

```tsx
import React from 'react';
import {
  EntityPage,
  EntityPageState,
  useEntity,
  useEntityPage,
} from '@wix/patterns';
import { Controller, useController, useForm } from '@wix/patterns/form';
import { Box, Card, FormField, Input } from '@wix/design-system';
import { CardContainerProps } from '../../../dist/types/components/CardContainer';

interface MyEntity {
  id: string;
  name?: string;
  createdAt: Date;
  updatedAt: Date;
}

interface FormValues {
  name?: string;
}

function ControllerExample() {
  const form = useForm<FormValues>();
  const state: EntityPageState<MyEntity, FormValues> = useEntityPage<
    MyEntity,
    FormValues
  >({
    parentPageId: '',
    form,
    onSave: async () => {
      const formValues = form.getValues();

      return Promise.resolve({
        updatedEntity: {
          ...state.entity,
          ...formValues,
        } as MyEntity,
      });
    },
    saveErrorToast: (e) => 'Failed to save',
    fetch: () =>
      Promise.resolve({
        entity: {
          id: 'id',
          name: 'Entity Name',
          createdAt: new window.Date(),
          updatedAt: new window.Date(),
        },
      }),
  });

  const entity = useEntity<MyEntity, FormValues>(state);

  return (
    <EntityPage state={state}>
      <EntityPage.Header title={{ text: entity?.name ?? '' }} />
      <EntityPage.Content>
        <EntityPage.MainContent>
          <EntityPage.Card minHeight="24px">
            <Card.Header title="Name Card" />
            <Card.Divider />
            <Card.Content>
              <Controller
                control={form.control}
                name="name"
                defaultValue={entity?.name}
                rules={{
                  required: { value: true, message: 'This field is required!' },
                }}
                render={({
                  field: { onChange, onBlur, value, ref },
                  fieldState: { invalid, error },
                }) => (
                  <FormField
                    label="Name"
                    status={invalid ? 'error' : undefined}
                    statusMessage={error?.message}
                  >
                    <Input
                      dataHook="name-input"
                      inputRef={ref}
                      value={value}
                      onChange={onChange}
                      onBlur={onBlur}
                    />
                  </FormField>
                )}
              />
            </Card.Content>
          </EntityPage.Card>
        </EntityPage.MainContent>
      </EntityPage.Content>
    </EntityPage>
  );
}
```

## API

### Extends

[Page](https://www.docs.wixdesignsystem.com/?path=/story/components-layout-page--page)

### Props

| Prop | Type | Required | Default | Description |
|------|------|----------|---------|-------------|
| `state` | `EntityPageState<T, V>` | Yes | - | EntityPageState instance created with the `useEntityPage` hook |
| `actionsBarConfig` | `ActionsBarConfig` | No | - | Configuration for the actions bar |
| `children` | `ReactNode` | No | - | Accepts compound components as child items: - `<Page.Header/>` - `<Page.Content/>` - `<Page.Tail/>` - `<Page.Section/>` - `<Page.Footer/>` |
| `dataHook` | `string` | No | - | Applies a data-hook HTML attribute that can be used in the tests |
| `backgroundImageUrl` | `string` | No | - | Provides a link to the background image source (URL). Image will be displayed at the top of a page, underneath the \<Page.Header/>. |
| `maxWidth` | `number` | No | - | Sets the maximum width of the page (paddings excluded) |
| `minWidth` | `number` | No | - | Sets the minimum width of the page (paddings excluded). When `mobile` is enabled on `<WixDesignSystemProvider/>`, the default minimum width is removed, but an explicitly provided value is still applied. |
| `height` | `string` | No | - | Sets the height of the page in pixels (px), viewport height (vh), etc. |
| `sidePadding` | `number` | No | - | Sets the side paddings of a page |
| `className` | `string` | No | - | Specifies a CSS class name to be appended to the component’s root element. |
| `gradientClassName` | `string` | No | - | Specifies a CSS class name that defines a gradient background for \<Page.Header/> |
| `scrollableContentRef` | `((ref: HTMLElement \| null) => void)` | No | - | Defines a reference called together with page scrollable content ref after page mount. <br/> **Note** - if you need this ref only for listening to scroll events on the scrollable content then use this prop instead: `scrollProps = {onScrollChanged/onScrollAreaChanged}` |
| `zIndex` | `number` | No | - | Specifies the stack order (z-index) of a page |
| `horizontalScroll` | `boolean` | No | - | Enables page content to scroll horizontally when its width exceed maximum allowed width |
| `scrollProps` | `ScrollableContainerCommonProps` | No | - | Pass properties related to the scrollable content of the page. <br/> **onScrollAreaChanged** - defines a handler function for scroll area changes. Function is triggered when the user scrolls to a different area of the scrollable content. See signature for possible areas: `function({area: {y: AreaY, x: AreaX}, target: HTMLElement}) => void` `AreaY`: top \| middle \| bottom \| none `AreaX`: start \| middle \| end \| none (not implemented yet) <br/> **onScrollAreaChanged** - defines a general handler for scroll changes with throttling (100ms): `function({target: HTMLElement}) => void` |

## BI

### Entity Page Events

| Event                                                                                                     | Description                                          |
|-----------------------------------------------------------------------------------------------------------|------------------------------------------------------|
| [144:150](https://bo.wix.com/data-tools/bi-catalog-app/event/144:150) | Sent on `Cancel` / `Save` click with `isValid` flag. |
| [144:149](https://bo.wix.com/data-tools/bi-catalog-app/event/144:149) | Sent on unsuccessful `Save`.                         |
| [144:141](https://bo.wix.com/data-tools/bi-catalog-app/event/144:141) | Sent when a user clicks on a "try again" CTA.        |
| [144:174](https://bo.wix.com/data-tools/bi-catalog-app/event/144:174) | Sent on navigation with a dirty state.               |



### Component load events
Event   |   Description   |
--------- | --------------- |
[144:110](https://bo.wix.com/data-tools/bi-catalog-app/event/144:110) | Sent when a Wix Patterns component starts loading
[144:111](https://bo.wix.com/data-tools/bi-catalog-app/event/144:111) | Sent when a Wix Patterns component is done loading


#### 🐪 Couldn't find what you need?
* Check our [BI Catalog](https://bo.wix.com/data-tools/bi-catalog-app?viewId=all-items-view&selectedColumns=src%2Cevid%2Cname%2Cowner%2Cproduct%2CuserType+false%2CdateUpdated%2CdateCreated+false%2CcreatedBy+false%2Cstatus&source=%5B%7B%22id%22%3A%22144%22%2C%22name%22%3A%22144+-+Cairo%22%7D%5D)
* Contact us on [#cairo-bi](https://wix.slack.com/archives/C03N53KURH9)


