Button

The Button component is a fundamental UI element. It supports multiple visual styles (variants), sizes, and can render as a button or an anchor link.

Available in PHPXUI

This component is part of the PHPXUI library. You can easily install it and explore more pre-built components for your project.

Implementation

Create a new file at src/app/Lib/Components/Button.php.

Note how the CSS classes below reference your theme variables (e.g., bg-primary, bg-destructive) rather than hardcoded hex codes.

<?php

namespace Lib\Components;

use Lib\PHPX\PHPX;

class Button extends PHPX
{
    public ?string $class = '';
    public mixed $children = null;

    public function __construct(array $props = [])
    {
        parent::__construct($props);
    }

    /**
     * Compute standard shadcn/ui classes based on props.
     */
    private function getComputedClasses(): string
    {
        $variant = $this->props['variant'] ?? 'default';
        $size = $this->props['size'] ?? 'default';

        // Base Styles: Focus rings use --ring color, typography uses --foreground
        $baseClass = 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50';

        // Variants: Mapped to globals.css variables
        $variantClasses = [
            'default'     => 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
            'destructive' => 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
            'outline'     => 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
            'secondary'   => 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
            'ghost'       => 'hover:bg-accent hover:text-accent-foreground',
            'link'        => 'text-primary underline-offset-4 hover:underline',
        ];

        // Sizes
        $sizeClasses = [
            'default' => 'h-9 px-4 py-2',
            'sm'      => 'h-8 rounded-md px-3 text-xs',
            'lg'      => 'h-10 rounded-md px-8',
            'icon'    => 'h-9 w-9',
        ];

        return $this->getMergeClasses(
            $baseClass,
            $variantClasses[$variant] ?? $variantClasses['default'],
            $sizeClasses[$size] ?? $sizeClasses['default']
        );
    }

    public function render(): string
    {
        $class = $this->getComputedClasses();
        $attributes = $this->getAttributes([
            'class' => $class,
            'type' => 'button',
        ]);

        return <<<HTML
        <button {$attributes}>
            {$this->children}
        </button>
        HTML;
    }
}

Props

Prop Default Description
variant "default" Style variant. Options: default, secondary, destructive, outline, ghost, link.
size "default" Size of the button. Options: default, sm, lg, icon.
type "button" HTML button type attribute (e.g., submit, reset).

Usage

<?php

use Lib\Components\Button;
use Lib\PPIcons\Mail; // Assuming you have an icon component

?>

<div class="flex flex-col gap-8 p-4">

    <!-- 1. Variants -->
    <div class="flex flex-wrap gap-4 items-center">
        <Button>Default</Button>
        <Button variant="secondary">Secondary</Button>
        <Button variant="destructive">Destructive</Button>
        <Button variant="outline">Outline</Button>
        <Button variant="ghost">Ghost</Button>
        <Button variant="link">Link</Button>
    </div>

    <!-- 2. Sizes -->
    <div class="flex flex-wrap gap-4 items-center">
        <Button size="sm">Small</Button>
        <Button size="default">Default</Button>
        <Button size="lg">Large</Button>
    </div>

    <!-- 3. Icon Button -->
    <div class="flex items-center gap-4">
        <Button variant="outline" size="icon">
            <Mail class="size-4" /> 
        </Button>
        <Button>
            <Mail class="mr-2 size-4" /> Login with Email
        </Button>
    </div>

</div>