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