Skip to main content
Flowra
PricingCommunityFAQ
JoinStart with Flowra
  • PricingPlans, seats and payment
  • Frequently asked questionsEverything you have asked, in one place
  • Contact usWrite to the right team
  • CommunityKaro Studio, who make Flowra

For your team

  • Marketing teamsCampaigns from brief to launch
  • Product and dev teamsFeatures and bugs with full context
  • Design and content teamsBrief, files and delivery side by side
  • Operations teamsWork, documents and costs you can track
  • Sales and services teamsFrom meeting to contract and payment
  • Remote teamsOnline meeting to delivery, on your time

For your role

  • Project managersAction stories instead of chasing the team
  • Freelancers and consultantsFrom brief to contract and settlement

For your workflow

  • Meeting to actionMeeting decisions as trackable work
  • Actions with financial contextCosts next to the work that caused them
  • Actions with contract contextEvery commitment as trackable work
  • Brief to project deliveryEvery project step, one complete action
See all solutionsStart with FlowraJoin
++
Flowra design system

Fundamentals

PrinciplesVoice and writingCopy rules for each surfaceGlossaryRTL and languagesNumbers and datesAccessibility

Foundations

ColorDark modePrintingTypographySpacing and layoutRadius and shadowLayersMotionNotification soundKeyboard shortcutsIconsService logos

Components

ButtonsText fieldPickerDate and timeCheckboxRadioKeySegmented controlSliderMenu and sheetDialogCard and listTables and data listsBadge, pill, and switchTabs and filtersAvatarEmpty and loading statesProgress and stepsToastFloating helpNavigationPage headerAssistants

Patterns

Connector pageList, filter, and searchForm layoutCreation flowUpgrade promptConfirmation and irreversible actionsPhone layoutFixed bars and scrolling

Brand

Flowra brandMark and logoBrand colorBrand typographyMisuse

Design system/Components

Buttons

One family, one shape: the pill. Three variants for three levels of importance, one red variant only for destructive actions, and three sizes for three contexts. Every button is a verb.

In codeapp/globals.css (.btn)

On this page

  1. Variants
  2. Destructive button
  3. Sizes
  4. States
  5. Anatomy
  6. Accessibility
  7. Code
  8. Size at each breakpoint
  9. States, precisely
  10. Contrast for each variant
  11. Right to left

Variants

btn-dark is the primary button: the action the page was built for. btn-ghost is for secondary actions and sits on the page like a card. btn-accent is rare: for when one action needs to be seen more than anything else on the page, like "Upgrade."

Live example
btn-smbtnbtn-lg
btn-dark
btn-ghost
btn-accent
btn-danger

When to use it

  • btn-dark: once per area, for the main action.
  • btn-ghost: cancel, a secondary action, a link to another page.
  • btn-accent: upgrade, or an action that must be seen; at most one per page.
  • btn-danger: only for confirming a destructive action, like the red “Yes, delete” button in ConfirmDialog.

When not to

  • Two btn-dark buttons side by side; make one of them ghost.
  • A button for going somewhere else when a text link would do.

Destructive button

btn-danger has a strong red background (--red-strong) with white text and darkens 6 percent on hover. It's only for confirming something that can't be undone, and it almost always appears inside a ConfirmDialog or an inline confirmation next to "Cancel", not as the first button that starts the task.

btn-dangerbg var(--red-strong) · #fff · border var(--red-strong)Hover brightness(0.94)

Do

className="btn btn-danger" for “Yes, delete”.

Don't

style={{ background: "var(--red)" }} on a .btn; every hand-made version is slightly different.

Do

The “Delete” row in the menu is red and opens a confirmation dialog.

Don't

A red button that deletes without confirmation.

Why

White text on --red-strong is 5.14 to 1 in light and 5.54 in dark, so it meets AA. Even so, the red button is used sparingly and only for one verb, because red means something will be lost.

Sizes

All sizes have a 999px radius. Icons are 14 to 15px and come before the label with a 6px gap.

btn-sm36px · 13px40px on phones
btn38px · 13.5px / 600Touch 48px · 15px
Page header pill42px · 13.5px.page-head-actions .btn
btn-lg52px · 15.5px / 600Sign-in, payment; touch 56px
btn-field58px · 14.5pxMatches floating field height

States

A button rises 1px under the pointer and shrinks to 97 percent when pressed. Disabled means half-faded and motionless. While in progress, the label gives way to a small spinner and the button is disabled so it can't be pressed twice.

Live example
Default
Inactive
Tap: in progress
icon-btn

Why

A disabled button doesn't say why. In the sign-in form, the button stays enabled when values are wrong, and pressing it names the field with the problem; only an empty required field disables the button, because being empty explains itself.

Anatomy

  1. ContainerA pill with a fixed height; the width comes from the label, and the label never wraps.
  2. IconOptional, before the label; takes the button's text color.
  3. TagA verb: "Create action", "Save".

Accessibility

  • A button with only an icon (icon-btn) gets aria-label and title.
  • On touch screens, btn-sm and pills inside main grow to 42 to 44px.
  • A <Link> shaped like a button gets the same .btn class but stays a link.

Code

<button className="btn btn-dark">
  <Icon d={paths.plus} size={15} />
  {tr("ساخت اقدام")}
</button>

<button className="btn btn-ghost btn-sm" onClick={onClose}>{tr("انصراف")}</button>

<button className="btn btn-dark" disabled={busy}>
  {busy ? <span className="spinner" /> : tr("ذخیره")}
</button>

Size at each breakpoint

Button height comes from three conditions: screen width, pointer type, and the container the button sits in. This table shows what the browser computes after every rule in globals.css.

.btn desktop38px · padding 0 16px · 13.5px / 600 · gap 6px
.btn touch48px · 15px@media (pointer: coarse)
.btn phonefont-size 15px≤ 640px
.btn-sm desktop36px · padding 0 14px · 13pxIcon 14px
.btn-sm phone40px · 13.5pxTouch inside main: min-height 44px
.btn-lg52px · 15.5px / 600Touch 56px · 16px
.btn-field58px · 14.5px / 600Touch 62px
Page header pill42px · padding-inline 14px 18px · gap 7pxIcon 15px
Empty state button52px · padding-inline 26px · 15.5pxPhone full-width
Desktop dialog footermin-width 128px · padding-inline 20pxPhone: flex 1 · min-height 48px
Inside a phone .modalmin-height 48px · radius 12px · 14.5px

States, precisely

Defaulttransition: all 0.15s ease
HovertranslateY(-1px)btn-lg without the lift
btn-dark hoverbackground: var(--dark-hover)
btn-ghost hover--muted · shadow 0 2px 6px rgba(24,20,14,.07)
btn-accent hoverfilter: brightness(0.94)
Pressscale(0.97) · 0.06s
Inactiveopacity 0.5 · cursor: not-allowedNo hover or press
In progress.spinner 15px · border 2px · 0.6s linearAlong with disabled
Focusoutline 2px solid var(--accent) · offset 2px.btn:focus-visible; both themes
  • Button hover isn't under @media (hover: hover); on touch, the 1px lift can stick after a tap until the next touch. Press (scale) lasts only while the finger is down.
  • The default spinner is white (rgba(255,255,255,.3) with a #fff head), for dark buttons; on btn-ghost use .spinner-dark (20px, gray).

Contrast for each variant

btn-dark12.94 : 1 · 14.62 : 1Light · dark; AAA
btn-ghost16.28 : 1 · 14.17 : 1--text on --card; AAA
btn-accent5.19 : 1 · 5.19 : 1#fff on --accent-strong; AA
btn-danger5.14 : 1 · 5.54 : 1#fff on --red-strong; AA
btn-ghost border1.32 : 1 · 1.38 : 1Decorative border; the text and shadow define the button

Why

Every variant now meets AA for normal text. btn-accent sits on --accent-strong, an orange slightly darker than the brand, so the white label stays legible; there's still at most one per page, because its job is to stand out. The delete button always has the trash icon and the consequence sentence next to it, so meaning never relies on color alone.

Right to left

  • The icon comes before the label in the DOM, and with inline-flex it sits to the right of the label in right-to-left; no reordering needed.
  • padding-inline: 14px 18px on the page header pill means less on the icon side; it's correct in both directions because it's logical.
  • A “Next” arrow inside a button gets .rtl-flip or StepArrow.

Do

In progress: disabled plus a spinner.

Don't

Just a spinner; tapping again sends a second request.

Do

The primary action goes last in the dialog footer row.

Don't

btn-dark first and Cancel after it; on desktop the footer is aligned to the end of the row, so the primary action has to come last.

Do

<Link className="btn …"> to go to another page.

Don't

<button onClick={() => router.push()}>; middle-click and “Open in new tab” are lost.

Do

Set the size with a class: btn-sm, btn-lg.

Don't

Inline height or border-radius; it misses the touch and phone rules.

Related pages

Page headerPage header pills, the 42px version of this button.Radius and shadowWhy every button is a pill.Confirmation and irreversible actionsThe red delete button and its place in the confirmation dialog.Text fieldbtn-field matches the height of a floating field.MotionRising under the pointer and shrinking under a finger.Voice and writingButton labels are verbs.Flowra design systemThe system this button is one piece of.IconsIcons beside a label, and icon buttons.Badge, pill, and switchPills match the height of btn-sm.Empty and loading statesThe empty state action and the in-progress spinner.Upgrade promptbtn-accent is the upgrade button.
PreviousService logosNextText field

Related pages

  • PageBrand kitThe Flowra mark and logo, colors, typography, clear space and minimum size, and the brand kit files to download.
  • PageDocumentationThe complete Flowra guide: actions, calendar, meetings, knowledge, files, Folio, chat, network, finance, connectors, settings and AI, each with its connections.
  • PageChangelogWhat each release added to Flowra, what got better, and what’s coming next.
  • PageContact usReach the right team: support, sales and plans, partnerships, careers, or security and privacy.
Flowra

Flowra is an all-in-one workspace for managing tasks, projects, finances, meetings, and teamwork, powered by AI to keep everything organized in one place.

Solutions for teams

  • Marketing teams
  • Product and dev teams
  • Design and content teams
  • Operations teams
  • Sales and services teams
  • Remote teams

Roles and flows

  • Project managers
  • Freelancers and consultants
  • Meeting to action
  • Actions with financial context
  • Actions with contract context
  • Brief to project delivery

With Flowra

  • All solutions
  • Pricing
  • Frequently asked questions
  • Documentation
  • Contact us
  • Brand kit
  • Design system
Crafted by Karo Studio
SecurityPrivacyTermsCookies
Version 0.16.0