Skip to content

Button

The Button component provides an interactive button with visual feedback for different states (normal, hover, pressed, disabled). It supports both sprite-based and graphics-based rendering approaches.

Basic Usage

html
<Button 
  text="Click Me" 
  width={150} 
  height={50}
  click={() => console.log("Button clicked!")} 
/>

Properties

PropertyTypeDefaultDescription
textstring""Button text content
disabledbooleanfalseWhether the button is disabled
widthnumber120Button width in pixels
heightnumber40Button height in pixels
xnumber0Button X position
ynumber0Button Y position
alphanumber1Button opacity (0-1)
visiblebooleantrueButton visibility
styleButtonStyle{}Visual styling configuration
cursorstring"pointer"Button cursor
controlsControlsDirective | JoystickControls-Controls instance to automatically apply button events to. Can be accessed via element.directives.controls
controlNamestring-Name of the control to trigger with applyControl when button is clicked
shape'rect' | 'circle' | 'ellipse''rect'Shape of the button background
backgroundElement | ComponentFunction-Custom background component or element (replaces default background if provided)
childrenElement[]-Custom children components for button content (takes priority over text if provided)

Events

EventTypeDescription
click(event: FederatedPointerEvent) => voidFired when button is clicked
hoverEnter(event: FederatedPointerEvent) => voidFired when mouse enters button
hoverLeave(event: FederatedPointerEvent) => voidFired when mouse leaves button
pressDown(event: FederatedPointerEvent) => voidFired when button is pressed down
pressUp(event: FederatedPointerEvent) => voidFired when button is released

Button States

The button automatically manages four visual states:

  • Normal: Default appearance
  • Hover: When mouse is over the button
  • Pressed: When button is being clicked
  • Disabled: When button is not interactive

Styling

Background Colors

html
<Button 
  text="Styled Button"
  style={{
    backgroundColor: {
      normal: "#28a745",
      hover: "#218838",
      pressed: "#1e7e34",
      disabled: "#6c757d"
    }
  }}
/>

Text Styling

html
<Button 
  text="Custom Text"
  style={{
    text: {
      fontSize: 18,
      fontFamily: "Arial",
      color: "#ffffff"
    }
  }}
/>

Border Styling

html
<Button 
  text="Bordered Button"
  style={{
    border: {
      radius: 8,
      width: 2,
      color: "#ffffff"
    }
  }}
/>

Sprite-based Button

For more advanced styling, you can use different sprite textures for each state:

html
<Button 
  text="Play Game"
  style={{
    textures: {
      normal: "/assets/button-normal.png",
      hover: "/assets/button-hover.png",
      pressed: "/assets/button-pressed.png",
      disabled: "/assets/button-disabled.png"
    }
  }}
/>

Controls Integration

The Button can be automatically integrated with the controls system, similar to joystick controls:

html
<Canvas>
  <Button 
    text="Jump" 
    controls={element.directives.controls}
    controlName="jump"
    width={120}
    height={40}
  />
</Canvas>

<script>
  import { signal, mount } from "canvasengine";
  import { Button } from "@canvasengine/core";

  const controls = signal({
    jump: {
      bind: "space",
      keyDown() {
        console.log("Jump!");
        // Jump logic here
      },
    },
  });

  mount((element) => {
    // The button will automatically trigger the "jump" control when clicked
  });
</script>

Button Shapes

You can customize the button shape using the shape property:

Rectangular Button (default)

html
<Button 
  text="Rectangular"
  shape="rect"
  width={150}
  height={50}
/>

Circular Button

html
<Button 
  text="Circular"
  shape="circle"
  width={100}
  height={100}
/>

Elliptical Button

html
<Button 
  text="Elliptical"
  shape="ellipse"
  width={150}
  height={80}
/>

Custom Content

You can provide custom content using children components instead of text:

Button with Icon

html
<Button shape="circle" width={80} height={80}>
  <Sprite image="icon.png" width={50} height={50} />
</Button>

Button with Multiple Elements

html
<Button shape="rect" width={200} height={60}>
  <Sprite image="icon.png" x={20} y={30} width={30} height={30} />
  <Text text="Custom" x={60} y={30} />
</Button>

When children are provided, they take priority over the text property.

Custom Background

You can provide a custom background component:

html
<Button 
  text="Custom Background"
  background={<Sprite image="custom-bg.png" />}
  width={150}
  height={50}
/>

Complete Example

html
<Canvas width={800} height={600}>
  <Button 
    text="Start Game"
    x={350}
    y={250}
    width={200}
    height={80}
    style={{
      backgroundColor: {
        normal: "#007bff",
        hover: "#0056b3",
        pressed: "#004085",
        disabled: "#6c757d"
      },
      border: {
        radius: 10
      },
      text: {
        fontSize: 20,
        fontFamily: "Arial Bold",
        color: "#ffffff"
      }
    }}
    click={() => {
      console.log("Starting game...");
      // Game start logic here
    }}
  />
  
  <Button 
    text="Settings"
    x={350}
    y={350}
    width={200}
    height={60}
    style={{
      backgroundColor: {
        normal: "#6c757d",
        hover: "#5a6268",
        pressed: "#545b62"
      },
      text: {
        fontSize: 16,
        color: "#ffffff"
      }
    }}
    click={() => {
      console.log("Opening settings...");
    }}
  />
  
  <!-- Circular button with controls -->
  <Button 
    text="Jump"
    shape="circle"
    x={100}
    y={100}
    width={80}
    height={80}
    controls={element.directives.controls}
    controlName="jump"
    style={{
      backgroundColor: {
        normal: "#28a745",
        hover: "#218838",
        pressed: "#1e7e34"
      }
    }}
  />
  
  <!-- Button with custom content -->
  <Button 
    shape="circle"
    x={200}
    y={100}
    width={80}
    height={80}
    style={{
      backgroundColor: {
        normal: "#ffc107",
        hover: "#e0a800",
        pressed: "#d39e00"
      }
    }}
  >
    <Sprite image="power-icon.png" width={50} height={50} />
  </Button>
</Canvas>

<script>
  import { signal, mount } from "canvasengine";
  import { Button } from "@canvasengine/core";

  const controls = signal({
    jump: {
      bind: "space",
      keyDown() {
        console.log("Jump action!");
      },
    },
  });

  mount((element) => {
    // Controls are automatically applied when buttons are clicked
  });
</script>

## TypeScript Types

```typescript
interface ButtonStyle {
  backgroundColor?: {
    normal?: string;
    hover?: string;
    pressed?: string;
    disabled?: string;
  };
  border?: {
    color?: string;
    width?: number;
    radius?: number;
  };
  text?: {
    color?: string;
    fontSize?: number;
    fontFamily?: string;
  };
  textures?: {
    normal?: string;
    hover?: string;
    pressed?: string;
    disabled?: string;
  };
}

interface ButtonProps {
  text?: string;
  disabled?: boolean;
  click?: (event: FederatedPointerEvent) => void;
  hoverEnter?: (event: FederatedPointerEvent) => void;
  hoverLeave?: (event: FederatedPointerEvent) => void;
  pressDown?: (event: FederatedPointerEvent) => void;
  pressUp?: (event: FederatedPointerEvent) => void;
  style?: ButtonStyle;
  width?: number;
  height?: number;
  x?: number;
  y?: number;
  alpha?: number;
  visible?: boolean;
  cursor?: string;
  controls?: ControlsDirective | JoystickControls;
  controlName?: string;
  shape?: 'rect' | 'circle' | 'ellipse';
  background?: Element | ComponentFunction;
  children?: Element[];
}