import { usePrimaryButton } from '@coinbase/onchainkit/minikit';
import { useState } from 'react';

enum GameState {
  RUNNING = 'running',
  PAUSED = 'paused',
  STOPPED = 'stopped'
}

export default function GameComponent() {
  const [gameState, setGameState] = useState(GameState.STOPPED);

  // Configure primary button based on game state
  usePrimaryButton(
    { 
      text: gameState === GameState.RUNNING ? 'PAUSE GAME' : 'START GAME' 
    },
    () => {
      setGameState(
        gameState === GameState.RUNNING 
          ? GameState.PAUSED 
          : GameState.RUNNING
      );
    }
  );

  return (
    <div className="game-container">
      <h2>Game Status: {gameState}</h2>
      {/* Game content */}
    </div>
  );
}
Defined in @coinbase/onchainkit
Configures a persistent primary button that appears at the bottom of the Mini App frame. Perfect for global actions that should always be accessible.

Parameters

options
SetPrimaryButtonOptions
required
Configuration object for the primary button appearance and behavior.
callback
() => void
required
Function to execute when the primary button is clicked.
import { usePrimaryButton } from '@coinbase/onchainkit/minikit';
import { useState } from 'react';

enum GameState {
  RUNNING = 'running',
  PAUSED = 'paused',
  STOPPED = 'stopped'
}

export default function GameComponent() {
  const [gameState, setGameState] = useState(GameState.STOPPED);

  // Configure primary button based on game state
  usePrimaryButton(
    { 
      text: gameState === GameState.RUNNING ? 'PAUSE GAME' : 'START GAME' 
    },
    () => {
      setGameState(
        gameState === GameState.RUNNING 
          ? GameState.PAUSED 
          : GameState.RUNNING
      );
    }
  );

  return (
    <div className="game-container">
      <h2>Game Status: {gameState}</h2>
      {/* Game content */}
    </div>
  );
}

Usage Patterns

Global State Management

The primary button is perfect for actions that affect the entire app:
components/GlobalStateExamples.tsx
// Game controls
usePrimaryButton(
  { text: isPlaying ? 'Pause' : 'Play' },
  toggleGameState
);

// Modal controls  
usePrimaryButton(
  { text: 'Close' },
  closeModal
);

Form Submission

Use for primary form actions:
components/FormSubmit.tsx
usePrimaryButton(
  { text: isValid ? 'Submit' : 'Complete Required Fields' },
  handleFormSubmission
);

Multi-Step Flows

Navigate through complex workflows:
components/MultiStepFlow.tsx
usePrimaryButton(
  { text: getStepButtonText(currentStep) },
  () => advanceToNextStep()
);

Best Practices

Button Text Guidelines

  • Keep it action-oriented: “Start Game”, “Submit Order”, “Continue”
  • Be specific: “Save Changes” vs generic “Submit”
  • Indicate state: “Pause Game” when playing, “Resume Game” when paused
  • Stay concise: Aim for 1-3 words when possible

Layout Considerations

  • The primary button appears at the bottom of the frame
  • Don’t duplicate actions: Avoid having the same action as an in-content button
  • Consider mobile: Button is optimized for thumb accessibility
  • Test across clients: Button appearance may vary between Farcaster clients

Performance Tips

  • Memoize callbacks: Use useCallback for complex button handlers
  • Avoid frequent changes: Don’t update button text on every render
  • Batch state updates: Update button config and app state together
components/HandlePrimaryAction.tsx
import { useCallback } from 'react';

const handlePrimaryAction = useCallback(() => {
  // Expensive operation
  performComplexAction();
}, [dependencies]);

usePrimaryButton(
  { text: 'Process Data' },
  handlePrimaryAction
);
The primary button is persistent across your entire Mini App session. Only use usePrimaryButton once per component tree to avoid conflicts.
The primary button provides a native, accessible way to surface your most important action. It’s especially effective for games, forms, and multi-step workflows where users need consistent access to the next action.