# ctx.element

Экземпляр `ElementProxy`, указывающий на DOM-контейнер песочницы (sandbox), который служит целью рендеринга по умолчанию для `ctx.render()`. Он доступен в сценариях, где существует контейнер рендеринга, таких как `JSBlock`, `JSField`, `JSItem` и `JSColumn`.

## Применимые сценарии

| Сценарий | Описание |
|------|------|
| **JSBlock** | DOM-контейнер блока, используемый для рендеринга пользовательского содержимого блока. |
| **JSField / JSItem / FormJSFieldItem** | Контейнер рендеринга для поля или элемента формы (обычно `<span>`). |
| **JSColumn** | DOM-контейнер ячейки таблицы, используемый для рендеринга пользовательского содержимого колонки. |

> Примечание: `ctx.element` доступен только в контекстах RunJS, имеющих контейнер рендеринга. В контекстах без UI (например, в чисто серверной логике) он может быть `undefined`. Перед использованием рекомендуется проверять значение на наличие.

## Определение типа

```typescript
element: ElementProxy | undefined;

// ElementProxy — это прокси для исходного HTMLElement, предоставляющий безопасный API
class ElementProxy {
  __el: HTMLElement;  // Внутренний необработанный DOM-элемент (доступен только в особых случаях)
  innerHTML: string;  // Очищается через DOMPurify при чтении/записи
  outerHTML: string; // Аналогично вышеуказанному
  appendChild(child: HTMLElement | string): void;
  // Другие методы HTMLElement пробрасываются напрямую (прямое использование не рекомендуется)
}
```

## Требования безопасности

**Рекомендация: Весь рендеринг должен выполняться через `ctx.render()`.** Избегайте прямого использования DOM API через `ctx.element` (например, `innerHTML`, `appendChild`, `querySelector` и т. д.).

### Почему рекомендуется ctx.render()

| Преимущество | Описание |
|------|------|
| **Безопасность** | Централизованный контроль безопасности для предотвращения XSS и некорректных операций с DOM. |
| **Поддержка React** | Полная поддержка JSX, React-компонентов и жизненных циклов. |
| **Наследование контекста** | Автоматическое наследование `ConfigProvider` приложения, тем и т. д. |
| **Обработка конфликтов** | Автоматическое управление созданием/размонтированием корня React во избежание конфликтов нескольких экземпляров. |

### ❌ Не рекомендуется: Прямое манипулирование ctx.element

```ts
// ❌ Не рекомендуется: прямое использование API ctx.element
ctx.element.innerHTML = '<div>Содержимое</div>';
ctx.element.appendChild(node);
ctx.element.querySelector('.class');
```

> `ctx.element.innerHTML` устарел. Пожалуйста, используйте `ctx.render()` вместо него.

### ✅ Рекомендуется: Использование ctx.render()

```ts
// ✅ Рендеринг React-компонента
const { Button, Card } = ctx.libs.antd;
ctx.render(
  <Card title={ctx.t('Добро пожаловать')}>
    <Button type="primary">Нажать</Button>
  </Card>
);

// ✅ Рендеринг HTML-строки
ctx.render('<div style="padding:16px;">' + ctx.t('Содержимое') + '</div>');

// ✅ Рендеринг DOM-узла
const div = document.createElement('div');
div.textContent = ctx.t('Привет');
ctx.render(div);
```

## Особый случай: В качестве якоря для Popover

Когда вам нужно открыть Popover, используя текущий элемент в качестве якоря, вы можете обратиться к `ctx.element?.__el`, чтобы получить необработанный DOM в качестве `target`:

```ts
// ctx.viewer.popover требует необработанный DOM в качестве target
await ctx.viewer.popover({
  target: ctx.element?.__el,
  content: <div>Всплывающее содержимое</div>,
});
```

> Используйте `__el` только в сценариях типа «использование текущего контейнера в качестве якоря»; в остальных случаях не манипулируйте DOM напрямую.

## Связь с ctx.render

- Если `ctx.render(vnode)` вызывается без аргумента `container`, по умолчанию рендеринг происходит в контейнер `ctx.element`.
- Если `ctx.element` отсутствует и `container` не передан, будет выдана ошибка.
- Вы можете явно указать контейнер: `ctx.render(vnode, customContainer)`.

## Примечания

- `ctx.element` предназначен для внутреннего использования методом `ctx.render()`. Прямой доступ или изменение его свойств/методов не рекомендуется.
- В контекстах без контейнера рендеринга `ctx.element` будет равен `undefined`. Перед вызовом `ctx.render()` убедитесь, что контейнер доступен, или передайте `container` вручную.
- Хотя `innerHTML`/`outerHTML` в `ElementProxy` очищаются с помощью DOMPurify, все же рекомендуется использовать `ctx.render()` для унифицированного управления рендерингом.

## Связанные разделы

- [ctx.render](./render.md): Рендеринг содержимого в контейнер
- [ctx.view](./view.md): Контроллер текущего представления
- [ctx.modal](./modal.md): Быстрый API для модальных окон