Filip Rut Kiddosy Design System Polski

DocsComponents

Activity card

The core of the activity list: photo, category, time, age and price.

Variants

One anatomy, optional parts. The card is a size container: narrower than 480 px it switches to the phone layout (smaller photo, title on its own line, price stacked).

Full card: date and time badges, spots left, age, travel time, price from.
With rating (optional; hidden in the app until reviews exist).
Online: a monitor icon replaces travel time; free price.
Phone layout: the same card in a container narrower than 480 px (walking time drops out).
no age limitup to 3 yrs3–6 yrsfrom 7 yrs12–15 yrsfrom 15 yrs
Age label family: six icons by age threshold (no limit, up to 3, from 3, 7, 12, 15).

States

Hover and focus are forced below. The whole card reacts, because the title link covers it: hover turns the border and the title deep blue, keyboard focus draws a 3 px ring around the card.

Hover
Focus (keyboard)
Sold out: no spots left. With a photo, the photo turns greyscale at 70 % opacity; spots text is up to the app.
Loading: OfferCardSkeleton keeps the same anatomy with pulsing blocks; the list container carries role="status" and aria-busy.
Favourites heart: rest · hover (white, heart fills with the primary colour) · keyboard focus (ring inside).

API reference

Props of OfferCard. Every text comes ready from the app’s translations; OfferCardSkeleton takes no content props.

PropTypeDefaultDescription
href, title, link string, string, link component – The title is a link stretched over the whole card; the app injects its router link.
category "all" | "education" | "sport" | "art" | "events" | "places" | "gastronomy" | "health" – Sets data-cat: the photo tint and the placeholder take the category colour.
categoryIconSrc, niche string, string – 14 px category glyph and the niche name above the title.
photoSrc, placeholderIconSrc string | null, string – 4:3 photo; without it a 32 px category glyph on the category tint.
mediaAction ReactNode – Slot on the photo for the favourites heart; empty = no heart.
day, time string – Date badge (outline) and time badge (dark).
spots, spotsTone string, "warn" | "none" "warn" Ready text with the number of spots; warn is red.
age ReactNode – An AgeLabel: age icon 14 px + label 13 / 600.
rating { value, count? } – Optional star rating with the number of reviews.
travel drive (car, walk?) | online | home – Travel time or the form of classes; hidden below 768 px, walking time hidden in the phone layout.
priceUnit, price string, string – Unit before the amount (“from”) and the amount or “Free”.
soldOut boolean false No spots left: the photo turns greyscale at 70 % opacity.

Accessibility

  • The card is an article; its title is the only link, stretched over the card, so a screen reader hears one link per card, named by the title.
  • The favourites heart sits before the title in the DOM, so Tab reaches it first; it has its own name (“Save to favourites: …”) and a 44 px target.
  • Travel icons are decorative; “By car” / “On foot” are read only by screen readers.
  • Loading: the skeleton is hidden from screen readers; the list container announces the state (role="status", aria-busy).
  • Contrast on the white card: title 20.2:1 (hover 8.4:1), meta 7.6:1, spots left 6.5:1, time badge 20.2:1. Focus ring: 3 px in the ring token, 4.0:1 against white.
  • The 2 px resting border is only a soft edge (1.1:1 against the page); the card is recognised by the white surface and the row shadow, and hover raises the border to 7.6:1.

Do and don’t

DoLet the category colour come from data-cat. The photo tint and the placeholder follow the category on their own.
Don’tDon’t paint the card in the full category colour. The category lives in the tint (12 %) and the glyph, not in a filled surface.
Kiddosy Design System