Skip to main content

Accessibility

GrapeVest targets WCAG 2.2 level AA. This page describes what that means in practice and what already works.

Keyboardโ€‹

Every feature works without a mouse.

  • Dialog on top of a dialog (e.g. the emoji picker over the family panel): the keyboard works in the topmost one โ€” Tab doesn't escape to the one below, and Escape closes one layer at a time. The same goes for the calendar in a form: Escape closes just the calendar, not the whole form.

  • Calendar is a named dialog; on open, focus goes to the selected (or today's) day, and every day has a full date name.

  • Ticker suggestions: โ†‘ โ†“ move, Enter picks, Escape closes the list.

  • Monthly entry: after Next/Back, focus moves to the new step's heading.

  • Skip to content โ€” the first Tab on every page (the app, the start page, legal pages) reveals a link that jumps straight to the content, past the navigation.

  • Visible focus โ€” whatever you reach with the keyboard gets a clear outline in the accent colour (form fields: a ring). Mouse clicks don't draw it.

  • Tabs (Dashboard, Analysis, Portfolio): the โ† โ†’ arrows switch tabs, Home and End jump to the first and last one. Focus moves with the selection, so a screen reader announces the new tab right away.

  • Positions table (Portfolio, "Investment details" module on desktop): the position name is a button โ€” Tab to it, Enter opens the details.

  • Portfolio composition chart: every slice can be reached with Tab and selected with Enter (or Space). Each slice is named with its share and amount, e.g. "Bonds: 60%, 60,000 zล‚".

  • Dialogs and panels (position details, instrument picker, partner access confirmation): focus moves inside when they open, Tab stays within them, and focus returns to where you started when they close. Escape closes panels, but not the key-access confirmation โ€” that decision has to be made with a button.

  • Wizards (onboarding, broker import, adding an account, editing a goal): after moving to the next step, focus lands on the new view's heading, so the keyboard and screen readers don't get lost when the button disappears.

  • The browser tab title names the current screen ("Portfolio ยท GrapeVest").

Screen readersโ€‹

  • Page language follows the app language (PL, EN, DE), so a screen reader uses the right pronunciation.
  • Form errors are announced immediately and point to the field they refer to (e.g. a wrong confirmation password, a missing goal name). The "month saved" confirmation is announced as a status message.
  • Form fields have labels, not just placeholder hints.
  • The income and expenses chart has a hidden table with the amounts for each month โ€” the same data the bars show visually.
  • A change in value is never shown by colour alone: it always comes with a sign (+/โˆ’) or an arrow.

Forms and validationโ€‹

  • Numbers in fields look the way you type them: with the decimal separator of your language, without technical tails like "6.890000000000001".

  • Amount fields accept numbers only: digits, comma or dot, and spaces. Letters, "zล‚" and other characters simply don't get typed (including on paste). A minus sign is allowed only where a value can be negative (assumed inflation for bonds).

  • Errors show at the field: after leaving a field with an invalid value the border turns red and a message appears below it (e.g. "Enter a number", "At most 100" for percentages). Screen readers announce it, and it disappears once the value is valid.

  • Required fields (e.g. an asset or custom position name) say "This field is required" when left empty.

  • Saving with an error is blocked: the entry, position, asset and goal forms won't save an invalid value โ€” they show what to fix.

  • Every field has a visible label above it โ€” including the goal name and source, the quantity and price of a crypto transaction and the password when deleting the account. The hint inside the field (e.g. "e.g. Holiday") is only an example and disappears as you type.

  • The calendar (goal deadline, bond purchase date, date of birth) stays open when you click its header or an empty spot in the window.

  • Deleting the account: after "Delete account" the cursor goes straight to the password field, and after "Cancel" it returns to the button.

  • Confirmations (clear the plan, load the sample, delete a position): focus lands on the warning text โ€” not on the red button, so Enter deletes nothing โ€” and after "Cancel" returns to the button. After saving a position in Portfolio, focus returns to its header.

Contrastโ€‹

  • Status colours (on track / needs attention / problem: ritual markers, the health score, progress bars) come from the theme, so light and dark each have their own tuned contrast. Warning buttons with white text use a darker amber (โ‰ฅ 4.5:1). Text has at least 4.5:1 contrast against its background โ€” in both light and dark mode.

Colour doesn't judge. Green and red only mean a value went up or down (gain, monthly change). Debt uses the normal text colour with a minus, the health score and its parts use a single accent colour (a word describes the state), and warnings โ€” an exceeded budget, an ambitious goal deadline, negative living costs โ€” are amber, with no red alarm.

  • Notices (warning, error, confirmation) share one set of colours checked for contrast in both themes โ€” every dialog and form looks the same.

  • The smallest text in the app is 11 px (badges, chart axes, labels); previously some badges and captions were 9โ€“10 px. Screen tabs use the regular body size (14 px).

  • Small text (up to 12 px) is never semi-transparent โ€” including on the purple net worth card. Weight and size separate primary from secondary, not a faded colour.

  • Small badges keep 4.5:1 too: "auto" next to recognised brokers, the notification count and the "Refresh" button for a new app version.

  • Grey metadata (dates, captions, labels) is slightly darker in light mode than the stock palette, so it stays readable on a phone in daylight.

  • Gain, loss and warning colours adapt to the theme: darker green, red and amber on a light background, lighter shades on a dark one.

  • On the purple net-worth card and on buttons, white text sits on the darker part of the purple, and captions are no longer dimmed.

  • Purple links, text actions and the active navigation item use a lighter shade in dark mode, and light backgrounds (e.g. IKE/IKZE badges) have dark counterparts โ€” nothing glows as a light patch on a dark screen.

An automated test checks the colour values, so a palette change that would drop contrast below the threshold does not pass.

Phone and tabletโ€‹

  • Small text buttons ("Where does this score come from?", "How we calculate return", "Refresh" quotes, show password) have a touch area of at least 44 px even though they look smaller; the value change in Portfolio is 24 px because another button sits right above it.
  • Monthly history on a narrow phone (< 390 px) shows income, saved and living costs as "label โ€” amount" rows, and the month name doesn't wrap.
  • Bottom edge of the screen: in demo mode the content ends above the "Demo mode" pill, and the new-version notice appears above it, not underneath. Its buttons, "Exit" in demo mode and the list/chart toggle in history have a 44 ร— 44 px touch area; category colour swatches are 36 px.
  • Choosing an account or asset opens above the whole page; scrolling the list doesn't move the page underneath.
  • Form fields use a 16 px font, so an iPhone doesn't zoom in every time you tap a field (e.g. in the monthly entry).
  • Small buttons (e.g. "Today" in the date picker, "+ transaction", removing a transaction, filters) have a touch area of at least 44 ร— 44 px, even when they look smaller.
  • Loans in the monthly entry: on a narrow phone the instalment and overpayment fields move below the loan name instead of squeezing it to nothing.
  • Very large net-worth amounts get a smaller font step instead of being cut off. The equity note next to a loan wraps, so the loan amount is always visible.
  • The positions table on desktop scrolls sideways when space runs out instead of clipping columns.
  • Tablets (from 768 px) get a wider content column instead of a narrow phone strip in the middle of the screen; the top-right buttons (settings, partner invite, notifications) stay aligned with that column.
  • Side panels keep their header with the close button in place while the content scrolls. The instrument picker has its own โœ• button.

Motionโ€‹

Animations are short and show what changed (a panel slides in from the side, a progress bar fills). If you turn on "Reduce motion" in your system settings:

  • nothing slides or scales, and looping animations (e.g. the landing page background) stop,
  • panels and cards appear with a short fade, so you can still tell something opened,
  • scrolling to a place on the page is instant.
  • the opening animation (the grape cluster) becomes a short fade.

Progress bars and chart bars fill without recalculating the page layout, so the animation doesn't stutter on a phone. The scrolling strip of broker logos on the start page can be stopped with the "Pause animation" button below it; it also stops while you hover over it or reach it with the keyboard.

Themeโ€‹

The theme (light, dark or system) is applied before the page is drawn, so there is no flash of a light screen when you start in dark mode. The browser and installed-app bar takes the app background colour of the chosen theme.

This needs no change to the Content Security Policy: the theme script carries the same one-time nonce as the rest of the page's scripts and sends nothing โ€” it only reads preferences stored on the device.