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 โ
Tabdoesn't escape to the one below, andEscapecloses one layer at a time. The same goes for the calendar in a form:Escapecloses 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,
Enterpicks,Escapecloses the list. -
Monthly entry: after Next/Back, focus moves to the new step's heading.
-
Skip to content โ the first
Tabon 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,
HomeandEndjump 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 โ
Tabto it,Enteropens the details. -
Portfolio composition chart: every slice can be reached with
Taband selected withEnter(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,
Tabstays within them, and focus returns to where you started when they close.Escapecloses 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.