> ## Documentation Index
> Fetch the complete documentation index at: https://base-a060aa97-danc-alpha-docs.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# usePrimaryButton

> Configure and handle the persistent primary button

Defined in [@coinbase/onchainkit](https://github.com/coinbase/onchainkit)

<Info>
  Configures a persistent primary button that appears at the bottom of the Mini App frame. Perfect for global actions that should always be accessible.
</Info>

## Parameters

<ParamField body="options" type="SetPrimaryButtonOptions" required>
  Configuration object for the primary button appearance and behavior.

  <Expandable title="SetPrimaryButtonOptions properties">
    <ParamField body="text" type="string" required>
      The text to display on the primary button.
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="callback" type="() => void" required>
  Function to execute when the primary button is clicked.
</ParamField>

<RequestExample>
  ```tsx components/GameComponent.tsx
  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>
    );
  }
  ```

  ```tsx components/FormComponent.tsx
  import { usePrimaryButton } from '@coinbase/onchainkit/minikit';
  import { useState } from 'react';

  export default function FormComponent() {
    const [formData, setFormData] = useState({ name: '', email: '' });
    const [isValid, setIsValid] = useState(false);

    // Dynamic button text and action based on form state
    usePrimaryButton(
      { 
        text: isValid ? 'Submit Form' : 'Complete Form First' 
      },
      () => {
        if (isValid) {
          handleSubmit();
        } else {
          // Focus first empty field
          focusFirstEmptyField();
        }
      }
    );

    const handleSubmit = async () => {
      await fetch('/api/submit', {
        method: 'POST',
        body: JSON.stringify(formData)
      });
    };

    return (
      <form>
        <input 
          value={formData.name}
          onChange={(e) => {
            setFormData({ ...formData, name: e.target.value });
            setIsValid(e.target.value && formData.email);
          }}
          placeholder="Name"
        />
        <input 
          value={formData.email}
          onChange={(e) => {
            setFormData({ ...formData, email: e.target.value });
            setIsValid(formData.name && e.target.value);
          }}
          placeholder="Email"
        />
      </form>
    );
  }
  ```

  ```tsx components/CheckoutComponent.tsx
  import { usePrimaryButton } from '@coinbase/onchainkit/minikit';
  import { useState } from 'react';

  export default function CheckoutComponent() {
    const [step, setStep] = useState('cart'); // cart, shipping, payment, complete

    const getButtonConfig = () => {
      switch (step) {
        case 'cart':
          return { text: 'Proceed to Shipping', action: () => setStep('shipping') };
        case 'shipping':
          return { text: 'Proceed to Payment', action: () => setStep('payment') };
        case 'payment':
          return { text: 'Complete Purchase', action: () => processPurchase() };
        case 'complete':
          return { text: 'Continue Shopping', action: () => setStep('cart') };
        default:
          return { text: 'Next', action: () => {} };
      }
    };

    const config = getButtonConfig();

    usePrimaryButton(
      { text: config.text },
      config.action
    );

    const processPurchase = async () => {
      // Handle purchase logic
      setStep('complete');
    };

    return (
      <div className="checkout-flow">
        <h2>Step: {step}</h2>
        {/* Step-specific content */}
      </div>
    );
  }
  ```
</RequestExample>

## Usage Patterns

### Global State Management

The primary button is perfect for actions that affect the entire app:

```tsx components/GlobalStateExamples.tsx
// Game controls
usePrimaryButton(
  { text: isPlaying ? 'Pause' : 'Play' },
  toggleGameState
);

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

### Form Submission

Use for primary form actions:

```tsx components/FormSubmit.tsx
usePrimaryButton(
  { text: isValid ? 'Submit' : 'Complete Required Fields' },
  handleFormSubmission
);
```

### Multi-Step Flows

Navigate through complex workflows:

```tsx 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

```tsx components/HandlePrimaryAction.tsx
import { useCallback } from 'react';

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

usePrimaryButton(
  { text: 'Process Data' },
  handlePrimaryAction
);
```

<Warning>
  The primary button is persistent across your entire Mini App session. Only use `usePrimaryButton` once per component tree to avoid conflicts.
</Warning>

<Info>
  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.
</Info>
