CompositionAvailable

Game Action Bar

Game controls in one row, straight on the page: helper tools first and the main action last. Narrow bars put the tools on one row and the action below.

Loading example…

Installation

Add the component and its dependencies from the registry running on your computer.

terminal
npx shadcn@latest add https://brutallab.facilito.dev/r/game-action-bar.json

Usage

Import the component into your project and keep the source code under your control.

tsx
"use client";
import { useState } from "react";
import { ArrowElbowDownLeftIcon, ArrowRightIcon, CheckCircleIcon, CloudCheckIcon, EyeIcon, LightbulbIcon, SpeakerHighIcon } from "@phosphor-icons/react";
import { GameActionBar, GameActionMain, GameActionTool } from "@/components/ui/game-action-bar";
export default function Demo() {
  const [solved, setSolved] = useState(false);
  return (
    <div className="grid w-full gap-6">
      <GameActionBar
        aria-label="Practice actions"
        status={
          solved ? (
            <><CheckCircleIcon weight="fill" aria-hidden="true" /> Correct!</>
          ) : (
            <output title="Draft saved" className="inline-flex">
              <CloudCheckIcon weight="bold" size={20} aria-hidden="true" />
              <span className="sr-only">Draft saved</span>
            </output>
          )
        }
      >
        <GameActionTool icon={<SpeakerHighIcon weight="bold" />} keys={["Ctrl", "'"]} aria-label="Listen again">Listen</GameActionTool>
        <GameActionTool icon={<LightbulbIcon weight="bold" />} keys={["Ctrl", "Shift", ";"]} aria-label="Hint for this word" disabled={solved}>Hint</GameActionTool>
        <GameActionTool icon={<EyeIcon weight="bold" />} keys={["Ctrl", ";"]} aria-label="Show answer">Answer</GameActionTool>
        <GameActionMain
          icon={solved ? <ArrowRightIcon weight="bold" /> : <ArrowElbowDownLeftIcon weight="bold" />}
          onClick={() => setSolved(!solved)}
        >
          {solved ? "Next" : "Check"}
        </GameActionMain>
      </GameActionBar>
      <div className="w-full max-w-sm">
        <GameActionBar aria-label="Practice actions on a phone">
          <GameActionTool icon={<SpeakerHighIcon weight="bold" />} aria-label="Listen again">Listen</GameActionTool>
          <GameActionTool icon={<LightbulbIcon weight="bold" />} aria-label="Hint for this word">Hint</GameActionTool>
          <GameActionTool icon={<EyeIcon weight="bold" />} aria-label="Show answer">Answer</GameActionTool>
          <GameActionMain disabled icon={<ArrowElbowDownLeftIcon weight="bold" />}>Check</GameActionMain>
        </GameActionBar>
      </div>
    </div>
  );
}

States & interaction

Appearance, behavior and keyboard checks.

  • The composition inherits its controls’ states. Test empty, content, loading and error cases where the application needs them.
  • Examples on this page are runnable; the displayed code uses the same components. Business logic belongs to the consumer.
  • Test the example with Tab and Shift+Tab. Focus must stay visible in both themes.

API Reference

BrutalLab-specific properties. Native attributes are supported as well.

PropTypeDefaultDescription
ReactNode—Short status, such as a draft icon with hidden text, shown when the bar is wide and kept for assistive technology otherwise.
ReactNode / string[]Required / —Helper action; keys appear on wide bars and are decorative, so also set aria-keyshortcuts.
ReactNode—Main action with the game-number label; disabled it lies flat and muted.

Accessibility

Rules that should remain intact when adapting the component to a product.

The bar is a labelled group; give each tool and the main action an accessible name that contains its visible label.

Key hints are hidden from assistive technology; declare shortcuts with aria-keyshortcuts.