shadcn.io is not affiliated with official shadcn/ui
Payment Method Expiry Billing Block for Vue
Update only the expiry of a saved card: a drawn card face with a month and a year select, the days left worked out from a fixed date, and a refusal for a month that has passed or a year too far ahead.
Installation
Overview
Let a customer fix a card that is about to lapse without ever typing its number, with this card expiry section for Vue with Ark UI. It shows the account of Tallyvale, a bookkeeping app. A hairline frame with a plus mark on each corner holds a drawn greyscale card, the brand in text and "ending 4242" with no number, and the one editable thing sits on its face: a Month and a Year Native Select. Beside it the days left come from a fixed date ("Expires Oct 31, 2026, in 16 days") with a Badge that reads Expires soon, and turn into "Covered until Oct 31, 2029" once the date changes. A month that has passed or a year more than twenty ahead is refused with the reason in a reserved line, so nothing moves. The Shine Button saves the new date, the only colored control. On a phone the card sits above the facts and the button rides a bar fixed to the foot of the panel. It's built from Native Select, Badge, Shine Button and Guides, with a CSS entrance only. For card on file pages, expiring-card reminders and any subscription app.
FAQ
How do I fill it with the customer's card?
Edit CARD: the brand, the last4 and the expires month as 2026-10. Everything else is derived from it and from AS_OF, the fixed date the page treats as today. In your app read the card from your payment provider and pass today's date from your server, so the countdown is right in every time zone.
What does it refuse, and why?
A month before the current one is refused ("That month has passed") and so is a year more than twenty ahead of today, which no card carries. The years list runs two past that limit on purpose, so you can see the refusal. The message sits in a reserved line under the facts, the Update expiry button stays focusable and answers with "Pick a valid month and year", and the facts keep showing the saved date until the new one is valid.
What does Update expiry do, and what stays local?
It saves the month and year into the drawn card and says "Expiry saved in this demo." Nothing is sent to a bank, and the page never asks for a card number or a CVC. A bank may still ask to confirm a new expiry on the next charge, which is why the page says so. In your app send the new month and year to your payment provider's update-card call and show its result.
Why are the dates fixed?
The days left are counted between two ISO dates in UTC, so "in 16 days" is the same on the server and in every visitor's time zone, and never changes between the first paint and hydration. The card's last valid day is the last day of its expiry month.
Is it accessible?
The two selects are native, named Expiry month and Expiry year and grouped under a hidden legend, so every browser and screen reader handles them. The drawing of the card is decoration around them. The state is written as a word (Expires soon, Valid) beside a small dot, never only a color, and the refusal is announced when it appears.