Badge
Small labels which hold small amounts of information, system feedback, or states.
Props
type
information | important | emergency | success | dark | midtone | light | archived | aqua | black | blue | green | orange | pink | red | violet | white | yellow | aqua-light | black-light | blue-light | green-light | orange-light | pink-light | red-light | violet-light | yellow-light | sky | prairie | lilac | pasture | sunset | dawn | default
Defines the context and colour of the badge.
testId
string
Sets the data-testid attribute. Used with ByTestId queries in tests.
content
string
Text label of the badge.
icon
string
Use icontype instead. Includes an icon in the badge.
icontype
GoAIconType
Icon type to display in the badge.
ariaLabel
string
Accessible label for screen readers.
size
medium | large
Sets the size of the badge.
Defaults to
medium.
emphasis
Sets the visual emphasis. 'subtle' for less prominent, 'strong' for more emphasis.
Defaults to
strong.
version
1 | 2
The design system version for styling purposes.
Defaults to
1.
mt, mr, mb, ml
none | 3xs | 2xs | xs | s | m | l | xl | 2xl | 3xl | 4xl
Apply margin to the top, right, bottom, and/or left of the component.
Card view of case files
.case-file-row {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
align-items: center;
gap: var(--goa-space-m);
}<GoabContainer mt="l">
<div className="case-file-row">
<GoabBlock direction="column" gap="2xs">
<GoabText size="heading-xs" mt="none" mb="2xs">Fiscal year: 2021/2022</GoabText>
<GoabText size="body-s" mt="none" mb="none">Submitted: April 23, 2023</GoabText>
</GoabBlock>
<GoabBlock direction="row" gap="l" alignment="center">
<GoabBadge type="midtone" content="Not started" />
<GoabButton type="tertiary" size="compact">Start</GoabButton>
</GoabBlock>
</div>
</GoabContainer>
<GoabContainer>
<div className="case-file-row">
<GoabBlock direction="column" gap="2xs">
<GoabText size="heading-xs" mt="none" mb="2xs">Fiscal year: 2020/2021</GoabText>
<GoabText size="body-s" mt="none" mb="none">Submitted: April 9, 2022</GoabText>
</GoabBlock>
<GoabBlock direction="row" gap="l" alignment="center">
<GoabBadge type="important" content="Information needed" />
<GoabButton type="tertiary" size="compact">Edit</GoabButton>
</GoabBlock>
</div>
</GoabContainer>
<GoabContainer>
<div className="case-file-row">
<GoabBlock direction="column" gap="2xs">
<GoabText size="heading-xs" mt="none" mb="2xs">Fiscal year: 2019/2020</GoabText>
<GoabText size="body-s" mt="none" mb="none">Submitted: April 14, 2021</GoabText>
</GoabBlock>
<GoabBlock direction="row" gap="l" alignment="center">
<GoabBadge type="success" content="Approved" />
<GoabButton type="tertiary" size="compact">View</GoabButton>
</GoabBlock>
</div>
</GoabContainer>Expand or collapse part of a form
dl.accordion-example {
margin: 0 0;
}
.accordion-example dt {
color: var(--goa-color-text-default);
font: var(--goa-typography-heading-s);
margin-bottom: var(--goa-space-xs);
}
.accordion-example dd {
margin: 0 0 var(--goa-space-l);
font: var(--goa-typography-body-m);
}
.accordion-example dd:last-of-type {
margin-bottom: 0;
}<GoabText as="h3" mt="none" mb="m">Review your application</GoabText>
<GoabAccordion
heading="Referral details"
headingContent={<GoabBadge type="important" content="Updated" />}>
<dl className="accordion-example">
<dt>Date of referral</dt>
<dd>January 27, 2021</dd>
<dt>Work safety concerns</dt>
<dd>None</dd>
<dt>Type of referral</dt>
<dd>Word of mouth, internet search</dd>
<dt>Intake received from another site</dt>
<dd>Yes</dd>
</dl>
</GoabAccordion>
<GoabAccordion heading="Contact information">
<dl className="accordion-example">
<dt>Name</dt>
<dd>Joan Smith</dd>
<dt>Contact preference</dt>
<dd>Text message</dd>
</dl>
</GoabAccordion>Filter data in a table
const [typedChips, setTypedChips] = useState<string[]>([]);
const [inputValue, setInputValue] = useState("");
const [inputError, setInputError] = useState("");
const errorEmpty = "Empty filter";
const errorDuplicate = "Enter a unique filter";
const data = useMemo(
() => [
{
status: { type: "information" as GoabBadgeType, text: "In progress" },
name: "Ivan Schmidt",
id: "7838576954",
},
{
status: { type: "success" as GoabBadgeType, text: "Completed" },
name: "Luz Lakin",
id: "8576953364",
},
{
status: { type: "information" as GoabBadgeType, text: "In progress" },
name: "Keith McGlynn",
id: "9846041345",
},
{
status: { type: "success" as GoabBadgeType, text: "Completed" },
name: "Melody Frami",
id: "7385256175",
},
{
status: { type: "important" as GoabBadgeType, text: "Updated" },
name: "Frederick Skiles",
id: "5807570418",
},
{
status: { type: "success" as GoabBadgeType, text: "Completed" },
name: "Dana Pfannerstill",
id: "5736306857",
},
],
[]
);
const [dataFiltered, setDataFiltered] = useState(data);
const handleInputChange = (detail: GoabInputOnChangeDetail) => {
const newValue = detail.value.trim();
setInputValue(newValue);
};
const handleInputKeyPress = (detail: GoabInputOnKeyPressDetail) => {
if (detail.key === "Enter") {
applyFilter();
}
};
const applyFilter = () => {
if (inputValue === "") {
setInputError(errorEmpty);
return;
}
if (typedChips.length > 0 && typedChips.includes(inputValue)) {
setInputError(errorDuplicate);
return;
}
setTypedChips([...typedChips, inputValue]);
setTimeout(() => {
setInputValue("");
}, 0);
setInputError("");
};
const removeTypedChip = (chip: string) => {
setTypedChips(typedChips.filter(c => c !== chip));
setInputError("");
};
const checkNested = useCallback((obj: object, chip: string): boolean => {
return Object.values(obj).some(value =>
typeof value === "object" && value !== null
? checkNested(value, chip)
: typeof value === "string" && value.toLowerCase().includes(chip.toLowerCase())
);
}, []);
const getFilteredData = useCallback(
(typedChips: string[]) => {
if (typedChips.length === 0) {
return data;
}
return data.filter((item: object) =>
typedChips.every(chip => checkNested(item, chip))
);
},
[checkNested, data]
);
useEffect(() => {
setDataFiltered(getFilteredData(typedChips));
}, [getFilteredData, typedChips]);<GoabFormItem id="filterChipInput" error={inputError} mb="m">
<GoabBlock gap="xs" direction="row" alignment="start" width="100%">
<div style={{ flex: 1 }}>
<GoabInput
name="filterChipInput"
aria-labelledby="filterChipInput"
value={inputValue}
leadingIcon="search"
width="100%"
onChange={handleInputChange}
onKeyPress={handleInputKeyPress}
/>
</div>
<GoabButton type="secondary" onClick={applyFilter} leadingIcon="filter">
Filter
</GoabButton>
</GoabBlock>
</GoabFormItem>
{typedChips.length > 0 && (
<div>
<GoabText tag="span" color="secondary" mb="xs" mr="xs">
Filter:
</GoabText>
{typedChips.map((typedChip, index) => (
<GoabFilterChip
key={index}
content={typedChip}
mb="xs"
mr="xs"
onClick={() => removeTypedChip(typedChip)}
/>
))}
<GoabButton type="tertiary" size="compact" mb="xs" onClick={() => setTypedChips([])}>
Clear all
</GoabButton>
</div>
)}
<GoabTable width="full">
<thead>
<tr>
<th>Status</th>
<th>Name</th>
<th className="goa-table-number-header">ID Number</th>
</tr>
</thead>
<tbody>
{dataFiltered.map(item => (
<tr key={item.id}>
<td>
<GoabBadge type={item.status.type} content={item.status.text} icon={false} />
</td>
<td>{item.name}</td>
<td className="goa-table-number-column">{item.id}</td>
</tr>
))}
</tbody>
</GoabTable>
{dataFiltered.length === 0 && data.length > 0 && (
<GoabBlock mt="l" mb="l">
No results found
</GoabBlock>
)}Set a specific tab to be active
const review = [0, 1, 2, 3];
const complete = [0, 1];<GoabTabs initialTab={2}>
<GoabTab heading="All">
<GoabTable width="100%">
<thead>
<tr>
<th>Status</th>
<th>Text</th>
<th className="goa-table-number-header">Number</th>
<th style={{ width: "1%", whiteSpace: "nowrap" }}>Action</th>
</tr>
</thead>
<tbody>
{review.map((i) => (
<tr key={`review-${i}`}>
<td>
<GoabBadge type="important" content="Review pending" />
</td>
<td>Lorem Ipsum</td>
<td className="goa-table-number-column">1234567890</td>
<td>
<GoabButton type="tertiary" size="compact">Action</GoabButton>
</td>
</tr>
))}
{complete.map((i) => (
<tr key={`complete-${i}`}>
<td>
<GoabBadge type="information" content="Complete" />
</td>
<td>Lorem Ipsum</td>
<td className="goa-table-number-column">1234567890</td>
<td>
<GoabButton type="tertiary" size="compact">Action</GoabButton>
</td>
</tr>
))}
</tbody>
</GoabTable>
</GoabTab>
<GoabTab heading={<>Review pending<GoabBadge type="important" content="4" icon={false} /></>}>
<GoabTable width="100%">
<thead>
<tr>
<th>Status</th>
<th>Text</th>
<th className="goa-table-number-header">Number</th>
<th style={{ width: "1%", whiteSpace: "nowrap" }}>Action</th>
</tr>
</thead>
<tbody>
{review.map((i) => (
<tr key={i}>
<td>
<GoabBadge type="important" content="Review pending" />
</td>
<td>Lorem Ipsum</td>
<td className="goa-table-number-column">1234567890</td>
<td>
<GoabButton type="tertiary" size="compact">Action</GoabButton>
</td>
</tr>
))}
</tbody>
</GoabTable>
</GoabTab>
<GoabTab heading={<>Complete<GoabBadge type="information" content="338" icon={false} /></>}>
<GoabTable width="100%">
<thead>
<tr>
<th>Status</th>
<th>Text</th>
<th className="goa-table-number-header">Number</th>
<th style={{ width: "1%", whiteSpace: "nowrap" }}>Action</th>
</tr>
</thead>
<tbody>
{complete.map((i) => (
<tr key={i}>
<td>
<GoabBadge type="information" content="Complete" />
</td>
<td>Lorem Ipsum</td>
<td className="goa-table-number-column">1234567890</td>
<td>
<GoabButton type="tertiary" size="compact">Action</GoabButton>
</td>
</tr>
))}
</tbody>
</GoabTable>
</GoabTab>
</GoabTabs>Show different views of data in a table
const review = [0, 1, 2, 3];
const complete = [0, 1];<GoabTabs initialTab={1}>
<GoabTab heading="All">
<GoabTable width="100%">
<thead>
<tr>
<th>Status</th>
<th>Text</th>
<th className="goa-table-number-header">Number</th>
<th style={{ width: "1%", whiteSpace: "nowrap" }}>Action</th>
</tr>
</thead>
<tbody>
{review.map((i) => (
<tr key={`review-${i}`}>
<td>
<GoabBadge type="important" content="Review pending" />
</td>
<td>Lorem Ipsum</td>
<td className="goa-table-number-column">1234567890</td>
<td>
<GoabButton type="tertiary" size="compact">Action</GoabButton>
</td>
</tr>
))}
{complete.map((i) => (
<tr key={`complete-${i}`}>
<td>
<GoabBadge type="information" content="Complete" />
</td>
<td>Lorem Ipsum</td>
<td className="goa-table-number-column">1234567890</td>
<td>
<GoabButton type="tertiary" size="compact">Action</GoabButton>
</td>
</tr>
))}
</tbody>
</GoabTable>
</GoabTab>
<GoabTab
heading={
Review pending
<GoabBadge type="important" content="4" icon={false} />
}
>
<GoabTable width="100%">
<thead>
<tr>
<th>Status</th>
<th>Text</th>
<th className="goa-table-number-header">Number</th>
<th style={{ width: "1%", whiteSpace: "nowrap" }}>Action</th>
</tr>
</thead>
<tbody>
{review.map((i) => (
<tr key={i}>
<td>
<GoabBadge type="important" content="Review pending" />
</td>
<td>Lorem Ipsum</td>
<td className="goa-table-number-column">1234567890</td>
<td>
<GoabButton type="tertiary" size="compact">Action</GoabButton>
</td>
</tr>
))}
</tbody>
</GoabTable>
</GoabTab>
<GoabTab
heading={
<>
Complete
<GoabBadge type="information" content="338" icon={false} />
</>
}
>
<GoabTable width="100%">
<thead>
<tr>
<th>Status</th>
<th>Text</th>
<th className="goa-table-number-header">Number</th>
<th style={{ width: "1%", whiteSpace: "nowrap" }}>Action</th>
</tr>
</thead>
<tbody>
{complete.map((i) => (
<tr key={i}>
<td>
<GoabBadge type="information" content="Complete" />
</td>
<td>Lorem Ipsum</td>
<td className="goa-table-number-column">1234567890</td>
<td>
<GoabButton type="tertiary" size="compact">Action</GoabButton>
</td>
</tr>
))}
</tbody>
</GoabTable>
</GoabTab>
</GoabTabs>Show multiple actions in a compact table
const rows = [
{ status: "information", statusText: "In progress", name: "Darlene Robertson", id: 45904 },
{ status: "dark", statusText: "Inactive", name: "Floyd Miles", id: 47838 },
{ status: "success", statusText: "Active", name: "Kathryn Murphy", id: 34343 },
{ status: "important", statusText: "Recent", name: "Annette Black", id: 89897 },
{ status: "success", statusText: "Active", name: "Esther Howard", id: 12323 },
{ status: "success", statusText: "Active", name: "Jane Cooper", id: 56565 },
];<GoabTable width="100%">
<thead>
<tr>
<th>Status</th>
<th>Name</th>
<th style={{ textAlign: "right" }}>Id Number</th>
<th style={{ width: "1%", whiteSpace: "nowrap" }}>Edit | Flag | Send</th>
</tr>
</thead>
<tbody>
{rows.map((row) => (
<tr key={row.id}>
<td>
<GoabBadge
type={row.status as "information" | "dark" | "success" | "important"}
content={row.statusText}
icon={false}
/>
</td>
<td>{row.name}</td>
<td className="goa-table-number-column">{row.id}</td>
<td>
<GoabBlock>
<GoabIconButton size="small" icon="pencil" ariaLabel="Edit" />
<GoabIconButton size="small" icon="flag" ariaLabel="Flag" />
<GoabIconButton size="small" icon="mail" ariaLabel="Send" />
</GoabBlock>
</td>
</tr>
))}
</tbody>
</GoabTable>Show multiple tags together
<GoabBlock gap="xs">
<GoabBadge type="information" content="In progress" />
<GoabBadge type="important" content="Priority" />
<GoabBadge type="emergency" content="Past deadline" />
</GoabBlock>Show status in a table
interface BadgeValue {
key: number;
type: GoabBadgeType;
content: string;
}
const badgeValues: BadgeValue[] = [
{ key: 1, type: "important", content: "Pending" },
{ key: 2, type: "emergency", content: "Failed" },
{ key: 3, type: "success", content: "Complete" },
{ key: 4, type: "information", content: "In progress" },
{ key: 5, type: "midtone", content: "Closed" },
{ key: 6, type: "success", content: "Complete" },
];
const handleClick = () => {
console.log("clicked");
};<GoabTable width="100%">
<thead>
<tr>
<th>Status</th>
<th>Name</th>
<th className="goa-table-number-header">File number</th>
<th style={{ width: "1%", whiteSpace: "nowrap" }}></th>
</tr>
</thead>
<tbody>
{badgeValues.map((badge) => (
<tr key={badge.key}>
<td>
<GoabBadge type={badge.type} content={badge.content} icon={false} />
</td>
<td>Lorem ipsum dolor sit amet consectetur</td>
<td className="goa-table-number-column">1234567890</td>
<td>
<GoabButton size="compact" type="tertiary" onClick={handleClick}>
Assign
</GoabButton>
</td>
</tr>
))}
</tbody>
</GoabTable>Show status on a card
<GoabContainer
type="non-interactive"
accent="thick"
heading="Heading"
actions={<GoabBadge type="important" content="Priority" />}
>
Content
</GoabContainer>Task list page
<GoabText as="h1" mt="none">Apply for a service</GoabText>
<GoabCallout
type="important"
emphasis="low"
size="medium"
heading="Application incomplete"
mb="2xl"
mt="xl"
maxWidth="360px"
>
You have completed 1 of 3 sections.
</GoabCallout>
<GoabText as="h2">1. Before you start</GoabText>
<GoabTable width="100%" mb="2xl" mt="l">
<tbody>
<tr>
<td>
<a href="#">Read terms of use</a>
</td>
<td className="goa-table-number-column">
<GoabBadge type="success" content="Completed" ariaLabel="completed" icon={false} />
</td>
</tr>
</tbody>
</GoabTable>
<GoabText as="h2">2. Prepare application</GoabText>
<GoabTable width="100%" mb="2xl" mt="l">
<tbody>
<tr>
<td>
<a href="#">Your contact details</a>
</td>
<td className="goa-table-number-column">
<GoabBadge type="information" content="Not started" ariaLabel="not started" icon={false} />
</td>
</tr>
<tr>
<td>
<a href="#">Your family</a>
</td>
<td className="goa-table-number-column">
<GoabBadge type="information" content="Not started" ariaLabel="not started" icon={false} />
</td>
</tr>
<tr>
<td>
<a href="#">Verify your identity</a>
</td>
<td className="goa-table-number-column">
<GoabBadge type="information" content="Not started" ariaLabel="not started" icon={false} />
</td>
</tr>
</tbody>
</GoabTable>
<GoabText as="h2" mb="s">3. Schedule service</GoabText>
<GoabText size="body-s" color="secondary" mt="2xs">
You need to complete the previous section before you can start this task.
</GoabText>
<GoabTable width="100%" mt="l" mb="3xl">
<tbody>
<tr>
<td>Receive email confirmation</td>
<td className="goa-table-number-column">
<GoabBadge type="light" content="Cannot start yet" ariaLabel="cannot start yet" icon={false} />
</td>
</tr>
<tr>
<td>Pay service fee</td>
<td className="goa-table-number-column">
<GoabBadge type="light" content="Cannot start yet" ariaLabel="cannot start yet" icon={false} />
</td>
</tr>
</tbody>
</GoabTable>Other
Don't
Don't use a primary button to edit a badge.
Do
Use badges for information and organization, not interactivity.
Do
Use a tertiary button next to a badge if it needs to be manually updated.
Types
Don't
Don't style badges to look like buttons.
Don't
Don't use interactive colours. These are reserved for links, buttons, and other interactive elements.
Do
Match badge type to the status it represents
Content
Do
Use sentence case for badge text. Capitalize the first word only.
Do
Use short, concise text in badges.
Screen Readers
Icon-only interactive elements must have an accessible label so screen reader users understand their purpose.
For IconButton: The ariaLabel prop is required.
// Good - describes the action
<GoabIconButton icon="trash" ariaLabel="Delete item" />
// Bad - no label for screen readers
<GoabIconButton icon="trash" />
For Badge with icon only: Provide ariaLabel when there’s no visible text.
<GoabBadge icon="warning" ariaLabel="Warning" type="important" />
For Icon: Use ariaLabel when the icon conveys meaning, not just decoration.
The label should describe:
- What action happens (for buttons): “Delete”, “Edit”, “Close”
- What the icon represents (for informational icons): “Warning”, “Success”
Don't
Don't use icon-only elements without an accessible label