> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-pt/scenes-sdk7/ui-2d/ui_button_events.md).

# Eventos de Button da UI

Lide com eventos de button em UI entities.

Para criar um botão na sua UI, crie um `Button` elemento de UI com as seguintes propriedades:

* `value`: Uma string com o texto a exibir no botão.
* `onMouseDown`: Uma função callback que é executada toda vez que o usuário pressiona o botão do ponteiro na Entity.
* `uiTransform`: Propriedades de posicionamento do elemento de UI.

O exemplo a seguir mostra como criar um botão de UI clicável.

***Arquivo ui.tsx:***

```tsx
import { Button } from '@dcl/sdk/react-ecs'

export const uiMenu = () => (
	<Button
		value="Clique em mim"
		uiTransform={{ width: 100, height: 100 }}
		onMouseDown={() => {
			console.log('Clicado na UI')
		}}
	/>
)
```

***Arquivo index.ts:***

```ts
import { ReactEcsRenderer } from '@dcl/sdk/react-ecs'
import { uiMenu } from './ui'

export function main() {
    ReactEcsRenderer.setUiRenderer(uiMenu)
}
```

{% hint style="warning" %}
**📔 Nota**: Todos os snippets a seguir nesta página assumem que você tem uma `.ts` semelhante à acima, executando a função `ReactEcsRenderer.setUiRenderer()` .
{% endhint %}

Você também pode escrever a função executada pelo clique fora da definição da UI e referenciá-la pelo nome. Isso ajuda a manter o código de UI mais legível e também é útil se vários elementos de UI clicáveis precisarem chamar a mesma função.

```tsx
import { Button } from '@dcl/sdk/react-ecs'

function handleClick() {
	// Fazer algo onClick
	console.log('Clicado na UI')
}
export const uiMenu = () => (
	<Button
		value="Clique em mim"
		uiTransform={{ width: 100 }}
		onMouseDown={handleClick}
	/>
)
```

Os seguintes campos podem ser adicionados a um `Button` elemento de UI:

* `onMouseDown`: Uma função callback que é executada toda vez que o usuário pressiona o botão do ponteiro na Entity.
* `onMouseUp`: Uma função callback que é executada toda vez que o botão do ponteiro é solto enquanto aponta para a Entity.
* `onMouseEnter`: Uma função callback que é executada toda vez que o ponteiro começa a passar sobre o botão.
* `onMouseLeave`: Uma função callback que é executada toda vez que o ponteiro para de passar sobre o botão.
* `color`: Cor do texto no botão.
* `font`: Fonte do texto no botão.
* `textAlign`: Alinhamento do texto dentro do botão
* `uiTransform`: Propriedades de posicionamento do elemento de UI.
* `uiBackground`: Define a cor ou a textura do elemento de UI.
* `variant`: Use esta propriedade para definir o estilo do botão como um dos padrões. `primary` e `secondary` estão disponíveis.
* `disabled`: Booleano para desativar um botão. Quando `disabled` está definido como *true*, as `onMouseDown` e `onMouseUp` ações deixam de ser chamadas, e o botão para de anunciar qualquer interação de ponteiro. O botão também é desenhado "acinzentado": tanto o texto quanto o fundo são renderizados com metade do seu `alpha` valor. Esta é apenas uma mudança visual. Os valores de `Color4` que sua cena passa nunca são modificados, então você pode reutilizar com segurança um objeto de paleta compartilhado entre muitos elementos.

## Estilo do Button

Defina variant como `primary` ou `secondary` para aproveitar as opções de estilo padrão dos botões. `primary` torna o seu botão vermelho com texto branco, `secondary` torna o seu botão branco com texto vermelho.

```tsx
import { UiEntity, Button, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
	<UiEntity
		uiTransform={{
			width: 500,
			height: 230,
			margin: '16px 0 8px 270px',
			padding: 4,
			alignSelf: 'center',
		}}
		uiBackground={{ color: Color4.Gray() }}
	>
		<Button
			value="Clique em mim"
			variant="primary"
			uiTransform={{ width: 80, height: 20, margin: 4 }}
			onMouseDown={() => {
				console.log('Clicado na UI')
			}}
		/>
		<Button
			value="Clique em mim"
			variant="secondary"
			uiTransform={{ width: 80, height: 20, margin: 4 }}
			onMouseDown={() => {
				console.log('Clicado na UI')
			}}
		/>
	</UiEntity>
)
```

Você também está livre para usar todas as propriedades do background livremente. Você também pode definir um variant e então sobrescrever algumas de suas propriedades. Este exemplo usa o `primary` variant, mas substitui a cor para verde:

```tsx
import { Button } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

export const uiMenu = () => (
	<Button
		value="Meu Botão!"
		variant="primary"
		uiTransform={{ width: 100, height: 100 }}
		onMouseDown={() => {
			console.log('Clicado no Meu Botão!')
		}}
		uiBackground={{
			color: Color4.Green(),
		}}
	/>
)
```

## Botões alternáveis

Um caso de uso comum é fazer um botão alternar entre dois estados, como um interruptor. O exemplo abaixo alterna entre duas cores cada vez que o botão é pressionado:

```tsx
import { Button } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

let buttonEnabled = false

export const uiMenu = () => (
	<Button
		value="Meu Botão"
		variant="primary"
		uiTransform={{ width: 100, height: 100 }}
		onMouseDown={() => {
			console.log('Clicado no Meu Botão!')
			buttonEnabled = !buttonEnabled
			if (buttonEnabled) {
				// fazer algo
			} else {
				// fazer outra coisa
			}
		}}
		uiBackground={{
			color: buttonEnabled ? Color4.Green() : Color4.Red(),
		}}
	/>
)
```

Observe que no exemplo acima, a cor depende de uma `buttonEnabled` variável. Sempre que o valor dessa variável muda, isso afeta imediatamente a cor do background.

## Feedback de Hover

Outro caso de uso comum é exibir algum tipo de dica visual ao passar o cursor sobre um botão, para esclarecer que ele é interativo, ou até mesmo exibir uma dica de hover explicando o que este botão faz. Use os `onMouseEnter` e `onMouseLeave` callbacks para detectar quando o cursor do jogador está sobre o botão e reagir de acordo.

```tsx
import { Button } from '@dcl/sdk/react-ecs'

let buttonEnabled = false

export const uiMenu = () => (
	<Button
		value="Meu Botão"
		uiTransform={{ width: 100, height: 100 }}
		onMouseDown={() => {
			// função do botão
		}}
		onMouseEnter={() => {
			// mostrar dica
		}}
		onMouseLeave={() => {
			// esconder dica
		}}
	/>
)
```

## Tornando outros elementos clicáveis

Qualquer elemento na UI pode ser tornado clicável adicionando uma `onMouseDown` propriedade a ele; ela funciona de forma idêntica a um botão. O exemplo a seguir adiciona `onMouseDown` propriedades a imagens de background e texto.

```tsx
import { UiEntity, Label, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'
import { engine, Transform } from '@dcl/sdk/ecs'

export const uiMenu = () => (
	<UiEntity
		onMouseDown={() => {
			console.log('Background clicado!')
		}}
		uiTransform={{
			width: 400,
			height: 230,
		}}
		uiBackground={{ color: Color4.create(0.5, 0.8, 0.1, 0.6) }}
	>
		<Label
			onMouseDown={() => {
				console.log('Label clicado!')
			}}
			value={`Jogador: ${getPlayerPosition()}`}

			fontSize={18}
			uiTransform={{ width: '100%', height: 30 }}
		/>
	</UiEntity>
)

function getPlayerPosition() {
	const playerPosition = Transform.getOrNull(engine.PlayerEntity)
	if (!playerPosition) return 'desconhecido'
	const { x, y, z } = playerPosition.position
	return `{x: ${x.toFixed(2)}, y: ${y.toFixed(2)}, z: ${z.toFixed(2)} }`
}
```

## Bloqueio de ponteiro

Todas as UI entities são bloqueadoras de ponteiro por padrão, o que significa que os cliques dos jogadores passarão por elas e interagirão com objetos no espaço 3D atrás delas. Se uma Entity tiver um `onMouseDown` callback, então ela se torna bloqueadora de ponteiro, de modo que os cliques dos jogadores não afetam o que está atrás dessa UI entity.

Você pode alterar esse comportamento padrão mudando o valor da `pointerFilter` propriedade no `uiTransform` componente em qualquer UI entity. Por exemplo, para definir uma entity que não tem `onMouseDown` como bloqueadora de ponteiro.

Os valores suportados para `pointerFilter` são:

* `block`: O elemento de UI é bloqueador de ponteiro; os jogadores não podem clicar em nada atrás deste elemento de UI.
* `none`: O elemento de UI não é bloqueador de ponteiro. O elemento não é clicável e tudo atrás dele pode ser clicado.

Abaixo há uma UI simples que não tem um `onMouseDown`, mas que substitui o comportamento padrão de não bloquear o ponteiro ao definir `pointerFilter` como `block`.

```tsx
import { UiEntity, ReactEcs } from '@dcl/sdk/react-ecs'
import { Color4 } from '@dcl/sdk/math'

// desenhar UI
export const uiMenu = () => (
	<UiEntity
		uiTransform={{
			width: '100%',
			height: '100px',
			pointerFilter: `block`,
		}}
		uiText={{ value: `Este elemento é bloqueador de ponteiro`, fontSize: 40 }}
		uiBackground={{ color: Color4.create(0.5, 0.8, 0.1, 0.6) }}
	/>
)
```

### O bloqueio segue a caixa de layout, não os pixels visíveis

Um elemento bloqueador captura cliques em todo o seu **retângulo inteiro**, exista ou não algo desenhado ali. Um background totalmente transparente não faz diferença.

{% hint style="danger" %}
**Aviso:** Nunca coloque um handler de ponteiro ou `pointerFilter: 'block'` em um wrapper de tela inteira dimensionado `100%` por `100%`.

Seu retângulo é a tela inteira, então um único `onMouseDown` handler perdido na raiz do layout torna todos os outros elementos de UI e tudo no mundo 3D não clicáveis. A UI ainda parece perfeitamente correta, porque o panel que você vê cobre apenas uma pequena parte da tela, o que torna isso muito difícil de perceber.
{% endhint %}

Anexe os handlers ao menor elemento que precisar deles: o panel, o botão, a linha. Wrappers de layout permanecem sem handlers.

Há dois casos em que um elemento bloqueador de tela inteira é a coisa certa, e ambos são intencionais:

* Um **fundo modal**, que serve para engolir cliques e que você só renderiza enquanto o modal está aberto.
* Um **capturador de soltura de drag**, que só existe enquanto um drag está em andamento. Veja [interações de drag](#drag-interactions) abaixo.

Se clicar parar de funcionar em qualquer lugar da sua cena, esta é a primeira coisa a verificar.

## interações de drag

Os handlers de ponteiro de UI (`onMouseDown`, `onMouseUp`, `onMouseEnter`, `onMouseLeave`) não recebem parâmetros. Eles disparam como simples `() => void` callbacks sem dados de posição ou coordenadas. Não há `onMouseDrag` ou `onMouseMove` handler no sistema de UI.

Para construir UI baseada em drag (sliders, barras de scrub, alças de drag), use `PrimaryPointerInfo.screenDelta` de `@dcl/sdk/ecs`. Isso fornece o movimento do mouse em pixels desde o último frame, atualizado a cada frame independentemente de onde o cursor esteja.

O padrão funciona da seguinte forma:

1. `onMouseDown` no alvo do drag inicia o drag e registra o valor inicial.
2. Um system lê `screenDelta` a cada frame e o acumula no valor enquanto o drag está ativo.
3. Uma sobreposição invisível em tela inteira com `pointerFilter: 'block'` captura a liberação do mouse, então soltar fora do alvo estreito ainda encerra o drag.

```ts
import { engine, PrimaryPointerInfo, UiCanvasInformation } from '@dcl/sdk/ecs'

let dragging = false
let sliderValue = 0.5

// Chame este system a cada frame para acumular o movimento do drag
engine.addSystem(() => {
	if (!dragging) return

	const delta = PrimaryPointerInfo.getOrNull(engine.RootEntity)?.screenDelta
	if (!delta || delta.x === 0) return

	// Converter pixels da tela para uma faixa de 0–1
	// Dividir pelo fator de escala da UI para que a velocidade do drag corresponda ao cursor
	const canvas = UiCanvasInformation.getOrNull(engine.RootEntity)
	const scale = canvas ? Math.min(canvas.width / 1920, canvas.height / 1080) : 1
	const trackWidth = 200 // largura virtual em px da trilha do slider

	sliderValue = Math.max(0, Math.min(1, sliderValue + delta.x / scale / trackWidth))
})
```

{% hint style="warning" %}
**Nota:** Em mobile, `screenDelta` screenDelta sempre retorna 0 (não existe cursor de movimento livre). Para sliders compatíveis com mobile, adicione botões stepper (`-` / `+`) ao lado da trilha de drag. Use [`isMobile()`](/creator/content-creator-pt/criar-para-dispositivos-moveis/desenvolver/detect-platform.md) de `de` @dcl/sdk/platform
{% endhint %}

{% hint style="info" %}
**para ramificar sua UI.** Dica: `screenDelta` Sempre divida pelo fator de escala da UI, ou o drag vai passar demais ou de menos em telas cuja resolução seja diferente do seu tamanho virtual.
{% endhint %}


---

# 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, and the optional `goal` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-pt/scenes-sdk7/ui-2d/ui_button_events.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
