> ## Documentation Index
> Fetch the complete documentation index at: https://chameleon.voidlogger.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Commands and components

> Register slash commands, classic message components, and interaction handlers using the framework’s recommended public APIs.

## Register a command

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { command } from '@impulsedev/chameleon'

const ping = command('ping', 'Return latency information')
  .execute(async (ctx) => {
    await ctx.reply({
      content: `Gateway: ${client.gateway.ms}ms`,
      ephemeral: true
    })
  })

client.commands.register(ping)
```

## Register a button handler

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { defineButton } from '@impulsedev/chameleon'

client.components.register(
  defineButton({
    customId: 'open_modal',
    style: 'primary',
    label: 'Open modal',
    execute: async (ctx) => {
      await ctx.reply({ content: 'clicked', ephemeral: true })
    }
  })
)
```

If you only need the visual button definition for a message payload, use `Button.*`:

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { Button } from '@impulsedev/chameleon'

const openModalButton = Button.primary('open_modal', 'Open modal')
```

## Send classic V1 components

```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
import { ActionRow, Button } from '@impulsedev/chameleon'

await client.messages.send(channelId, {
  content: 'Classic components',
  components: [
    ActionRow.of(
      Button.primary('open_modal', 'Open modal')
    )
  ]
})
```

## Notes

* Classic message components are row-based because that is how Discord models V1 component payloads.
* The same `Button.*` helpers also work inside Components V2 accessory flows.
* Use `defineButton(...)` or `Button.of(...)` when the component also needs an `execute` handler.
