Skip to content

Components / Sections

Visit Card

Where to find a studio, a shop or a counter, as one card in a colour block: a drawn map with a pin, the address with a directions link, the opening hours for the week, the ways to get in touch, and above them a live line that says whether it is open now and until when (or when it opens next), with the time where the place is. Today's row of the week is marked. The live line is a small script reading the hours in the place's own time zone; without JavaScript the week reads as it is.

Live demo

Visit

Come and see the kiln

Your street 12Your city
Directions
Opening hours
MondayClosed
Tuesday10:00–18:00
Wednesday10:00–18:00
Thursday10:00–18:00
Friday10:00–19:00
Saturday10:00–17:00
SundayClosed

Closed on public holidays.

Live, from the library itself, at full size: scroll, hover, navigate away and back. The demo is never gated.

Variants · each row writes the attribute the prop writes; the section's own CSS answers

density

Measured

JavaScript of its own

1006 B raw

626 B gzip.

Uses the shared runtime (1.9 kB raw, once per site). With those included: 2.7 kB raw.

CSS 11.0 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.

Browser support

Baseline · widely available

every browser.

Install Pro

The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:

terminal
npx shadcn@latest add @moonarc-pro/visit-card
src/pages/index.astro
---
import VisitCard from '@/components/moonarc/pro/VisitCard.astro';
---
<VisitCard
  address={['Your street 12', 'Your city']}
  directions={{ href: 'https://www.openstreetmap.org/', label: 'Directions' }}
  timezone="Europe/Lisbon"
  hours={[
    { day: 'mon', label: 'Monday' },
    { day: 'tue', label: 'Tuesday', open: '10:00', close: '18:00' },
    { day: 'wed', label: 'Wednesday', open: '10:00', close: '18:00' },
    { day: 'thu', label: 'Thursday', open: '10:00', close: '18:00' },
    { day: 'fri', label: 'Friday', open: '10:00', close: '19:00' },
    { day: 'sat', label: 'Saturday', open: '10:00', close: '17:00' },
    { day: 'sun', label: 'Sunday' },
  ]}
  contacts={[{ label: 'Email', value: 'hello@your-studio.com', href: 'mailto:hello@your-studio.com' }]}
>
  <span slot="headline">Come and <em>see the kiln</em></span>
</VisitCard>

Without a key the registry answers 401 with an upgrade message.

Props

PropTypeDefaultDescription
addressstring[]noneThe address, one line an entry, in an address element.
hours{ day: 'mon' … 'sun'; label: string; open?: string; close?: string }[]noneThe week; open and close in 24-hour time, both unset for a closed day.
timezonestringnoneThe place's IANA time zone, e.g. Europe/Lisbon: the live line and today's row read the hours in it, wherever the reader is.
eyebrowstringnoneA short line above the heading.
headlinestringnoneThe heading. Slot "headline" wins and may hold an <em>, set in the emphasis face and colour.
directions{ href: string; label: string }noneA link to a map.
contacts{ label: string; value: string; href?: string }[]noneWays to get in touch: an email, a phone.
notestringnoneA line under the week: holidays, appointments.
openTextstring'Open now, until {close}'The live line while open.
closedTextstring'Closed now, opens {day} at {open}'The live line while closed; {day} is todayWord, tomorrowWord or the day's label.
todayWordstring'today'The word for today in the live line.
tomorrowWordstring'tomorrow'The word for tomorrow in the live line.
closedLabelstring'Closed'The word for a closed day in the week.
hoursLabelstring'Opening hours'The week table's caption, for a screen reader.
timeLabelstring'Local time'The words a screen reader hears before the time.
block1 | 2 | 3 | 4 | 52The colour block the card paints.
level2 | 32Heading level.
density'compact' | 'cozy' | 'roomy''cozy'Block padding ×0.8 / ×1 / ×1.25 through --ma-density.

Theming and overrides

The section reads the theme contract (shadcn's variable names with the base tokens as fallback), so a pasted theme or one --ma-brand recolours it. Its class names are the override surface and stay stable; a named slot replaces the matching prop with your own markup.

Classes

.ma-visit.ma-visit__address.ma-visit__card.ma-visit__clock.ma-visit__contact-label.ma-visit__contacts.ma-visit__directions.ma-visit__dot.ma-visit__eyebrow.ma-visit__halo.ma-visit__headline.ma-visit__hole.ma-visit__hours.ma-visit__info.ma-visit__live.ma-visit__map.ma-visit__minor.ma-visit__note.ma-visit__park.ma-visit__pin.ma-visit__roads.ma-visit__water

Slots

slot="eyebrow"slot="headline"

Reduced motion

The pin's halo does not breathe; the live line and the time still update.

With ClientRouter

Binds once per swap through the runtime's onMount; the half-minute timer stops when the page is swapped away.

Why it is built this way

Replaces: Store locator cards (Shopify themes) · Opening hours widgets. See the migration table.

Dotted Map

Backgrounds

A world map drawn as a grid of dots, with markers that pulse.

every browseralways

Contact · sample page

Write to the team.

Sample channels on the left. The form on the right is real and sends nothing here: fill it in and watch the button.

Email (sample)
hello@studio.example
Phone (sample)
+1 555 0100
Office (sample)
1 Sample Street, Springfield

Demo: nothing is sent.

A contact section in two columns: the ways to reach you (email, phone, office) on one side, a form that really sends on the other.

Chrome 135 · not Firefox · Safari 27click

The foot of a maker's site, made like the label sewn into what they make: a panel in a colour block with a stitched edge, the name large (a second part in the emphasis face), the link columns, a row of care symbols drawn as line icons with their words (how to wash it, that it goes in the oven, that it is mended for free) and a few small lines in the mono face.

every browserhover

The next batch, as one colour block: the product drawn large (ProductArt) under a round date stamp, and beside it the heading, a line, how many of the batch are spoken for (a count, and a bar that fills as the panel comes into view), three facts in the mono face and two actions.

Chrome 115 · not Firefox · Safari 26scroll

Also: view transitions · how costs are measured · browser support · accessibility policy · five-minute setup · MCP for agents · this page as Markdown