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

# Interactable

> Wrap custom widgets to get the same disabled opacity and press scale as NeoButton and other Neo controls.

Primary use: when you build your own widgets and want the same consistent disabled effect and scale-down on press as widgets like [`NeoButton`](/widgets/buttons/button), wrap them with `NeoInteractable`.

## Examples

<CodeGroup>
  ```dart With Builder lines theme={null}
  NeoInteractable(
    onPressed: () {},
    builder: (context, state) {
      return ColoredBox(
        color: state.isActive
            ? theme.colors.fillSecondary
            : theme.colors.transparent,
        child: Text(
          "Tap me",
          style: theme.textStyles.body1.copyWith(
            color: theme.colors.fgPrimary,
          ),
        ),
      );
    },
  ),
  ```

  ```dart With Child lines theme={null}
  NeoInteractable(
    onPressed: () {},
    child: Text(
      "Static content",
      style: theme.textStyles.body1,
    ),
  ),
  ```

  ```dart Disabled lines theme={null}
  NeoInteractable(
    isEnabled: false,
    onPressed: () {},
    child: Text("Unavailable"),
  ),
  ```
</CodeGroup>

Provide exactly one of `child` or `builder`.

## Properties

### Required

Provide either `child` or `builder` (exactly one).

### Content

<ParamField path="child" type="Widget?">
  Static child when interaction-driven rebuilds are not needed. Mutually exclusive with `builder`.
</ParamField>

<ParamField path="builder" type="NeoInteractableBuilder?">
  Builds content from the current interaction snapshot (`isEnabled`, `isHovered`, `isPressed`, `isActive`). Mutually exclusive with `child`.
</ParamField>

### Layout

<ParamField path="behavior" type="HitTestBehavior" default="HitTestBehavior.deferToChild">
  Hit-test behavior passed to the underlying gesture detector when press handlers are present.
</ParamField>

### Styling

<ParamField path="enableScale" type="bool" default="true">
  Whether the content scales slightly while pressed.
</ParamField>

<ParamField path="pressedScale" type="double" default="0.97">
  Scale factor applied while pressed when `enableScale` is `true`.
</ParamField>

<ParamField path="cursor" type="MouseCursor?">
  Mouse cursor override. When null, uses click when enabled and forbidden when disabled.
</ParamField>

### State

<ParamField path="onPressed" type="VoidCallback?">
  Called on tap when enabled.
</ParamField>

<ParamField path="isEnabled" type="bool" default="true">
  When `false`, dims via Neo's disabled opacity, clears hover/press, and ignores input.
</ParamField>

<ParamField path="onPressStart" type="VoidCallback?">
  Called when a press begins.
</ParamField>

<ParamField path="onPressEnd" type="VoidCallback?">
  Called when a press ends or is cancelled.
</ParamField>

<ParamField path="onHoverEnter" type="VoidCallback?">
  Called when the pointer enters the interactable region.
</ParamField>

<ParamField path="onHoverExit" type="VoidCallback?">
  Called when the pointer leaves the interactable region.
</ParamField>

<ParamField path="onHorizontalDragStart" type="GestureDragStartCallback?">
  Optional horizontal drag start handler.
</ParamField>

<ParamField path="onHorizontalDragUpdate" type="GestureDragUpdateCallback?">
  Optional horizontal drag update handler.
</ParamField>

<ParamField path="minPressDuration" type="Duration?">
  Overrides theme `durations.short` for the minimum time pressed stays true on quick taps.
</ParamField>

## Builder state

When you need custom hover/press visuals, use `builder`. The snapshot includes:

* `isEnabled` / `isHovered` / `isPressed`
* `isActive` — `true` when enabled and either hovered or pressed (same feedback on touch and desktop)

## Best Practices

* Prefer `child` when you only need disabled opacity and press scale.
* Use `builder` + `state.isActive` when your custom widget also needs hover/press color changes.
* Keep the wrapper thin — compose layout and styling in the child/builder, leave gestures to `NeoInteractable`.

## Integration Notes

* Neo widgets such as [`NeoButton`](/widgets/buttons/button) use this shell internally — wrapping your own widgets keeps interaction consistent with the rest of Neo.
* Press scale duration follows `theme.durations.short`.
