-
-
-# Button
-
-## Introduction
-
-### Definition
-
-The Button is a core UI component that allows users to trigger actions and
-navigate to different parts of the application. It establishes visual hierarchy
-to highlight the most important actions in each workflow while ensuring
-consistency and accessibility.
-
-### Purpose
-
-- **Visual hierarchy**: Highlight the most important actions in each workflow
-- **Consistent interaction**: Ensure consistent behavior and appearance across
- all areas
-- **Accessibility**: Provide inclusive sizes, contrasts, and states for all
- users
-- **Flexibility**: Adapt to multiple use cases from primary flows to contextual
- actions
-
-## Anatomy
-
-
-
-
-- **Label**: The main text describing the action
-- **Icon**: (Optional) Visual symbol to reinforce the action
-- **States**: Default, Hover, Pressed, Disabled, Loading
-- **Variants**: Visual styles for different contexts (primary, secondary, ghost,
- etc.)
-- **Sizes**: Small, Medium, Large
-
-## Variants
-
-### Type
-
-Buttons adapt to different use cases and visual hierarchies:
-
-
-
-
-
-
-
Variant
-
Description
-
Properties
-
-
-
-
-
Default
-
- Is the main, highlighted action used for the most important user tasks.
- Should only appear once per screen.
-
-
- variant="default"
-
-
-
-
Outline
-
Has a subtle, minimal style and is used for secondary actions.
-
- variant="outline"
-
-
-
-
Neutral
-
- Represents tertiary or less important options within the interface but
- offers an extra level of hierarchy.
-
-
- variant="neutral"
-
-
-
-
Ghost
-
- Is for secondary actions, blending subtly with content and standing out
- only on hover or focus.
-
-
- variant="ghost"
-
-
-
-
Critical
-
- Has a warning color scheme and is used for destructive actions that
- require user confirmation (e.g., delete or remove).
-
-
- variant="critical"
-
-
-
-
Promote
-
- Indicates actions related to upselling, such as offering higher-value
- products or upgrades to existing customers.
-
-
- variant="promote"
-
-
-
-
-
-### Icon
-
-
-
-
-
-
-
Type
-
Description
-
Properties
-
-
-
-
-
With icon
-
- Combines an icon with descriptive text for better clarity and
- recognition.
-
-
icon, label
-
-
-
Only icon
-
- Buttons that contain only an icon without visible text. Useful for
- toolbars or compact actions.
-
-
icon, hideLabel, round
-
-
-
Only emoji
-
- A special case of icon-only button, using an emoji as the icon. Useful
- for playful or expressive actions.
-
-
emoji, hideLabel, round
-
-
-
-
-### Sizes
-
-
-
-
-
-
-
Size
-
Description
-
Properties
-
-
-
-
-
lg (40)
-
Designed for mobile devices as they require a larger touch area.
-
variant="lg"
-
-
-
md (32)
-
Standard size for desktop, used in most cases.
-
variant="md"
-
-
-
sm (24)
-
- Perfect for secondary actions on desktop, such as buttons in tables,
- selectors, etc., where space is more limited.
-
-
variant="sm"
-
-
-
-
-### States
-
-Buttons can appear in different visual and functional states, each communicating
-an intention or restriction to the user.
-
-
-
-
-
-
-
State
-
Description
-
Properties
-
-
-
-
-
Pressed
-
Represents the active or selected state of the button.
-
pressed
-
-
-
Disabled
-
The button is inactive and does not respond to user interaction.
-
disabled
-
-
-
Loading
-
Indicates that an action is in progress.
-
loading
-
-
-
-
-###### Async Loading
-
-Demonstrates a real asynchronous action: the button enters a loading state after
-being clicked and provides feedback to the user.
-
-
-
-##### Best practices:
-
-- Use the disabled state to prevent invalid actions, not just for visual
- deactivation.
-- The loading state blocks interaction until the action is complete.
-- Provide clear feedback after asynchronous actions (e.g., show a success or
- error message).
-
-## Guidelines
-
-### Content best practices
-
-- Use clear, concise, and actionable language for button labels.
-- Ensure button labels are consistent with the associated action or
- functionality.
-- Be specific and actionable
- - ✅ **Correct:** "Create employee", "Submit request", "Download report"
- - ❌ **Incorrect:** "OK", "Send", "Do"
-- Use imperative verbs
- - ✅ **Correct:** "Save changes", "Delete account", "Export data"
- - ❌ **Incorrect:** "Saved", "Deletion", "Exportation"
-
-### Design best practices
-
-#### When to use
-
-- Use buttons whenever you need the user to trigger an action or navigate to a
- different part of the application.
-- Choose the appropriate button type based on the importance and context of the
- action.
-- Utilize the different button variants to create a clear visual hierarchy and
- guide the user's attention.
-- Only one primary button per section or screen on the right.
-
-#### How to use
-
-- Position the most important actions as **Primary** buttons, with less crucial
- actions as **Outline** or **Neutral** buttons.
-- Use the **Ghost** button type sparingly, as it can be less visually prominent.
-- Avoid using the **Critical** button type for anything other than truly
- destructive actions that require user confirmation.
-- Consider adding icons to buttons when they can enhance recognition and
- usability, but don't overuse icons.
-- Ensure that button sizes are consistent within the same context, following the
- recommended size guidelines.
-- Always provide a **disabled** state for buttons that may become unavailable
- based on user actions or application state.
-
-
- ),
- }}
- dont={{
- guidelines: [
- "Don't mix too many button styles in a single group.",
- "Avoid breaking the visual flow of action groups.",
- "Don't group unrelated actions together.",
- ],
- children: (
-
- ),
- }}
-/>
diff --git a/packages/react/src/components/Actions/Button/index.test.tsx b/packages/react/src/components/Actions/Button/index.test.tsx
deleted file mode 100644
index 62741b3f49..0000000000
--- a/packages/react/src/components/Actions/Button/index.test.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-import { render, screen } from "@testing-library/react"
-import { userEvent } from "@testing-library/user-event"
-import { expect, test, vi } from "vitest"
-import Add from "../../../icons/app/Add"
-import { Button } from "./index"
-
-test("Button calls the `onClick` handler when clicked", async () => {
- const onClick = vi.fn()
-
- render(
+
+ )
+})
+
+export { ButtonInternal }
diff --git a/packages/react/src/components/F0Button/types.ts b/packages/react/src/components/F0Button/types.ts
new file mode 100644
index 0000000000..80a05a22e8
--- /dev/null
+++ b/packages/react/src/components/F0Button/types.ts
@@ -0,0 +1,7 @@
+import { actionButtonVariants, actionSizes } from "@/ui/Action"
+
+export const buttonVariants = actionButtonVariants
+export type ButtonVariant = (typeof buttonVariants)[number]
+
+export const buttonSizes = actionSizes
+export type ButtonSize = (typeof buttonSizes)[number]
diff --git a/packages/react/src/components/Actions/OneDropdownButton/OneDropdownButton.tsx b/packages/react/src/components/F0ButtonDropdown/F0ButtonDropdown.tsx
similarity index 71%
rename from packages/react/src/components/Actions/OneDropdownButton/OneDropdownButton.tsx
rename to packages/react/src/components/F0ButtonDropdown/F0ButtonDropdown.tsx
index a909bfa000..e53f478ffa 100644
--- a/packages/react/src/components/Actions/OneDropdownButton/OneDropdownButton.tsx
+++ b/packages/react/src/components/F0ButtonDropdown/F0ButtonDropdown.tsx
@@ -1,39 +1,19 @@
+import { F0Icon } from "@/components/F0Icon"
+import { DropdownInternal } from "@/experimental/Navigation/Dropdown/internal.tsx"
+import { ChevronDown } from "@/icons/app/index.ts"
import { useI18n } from "@/lib/providers/i18n"
+import { cn, focusRing } from "@/lib/utils.ts"
+import { Action } from "@/ui/Action/index.tsx"
+import { actionVariants, buttonSizeVariants } from "@/ui/Action/variants.ts"
import { useMemo, useState } from "react"
-import { DropdownInternal } from "../../../experimental/Navigation/Dropdown/internal.tsx"
-import { ChevronDown } from "../../../icons/app/index.ts"
-import { cn, focusRing } from "../../../lib/utils.ts"
-import { Action } from "../../../ui/Action/index.tsx"
-import {
- actionVariants,
- buttonSizeVariants,
-} from "../../../ui/Action/variants.ts"
-import { F0Icon, IconType } from "../../F0Icon/index.tsx"
-import { OneDropdownButtonSize, OneDropdownButtonVariant } from "./types.ts"
+import { F0ButtonDropdownProps } from "./types.ts"
-export type OneDropdownButtonItem = {
- value: T
- label: string
- icon?: IconType
- critical?: boolean
-}
-
-export type OneDropdownButtonProps = {
- size?: OneDropdownButtonSize
- items: OneDropdownButtonItem[]
- variant?: OneDropdownButtonVariant
- value?: T
- disabled?: boolean
- loading?: boolean
- onClick: (value: T, item: OneDropdownButtonItem) => void
-}
-
-const OneDropdownButton = ({
+const F0ButtonDropdown = ({
items,
onClick,
value,
...props
-}: OneDropdownButtonProps) => {
+}: F0ButtonDropdownProps) => {
const t = useI18n()
const [isOpen, setIsOpen] = useState(false)
@@ -78,10 +58,11 @@ const OneDropdownButton = ({
disabled={props.disabled}
loading={props.loading}
data-testid="button-main"
+ aria-label={selectedItem.label}
prepend={selectedItem.icon && }
- appendOutside={true}
className="rounded-r-none after:rounded-r-none"
- append={
+ tooltip={props.tooltip}
+ appendOutside={
Action button that allows to select the action using a dropdown." +
+ "
This component received a list of items (each item has a value), when the user clicks the button the component emits the `onClick` event with the value of the item and the item itself
- {
// if action was triggered by user, focus the close button
if (isLastToggleInvokedByUser) {
@@ -164,7 +155,6 @@ export function PageHeader({
}}
variant="ghost"
hideLabel
- round
onClick={() => toggleSidebar()}
label="Open main menu"
icon={Menu}
@@ -185,10 +175,9 @@ export function PageHeader({
!("loading" in parentBreadcrumb) && (