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/Fundamentals

Accessibility

Every component works with a keyboard, tells screen readers what it is, is sized for fingers, and respects a preference for reduced motion. These are built into the components themselves so no page has to remember them.

On this page

  1. Focus
  2. Name and role
  3. Touch target size
  4. Hover is a mouse state
  5. Reduced motion
  6. Contrast and color
  7. Token contrast
  8. Focus rings, precisely
  9. Roles the components actually set
  10. Keyboard

Focus

The focus ring is never removed. Controls that draw their own surface, like selection chips, color swatches, and the time column, get a 2px orange ring with a small offset from the edge on focus-visible; every .btn and every .toggle switch has the same ring, in both themes. The rest keep the browser's own ring. The ring shows only for keyboard use, not on every click. Fields also show focus with the color of the line beneath them. After you pick an option in a menu, focus returns to the button that opened it so the keyboard doesn't lose its place. A dialog also moves focus inside itself when it opens, keeps Tab cycling within it, and returns focus to the button that opened it when it closes.

The first thing Tab reaches on every public page is the "Skip to main content" link.

Live example
Skip to main content

Press Tab and watch the focus ring on each control.

Name and role

  • A button with only an icon gets aria-label and title.
  • A button that opens a menu or list has aria-haspopup="listbox" and aria-expanded; the sidebar button also has aria-controls.
  • The current page link in navigation gets aria-current="page".
  • Toasts appear in a region with role="status" and aria-live="polite".
  • The upgrade prompt has role="note", and the six-digit verification code is read with its group label.

Touch target size

On phones, primary controls are at least 40px: btn-sm grows to 40, menu rows in a sheet are 48px, stepper buttons are 40, and fields on touch screens are 48px with a 16px font, which stops iOS from zooming the page on focus. The on/off switch keeps its own look, and an invisible ring enlarges its touch area.

Live example
36 → 40pxbtn-sm
40px.seat-step
Copy link
48px.sheet-menu
52pxbtn-lg

Hover is a mouse state

On iOS and Android, hover sticks to the last element after a tap. That's why row hover color is defined under @media (hover: hover), and on touch, :active gives the same feel only while the finger is on the screen. No information lives behind hover alone.

Reduced motion

When your system asks for prefers-reduced-motion, a global rule brings all animations and transitions close to zero. Motion built in JavaScript, like the ripple on a field's underline and the mark's wave, checks the same thing before starting. Instead of sliding up from the bottom, dialogs simply fade.

Live example

Your device: ·

@media (prefers-reduced-motion: reduce)

Contrast and color

Color is never the only carrier of meaning: a red counter has a number, a field error has a sentence, and a toast has full text next to its colored dot. Primary text on the background has full contrast in both themes; tertiary text is only for details that don't need to be read.

Token contrast

Ratios are calculated from the hex values in globals.css. AA requires 4.5 for normal text and 3 for large text (24px, or 18.66px bold); AAA requires 7 and 4.5 respectively. For control lines and borders (non-text) the threshold is 3.

--text on --bg14.94 : 1 · 15.45 : 1Light · dark; AAA
--text on --card16.28 : 1 · 14.17 : 1AAA
--text-secondary on --card5.14 : 1 · 5.80 : 1AA in both
--text-secondary on --bg4.72 : 1 · 6.32 : 1AA in both
--text-secondary on --muted4.64 : 1 · 5.33 : 1AA; .pill and .badge-soft
--text-tertiary on --card2.16 : 1 · 2.99 : 1Fails in both; non-essential details only
--dark-contrast on --dark12.94 : 1 · 14.62 : 1AAA
#fff on --accent-strong5.19 : 1 · 5.19 : 1AA; btn-accent and badge-accent
--accent-text on --card5.30 : 1 · 6.19 : 1AA; orange text
--accent-text on --bg4.87 : 1 · 6.75 : 1AA
--accent on --card3.63 : 1 · 5.04 : 1Non-text; meets the 3 threshold. Surfaces and graphics, not text
#fff on --accent3.63 : 1 · 3.37 : 1Large text only; avatars and icons, not labels
--red on --card5.14 : 1 · 4.55 : 1AA in both
--red on --bg4.72 : 1 · 4.96 : 1AA in both
#fff on --red-strong5.14 : 1 · 5.54 : 1AA; btn-danger and badge-count
--green on --card5.40 : 1 · 6.43 : 1AA in both
--border-strong on --card1.32 : 1 · 1.38 : 1Below 3; the line under a field at rest

Why

This table is honest, not marketing. Secondary text, red and green text, and every white label on an orange or red surface now meet AA for normal text in both themes. The brand orange (--accent) stays a surface and graphics color: the focus ring, checkmarks, the tab underline, and dots, which have a threshold of 3, and 3.63 is enough for them. Wherever orange is text, --accent-text is used, and wherever a white label sits on an orange or red surface, --accent-strong or --red-strong. The only remaining failure is --text-tertiary (2.16 to 1 in light), which is only for non-essential details; no necessary information is conveyed by it alone.

Focus rings, precisely

The :where() rule has zero specificity, so any control that defines its own ring wins. The floating field has no ring because the whole field changes on focus: an orange underline, an orange icon scaled 1.35 times, and an orange label above the edge.

Shell controls2px solid var(--accent) · offset 2px:where() on .icon-btn, .dropdown-option, .dropdown-toggle, .side-item, .dock-item, .assist-trigger, and more
.toggle2px solid var(--accent) · offset 2pxDisabled: opacity 0.45
.select-chip2px solid var(--accent) · offset 1px
.brand-swatch2px solid var(--accent) · offset 2px
.btn2px solid var(--accent) · offset 2px.btn:focus-visible; both themes
Floating fieldoutline: noneInstead, an orange underline, icon, and label
Skip link.skip-link · top 8px · 12.5pxSlides down from translateY(-250%) on focus

Roles the components actually set

  • OptionList: role="listbox" with aria-activedescendant; each row has role="option" and aria-selected, plus aria-disabled when disabled.
  • DropdownField and SelectMenu: aria-haspopup="listbox", aria-expanded, and aria-label equal to the label.
  • Floating on phones: role="dialog", aria-modal="true", and aria-label equal to the sheet title.
  • ActionMenu: role="menu" with aria-label set to the title; rows are role="menuitem", or role="menuitemradio" with aria-checked when they have active, and the divider is role="separator". The trigger button automatically gets aria-haspopup="menu" and aria-expanded.
  • Dialog and DialogShell: role="dialog", aria-modal="true", and aria-labelledby pointing to the title; ConfirmDialog has the same with role="alertdialog". All three use useDialogA11y to keep focus inside and return it to the trigger on close.
  • Toaster: role="status" and aria-live="polite"; the region is created with the first toast.
  • SkeletonRows: aria-busy="true" and aria-label “Loading...”.
  • CodeInput: role="group" with aria-label, and each box has its number as its name.
  • PlanGate: role="note"; the icon is aria-hidden.
  • Sidebar: aria-label “Navigation”, aria-current="page" on the current destination, and aria-expanded on the expand and collapse button.

Keyboard

Picker↑ ↓ · PageUp/PageDown (8) · Home/End · Enter/Space · typeaheadHome, End, Space, and type-ahead (600ms) only while focus is on the list
Open the list↑ / ↓ on the button
Close the panelEscapeTop panel only
DialogEscape · clicking the backdrop · ✕
Dialog focusdata-autofocus → first focusable → dialogTab and Shift+Tab cycle inside; on close, focus returns to the trigger
Action menu↑ ↓ (wrap) · Home/End · typeahead · Enter/Space · Escape · TabEscape returns focus to the button; Tab closes
Verification code← → · Backspace · paste
PasswordEye button tabIndex=-1Not in the Tab order

Related pages

MotionReduced motion is applied to all animations in one place.PickerFull keyboard support in pickers: arrows, Home and End, Enter and Escape.Phone layoutTouch targets and hover alternatives on phones.ToastToasts are announced to screen readers with aria-live.DialogEscape closes only the topmost layer.ColorToken contrast in both themes.
PreviousNumbers and datesNextColor

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