Background
Foreground
Primary
Primary FG
A clickable element for triggering actions or submitting forms.
---import { ArrowUpIcon } from '@lucide/astro';
import { Button } from '@bejamas/ui/components/button';---
<div class="flex flex-wrap items-center gap-2 md:flex-row"> <Button>Button</Button> <Button variant="outline" size="icon" aria-label="Submit"> <ArrowUpIcon /> </Button></div> bunx bejamas add button npx bejamas add button pnpm dlx bejamas add button yarn dlx bejamas add button---/** * @component Button * @title Button * @description A clickable element for triggering actions or submitting forms. * @figmaUrl https://www.figma.com/design/koxai7zw5vIuBzuVxe5T2l/bejamas-ui?node-id=2609-10438&t=YFStJ3V8fXEO8QD8-4 * * @preview * * <div class="flex flex-wrap items-center gap-2 md:flex-row"> * <Button>Button</Button> * <Button variant="outline" size="icon" aria-label="Submit"> * <ArrowUpIcon /> * </Button> * </div> * * @usage * * ```astro * --- * import { Button } from '@bejamas/ui/components/button'; * --- * * <Button>Click me</Button> * ``` * * ## Link * * You can use the `as` prop to render the component as an anchor. * * ```astro * --- * import { Button } from '@bejamas/ui/components/button'; * --- * * <Button as="a" href="https://bejamas.com">Click me</Button> * ``` * * @examples * * ### Variants * * <div class="flex flex-col items-start gap-8 sm:flex-row"> * <Button variant="default">Default</Button> * <Button variant="secondary">Secondary</Button> * <Button variant="outline">Outline</Button> * <Button variant="ghost">Ghost</Button> * <Button variant="destructive">Destructive</Button> * </div> * * ### Sizes * * <div class="flex flex-col items-start gap-8 sm:flex-row"> * <div class="flex items-start gap-2"> * <Button size="sm" variant="outline"> * Small * </Button> * <Button size="icon-sm" aria-label="Submit" variant="outline"> * <ArrowUpRightIcon /> * </Button> * </div> * <div class="flex items-start gap-2"> * <Button variant="outline">Default</Button> * <Button size="icon" aria-label="Submit" variant="outline"> * <ArrowUpRightIcon /> * </Button> * </div> * <div class="flex items-start gap-2"> * <Button variant="outline" size="lg"> * Large * </Button> * <Button size="icon-lg" aria-label="Submit" variant="outline"> * <ArrowUpRightIcon /> * </Button> * </div> * </div> * * ### With badge * * <Button variant="default"> * Click me * <Badge variant="secondary">Value</Badge> * </Button> * * ### Destructive * * <Button variant="destructive">Click me</Button> * * ### Outline * * <Button variant="outline">Click me</Button> * * ### Secondary * * <Button variant="secondary">Click me</Button> * * ### Ghost * * <Button variant="ghost">Click me</Button> * * ### Link * * <Button variant="link">Click me</Button> * * ### Default * * <Button>Click me</Button> * */
import type { HTMLAttributes } from "astro/types";import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@bejamas/ui/lib/utils";
const buttonVariants = cva( "inline-flex ease-out duration-150 border-border items-center justify-center gap-2 whitespace-nowrap rounded-lg font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive active:scale-98", { variants: { variant: { default: "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90", destructive: "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", outline: "border border-border bg-background hover:bg-muted hover:text-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50 aria-expanded:bg-muted aria-expanded:text-foreground", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-secondary", link: "text-accent underline-offset-4 hover:underline p-0", }, size: { default: "h-9 px-3 py-2 text-sm has-[.badge:last-child]:pr-1.5 has-[>svg]:px-2.5", sm: "h-8.5 text-sm rounded-lg gap-1.5 px-3 has-[>svg]:px-2", lg: "h-10 text-sm rounded-lg px-5 has-[>svg]:px-4 has-[.badge:last-child]:pr-3 [&_.badge:last-child]:ml-1.5", icon: "size-9", "icon-sm": "size-8.5", "icon-lg": "size-10", }, }, defaultVariants: { variant: "default", size: "default", }, },);
type ButtonVariantProps = VariantProps<typeof buttonVariants>;
type ButtonAsButton = { as?: "button";} & HTMLAttributes<"button">;
type ButtonAsAnchor = { as: "a";} & HTMLAttributes<"a">;
type ButtonOwnProps = ButtonVariantProps & { // you can add custom props here};
export type Props = (ButtonAsButton | ButtonAsAnchor) & ButtonOwnProps;
const { as: Tag = "button", variant, size, class: className = "", ...rest} = Astro.props as Props;---
{ /* TS can't reconcile our discriminated union props with a dynamic intrinsic Tag. The public Props type *is* strict (href only allowed when as="a"), but JSX wants an intersection of button+anchor attributes here. We deliberately suppress this internal error and rely on Props for caller safety.*/}<!-- @ts-expect-error – union Props + dynamic Tag confuse JSX typing (see comment above) --><Tag class={cn(buttonVariants({ variant, size }), className)} {...rest}> <slot /></Tag>---import { Button } from '@bejamas/ui/components/button';---
<Button>Click me</Button>You can use the as prop to render the component as an anchor.
---import { Button } from '@bejamas/ui/components/button';---
<Button as="a" href="https://bejamas.com">Click me</Button>---import { Button } from '@bejamas/ui/components/button';---
<div class="flex flex-col items-start gap-8 sm:flex-row"> <Button variant="default">Default</Button> <Button variant="secondary">Secondary</Button> <Button variant="outline">Outline</Button> <Button variant="ghost">Ghost</Button> <Button variant="destructive">Destructive</Button></div>---import { ArrowUpRightIcon } from '@lucide/astro';
import { Button } from '@bejamas/ui/components/button';---
<div class="flex flex-col items-start gap-8 sm:flex-row"> <div class="flex items-start gap-2"> <Button size="sm" variant="outline"> Small </Button> <Button size="icon-sm" aria-label="Submit" variant="outline"> <ArrowUpRightIcon /> </Button> </div> <div class="flex items-start gap-2"> <Button variant="outline">Default</Button> <Button size="icon" aria-label="Submit" variant="outline"> <ArrowUpRightIcon /> </Button> </div> <div class="flex items-start gap-2"> <Button variant="outline" size="lg"> Large </Button> <Button size="icon-lg" aria-label="Submit" variant="outline"> <ArrowUpRightIcon /> </Button> </div></div>---import { Badge } from '@bejamas/ui/components/badge';import { Button } from '@bejamas/ui/components/button';---
<Button variant="default"> Click me <Badge variant="secondary">Value</Badge></Button>---import { Button } from '@bejamas/ui/components/button';---
<Button variant="destructive">Click me</Button>---import { Button } from '@bejamas/ui/components/button';---
<Button variant="outline">Click me</Button>---import { Button } from '@bejamas/ui/components/button';---
<Button variant="secondary">Click me</Button>---import { Button } from '@bejamas/ui/components/button';---
<Button variant="ghost">Click me</Button>---import { Button } from '@bejamas/ui/components/button';---
<Button variant="link">Click me</Button>---import { Button } from '@bejamas/ui/components/button';---
<Button>Click me</Button>