Docs Components Core

Button

React example follows below.
ts
import { Button } from "@grassroot/ui-react";
const buttonFixture = {
id: "button",
buttons: [
{ id: "primary", label: "Start a project" },
{ id: "secondary", label: "View work", variant: "secondary" },
{ id: "ghost", label: "See the work", variant: "ghost" },
{ id: "link", label: "Read the case study", variant: "link" },
{ id: "small", label: "Small", size: "sm" },
{ id: "large", label: "Large", size: "lg" },
{ id: "disabled", label: "Disabled", disabled: true },
],
} satisfies {
id: string;
buttons: Array<{
id: string;
label: string;
variant?: "primary" | "secondary" | "ghost" | "link";
size?: "sm" | "md" | "lg";
disabled?: boolean;
}>;
};
export default function ButtonDemo() {
return (
<div style={{ display: "flex", flexWrap: "wrap", alignItems: "center", gap: "14px" }}>
{buttonFixture.buttons.map((button) => (
<Button
key={button.id}
variant={button.variant}
size={button.size}
disabled={button.disabled}
>
{button.label}
</Button>
))}
</div>
);
}
ts
<script setup lang="ts">
import { Button } from "@grassroot/ui-vue";
const buttonFixture = {
id: "button",
buttons: [
{ id: "primary", label: "Start a project" },
{ id: "secondary", label: "View work", variant: "secondary" },
{ id: "ghost", label: "See the work", variant: "ghost" },
{ id: "link", label: "Read the case study", variant: "link" },
{ id: "small", label: "Small", size: "sm" },
{ id: "large", label: "Large", size: "lg" },
{ id: "disabled", label: "Disabled", disabled: true },
],
} satisfies {
id: string;
buttons: Array<{
id: string;
label: string;
variant?: "primary" | "secondary" | "ghost" | "link";
size?: "sm" | "md" | "lg";
disabled?: boolean;
}>;
};
</script>
<template>
<div style="display: flex; flex-wrap: wrap; align-items: center; gap: 14px">
<Button
v-for="button in buttonFixture.buttons"
:key="button.id"
:variant="button.variant"
:size="button.size"
:disabled="button.disabled"
>{{ button.label }}</Button
>
</div>
</template>
ts
import { Component } from "@angular/core";
import { GrassrootButton } from "@grassroot/ui-angular";
const buttonFixture = {
id: "button",
buttons: [
{ id: "primary", label: "Start a project" },
{ id: "secondary", label: "View work", variant: "secondary" },
{ id: "ghost", label: "See the work", variant: "ghost" },
{ id: "link", label: "Read the case study", variant: "link" },
{ id: "small", label: "Small", size: "sm" },
{ id: "large", label: "Large", size: "lg" },
{ id: "disabled", label: "Disabled", disabled: true },
],
} satisfies {
id: string;
buttons: Array<{
id: string;
label: string;
variant?: "primary" | "secondary" | "ghost" | "link";
size?: "sm" | "md" | "lg";
disabled?: boolean;
}>;
};
@Component({
selector: "app-button-demo",
standalone: true,
imports: [GrassrootButton],
template: `
<div style="display:flex;flex-wrap:wrap;align-items:center;gap:14px">
@for (button of fixture.buttons; track button.id) {
<grassroot-button
[variant]="button.variant"
[size]="button.size"
[disabled]="button.disabled"
>{{ button.label }}</grassroot-button
>
}
</div>
`,
})
export class ButtonDemoComponent {
protected readonly fixture = buttonFixture;
}
export default ButtonDemoComponent;
ts
<script lang="ts">
import { Button } from "@grassroot/ui-svelte";
const buttonFixture = {
id: "button",
buttons: [
{ id: "primary", label: "Start a project" },
{ id: "secondary", label: "View work", variant: "secondary" },
{ id: "ghost", label: "See the work", variant: "ghost" },
{ id: "link", label: "Read the case study", variant: "link" },
{ id: "small", label: "Small", size: "sm" },
{ id: "large", label: "Large", size: "lg" },
{ id: "disabled", label: "Disabled", disabled: true },
],
} satisfies {
id: string;
buttons: Array<{
id: string;
label: string;
variant?: "primary" | "secondary" | "ghost" | "link";
size?: "sm" | "md" | "lg";
disabled?: boolean;
}>;
};
</script>
<div style="display:flex;flex-wrap:wrap;align-items:center;gap:14px">
{#each buttonFixture.buttons as button (button.id)}
<Button variant={button.variant} size={button.size} disabled={button.disabled}
>{button.label}</Button
>
{/each}
</div>
ts
/** @jsxImportSource solid-js */
import { Button } from "@grassroot/ui-solid";
import type { JSX } from "solid-js";
const buttonFixture = {
id: "button",
buttons: [
{ id: "primary", label: "Start a project" },
{ id: "secondary", label: "View work", variant: "secondary" },
{ id: "ghost", label: "See the work", variant: "ghost" },
{ id: "link", label: "Read the case study", variant: "link" },
{ id: "small", label: "Small", size: "sm" },
{ id: "large", label: "Large", size: "lg" },
{ id: "disabled", label: "Disabled", disabled: true },
],
} satisfies {
id: string;
buttons: Array<{
id: string;
label: string;
variant?: "primary" | "secondary" | "ghost" | "link";
size?: "sm" | "md" | "lg";
disabled?: boolean;
}>;
};
export default function ButtonDemo(): JSX.Element {
return (
<div style={{ display: "flex", "flex-wrap": "wrap", "align-items": "center", gap: "14px" }}>
{buttonFixture.buttons.map((button) => (
<Button variant={button.variant} size={button.size} disabled={button.disabled}>
{button.label}
</Button>
))}
</div>
);
}

Installation

API Reference

Import

import { Button } from "@grassroot/ui-react";

Props

Prop
Type
Default
Requirement
Description
variant
"secondary" | "ghost" | "primary" | "link" | undefined
"primary"
optional
Visual style.
size
"sm" | "md" | "lg" | undefined
"md"
optional
—
tone
Tone | undefined
"accent"
optional
Brand colour.
as
"button" | "a" | undefined
"button"
optional
Render as a native button or anchor while keeping Button styling.
href
string | undefined
—
optional
Passed through when as="a" renders a native anchor.
loading
boolean | undefined
false
optional
In-flight state: announces `aria-busy`, swaps the leading icon for a spinner, and suspends activation — WITHOUT removing the button from the tab order (the Grassroot rule: a busy control stays findable).
Prop
variant
Type
"secondary" | "ghost" | "primary" | "link" | undefined
Default
"primary"
Requirement
optional
Description
Visual style.
Prop
size
Type
"sm" | "md" | "lg" | undefined
Default
"md"
Requirement
optional
Description
—
Prop
tone
Type
Tone | undefined
Default
"accent"
Requirement
optional
Description
Brand colour.
Prop
as
Type
"button" | "a" | undefined
Default
"button"
Requirement
optional
Description
Render as a native button or anchor while keeping Button styling.
Prop
href
Type
string | undefined
Default
—
Requirement
optional
Description
Passed through when as="a" renders a native anchor.
Prop
loading
Type
boolean | undefined
Default
false
Requirement
optional
Description
In-flight state: announces `aria-busy`, swaps the leading icon for a spinner, and suspends activation — WITHOUT removing the button from the tab order (the Grassroot rule: a busy control stays findable).

Content regions

  • children
  • iconLeft

Native attributes

Standard DOM and ARIA attributes not listed above spread onto the root element.

Import

import { Button } from "@grassroot/ui-vue";

Props

Prop
Type
Default
Requirement
variant
ButtonVariant | undefined
"primary"
optional
size
ButtonSize | undefined
"md"
optional
tone
ButtonTone | undefined
"accent"
optional
as
"button" | "a" | undefined
"button"
optional
href
string | undefined
—
optional
loading
boolean | undefined
—
optional
disabled
boolean | undefined
—
optional
type
"button" | "submit" | "reset" | undefined
"button"
optional
Prop
variant
Type
ButtonVariant | undefined
Default
"primary"
Requirement
optional
Prop
size
Type
ButtonSize | undefined
Default
"md"
Requirement
optional
Prop
tone
Type
ButtonTone | undefined
Default
"accent"
Requirement
optional
Prop
as
Type
"button" | "a" | undefined
Default
"button"
Requirement
optional
Prop
href
Type
string | undefined
Default
—
Requirement
optional
Prop
loading
Type
boolean | undefined
Default
—
Requirement
optional
Prop
disabled
Type
boolean | undefined
Default
—
Requirement
optional
Prop
type
Type
"button" | "submit" | "reset" | undefined
Default
"button"
Requirement
optional

Events

EventPayload
click[event: MouseEvent]

Content regions

  • default
  • iconLeft

Import

import { Component } from "@angular/core";
import { GrassrootButton } from "@grassroot/ui-angular";

Props

Prop
Type
Default
Requirement
variant
ButtonVariant
"primary"
optional
size
ButtonSize
"md"
optional
tone
ButtonTone
"accent"
optional
as
"button" | "a"
"button"
optional
href
string
—
optional
loading
boolean
false
optional
disabled
boolean
false
optional
type
"button" | "submit" | "reset"
"button"
optional
className
string
—
optional
Prop
variant
Type
ButtonVariant
Default
"primary"
Requirement
optional
Prop
size
Type
ButtonSize
Default
"md"
Requirement
optional
Prop
tone
Type
ButtonTone
Default
"accent"
Requirement
optional
Prop
as
Type
"button" | "a"
Default
"button"
Requirement
optional
Prop
href
Type
string
Default
—
Requirement
optional
Prop
loading
Type
boolean
Default
false
Requirement
optional
Prop
disabled
Type
boolean
Default
false
Requirement
optional
Prop
type
Type
"button" | "submit" | "reset"
Default
"button"
Requirement
optional
Prop
className
Type
string
Default
—
Requirement
optional

Content regions

  • default
  • iconLeft

Import

import { Button } from "@grassroot/ui-svelte";

Props

Prop
Type
Default
Requirement
variant
ButtonVariant
"primary"
optional
size
ButtonSize
"md"
optional
tone
ButtonTone
"accent"
optional
as
"button" | "a"
"button"
optional
href
string
—
optional
loading
boolean
false
optional
disabled
boolean
false
optional
type
"button" | "submit" | "reset"
"button"
optional
className
string
—
optional
onClick
(event: MouseEvent) => void
—
optional
Prop
variant
Type
ButtonVariant
Default
"primary"
Requirement
optional
Prop
size
Type
ButtonSize
Default
"md"
Requirement
optional
Prop
tone
Type
ButtonTone
Default
"accent"
Requirement
optional
Prop
as
Type
"button" | "a"
Default
"button"
Requirement
optional
Prop
href
Type
string
Default
—
Requirement
optional
Prop
loading
Type
boolean
Default
false
Requirement
optional
Prop
disabled
Type
boolean
Default
false
Requirement
optional
Prop
type
Type
"button" | "submit" | "reset"
Default
"button"
Requirement
optional
Prop
className
Type
string
Default
—
Requirement
optional
Prop
onClick
Type
(event: MouseEvent) => void
Default
—
Requirement
optional

Events

EventPayload
onClick(event: MouseEvent) => void

Content regions

  • children
  • iconLeft

Import

import { Button } from "@grassroot/ui-solid";
import type { JSX } from "solid-js";

Props

Prop
Type
Default
Requirement
variant
ButtonVariant
"primary"
optional
size
ButtonSize
"md"
optional
tone
ButtonTone
"accent"
optional
as
"button" | "a"
"button"
optional
href
string
—
optional
loading
boolean
false
optional
disabled
boolean
—
optional
type
"button" | "submit" | "reset"
"button"
optional
onClick
(event: MouseEvent) => void
—
optional
className
string
—
optional
Prop
variant
Type
ButtonVariant
Default
"primary"
Requirement
optional
Prop
size
Type
ButtonSize
Default
"md"
Requirement
optional
Prop
tone
Type
ButtonTone
Default
"accent"
Requirement
optional
Prop
as
Type
"button" | "a"
Default
"button"
Requirement
optional
Prop
href
Type
string
Default
—
Requirement
optional
Prop
loading
Type
boolean
Default
false
Requirement
optional
Prop
disabled
Type
boolean
Default
—
Requirement
optional
Prop
type
Type
"button" | "submit" | "reset"
Default
"button"
Requirement
optional
Prop
onClick
Type
(event: MouseEvent) => void
Default
—
Requirement
optional
Prop
className
Type
string
Default
—
Requirement
optional

Events

EventPayload
onClick(event: MouseEvent) => void

Content regions

  • children
  • iconLeft