Arc
ComponentsBlocksDocsPricingTry the demo
Get Pro
Introduction
Installation
Theming
Motion
AI and MCP
Changelog
Metrics dashboardPro
KPI drilldownPro
Metric explorerPro
Revenue explorerPro
MRR waterfallPro
Cohort retentionPro
Usage forecastPro
Journey flowPro
Uptime statusNewPro
Choropleth explorerPro
Connected scatterPro
Horizon chartPro
Account healthNewPro
Market terminalPro
Budget variancePro
Small multiplesPro
Line replayPro
AI chatPro
AI composerPro
AI answerPro
Model pickerPro
Model arenaPro
Prompt studioPro
Document extractionPro
Agent memoryPro
AI side panelPro
Research runPro
AI insight cardNewPro
Catch upNewPro
AI feature launchNewPro
AI search barNewPro
AI setup wizardNewPro
Call insightsNewPro
Lead scoringNewPro
Agent runPro
Agent tasksPro
Agent approvalsPro
Agent routinesPro
Agent orchestratorPro
MCP serversPro
Knowledge basePro
Eval suitePro
Agent builderNewPro
Agent galleryNewPro
SidebarPro4
Page header
Command palette
Notification center
Selection toolbarPro
Empty states
Search resultsPro
Login and sign up5, free and Pro variants
Onboarding illustrationPro
OTP input
Multi-step formPro
Two-factor setupNewPro
Magic linkNewPro
Settings pagePro
Settings commandPro
Security settingsPro
Billing overviewPro
Usage billingPro
Cancel flowPro
Onboarding surveyNewPro
Spend alertNewPro
Team membersPro
Invite peoplePro
Team directoryPro
Roles and permissionsPro
Profile pageNewPro
API keysPro
WebhooksPro
IntegrationsPro
Environment variablesPro
Domain verifyNewPro
Webhook testerNewPro
Plan comparison
Pricing calculatorPro
Usage pricingPro
Cart drawerPro
Checkout summaryPro
Live checkoutPro
Seat managerNewPro
Credit top-upNewPro
Invoice studioPro
Wallet cardPro
Delivery trackerPro
Product listingPro
Product detailPro
Activity feedNewPro
Inbox triagePro
Support conversationPro
Support widgetPro
Help centerPro
Feature votingNewPro
File upload
Media playerPro
Week calendarPro
Availability pickerPro
Project boardPro
Release readinessPro
Kanban boardPro
Smart schedulerNewPro
Task breakdownNewPro
Goal trackerNewPro
Hero section
Hero signupPro
Scroll storyPro
Spotlight gridPro
Feature bentoPro
Comparison table
Logo marquee
Studio perspectivesPro
Stats band
Changelog feed
FAQ section
Contact section
Team showcasePro
Blog grid
Site header
Site footer
CTA section
Newsletter signup
Activity terrainPro
Revenue globePro
Customer galaxyPro
Semantic zoomPro
Layout morphPro
Exploded viewPro
What’s new74 new
BlocksSmart scheduler

Smart scheduler

Pro

A scheduling card where one sentence like "Find 30 min with Maya and Leo next week, mornings" is read into chips. The three best slots are then ranked across everyone's Google Calendar and Outlook calendars, with an availability strip per person and conflicts called out. Picking a slot opens a draft invite with a Google Meet link, ready to send.

Live block · sample data

When to use

  • A scheduling assistant inside a CRM, recruiting tool, or team app that books internal meetings from one sentence.
  • Showing why a time was suggested: who is free, what conflicts, and what is tentative.
  • An AI feature demo where the result has to be checkable at a glance before anything is sent.

When not to use

  • Public booking pages where guests pick from your open times; use availability-picker or booking-pill.
  • Browsing or editing a full calendar; use week-calendar or month-calendar.
  • Picking a single date or time without other people involved; use date-picker or time-picker.

Installation

Pro source and install commands unlock with a Pro plan.

Usage

Drop it into a CRM, recruiting tool or team app as the "find a time" step. Pass `parse` for your LLM call (structured output: duration, people, range, window) and keep `findSlots` deterministic on your server (Google freeBusy or Microsoft Graph getSchedule). Each slot returns every attendee's busy blocks for that day so the strips can draw them. `onSend` creates the event (reject to show a retry), and `onPick` plus `meetLink` let you create a real Meet link before sending. With no props it plays a simulated run on a loop until someone clicks or types in the card. The sample parser and slot finder (`parseScheduleRequest`, `findScheduleSlots`) are exported as a reference.

example.tsx
1import { SmartScheduler } from "@/components/arc/blocks/smart-scheduler/smart-scheduler";2 3export function ScheduleCard({ me }) {4  return (5    <SmartScheduler6      organizer={me}7      defaultQuery=""8      timeZone="ET"9      parse={(query, signal) =>10        fetch("/api/schedule/parse", { method: "POST", body: JSON.stringify({ query }), signal }).then(async (res) => {11          if (!res.ok) throw new Error((await res.json()).message ?? "Couldn't read that request.");12          return res.json();13        })}14      findSlots={(request, signal) =>15        fetch("/api/schedule/slots", { method: "POST", body: JSON.stringify(request), signal }).then((res) => res.json())}16      onSend={(invite, signal) =>17        fetch("/api/schedule/invite", { method: "POST", body: JSON.stringify(invite), signal }).then((res) => {18          if (!res.ok) throw new Error("Not sent");19        })}20    />21  );22}
Built fromButtonCopyButtonTextShimmer

API reference

2 parts. The first is the root.

SmartScheduler

Natural language scheduling in one card. A request such as "Find 30 min with Maya and Leo next week, mornings" is read into chips (duration, people with their avatars, range, time of day), then the three best slots are ranked across everyone's calendars. Above the list, one availability strip per person (with a Google Calendar or Outlook mark) draws that day's busy blocks, and an outlined column marks the slot under the pointer, sliding as you move between suggestions. Conflicts are called out with a warning icon and a short reason ("Leo's Arch office hours is tentative") and tint the block they overlap. Picking a slot opens a draft invite in the same space: an editable title, the time, a Google Meet link with a copy button, the guests, and Send invite, which turns into Sent. With no props it plays a simulated run on a loop until someone interacts.

PropTypeDefaultDescription
defaultQuerystring"Find 30 min with Maya and Leo next week, mornings"The request in the field on first render.
placeholderstring"Find 30 min with Maya next week"Placeholder for the empty field.
organizerSchedulerPersonSofia Ramirez (sample)The person sending the invite: { id, name, avatar?, email?, calendar?: "google" | "outlook" }. Shown as "You" in the strips.
directorySchedulerPerson[]sample directoryPeople the built in parser can match by first name. Ignored when you pass parse.
parse(query: string, signal: AbortSignal) => Promise<ScheduleRequest>–Turns the request into { duration (min), people, range: { label, detail, days: { id, label }[] }, window: { id, label, start, end } } (minutes from midnight). Wire your LLM call with structured output here. Throw an Error with a short message to show it in the card. A new request aborts the signal.
findSlots(request: ScheduleRequest, signal: AbortSignal) => Promise<SlotSuggestion[]>–Returns ranked slots, best first; the first three are shown. Each is { id, day, start, end, reason, conflicts: { personId, title, tentative? }[], busy: Record<personId, BusyBlock[]> }. busy feeds the strips. An empty array shows the no time works state.
onSend(invite: InviteDraft, signal: AbortSignal) => Promise<void>–Sends { title, slot, organizer, people, meetLink, timeZone }. Reject to show Couldn't send with the button ready to retry. Without it the send is simulated and the card says nothing was sent.
onPick(slot: SlotSuggestion) => void–Called when a slot is picked and the draft opens.
meetLinkstring"meet.google.com/kfq-rvwp-zte"Video link on the draft. Create a real one in onPick (Google Calendar conferenceData) and pass it back.
timeZonestring"ET"Short time zone label shown beside the window and the invite time.
autoPlaybooleantrue without parse, findSlots and onSendPlays read, preview, pick and send on a loop. Stops for good on the first click or key press in the card, pauses off screen, and is off under reduced motion.
classNamestring–Class on the root element.

BusyBlock

One event on an attendee's day, as drawn in the strips.

PropTypeDefaultDescription
startRequirednumber–Minutes from midnight.
endRequirednumber–Minutes from midnight.
titleRequiredstring–Event title, used in the block's tooltip, the strip's label and conflict reasons.
tentativeboolean–Drawn with a dashed outline and treated as a soft conflict.

Keyboard interactions

Enter
In the field, reads the request and finds times.
Tab
Moves from the field to Find times, then to the suggested slots, or through the draft's title, copy link, Back and Send invite.
Arrow uporArrow down
Moves between the suggested slots; focusing a slot previews it in the strips.
EnterorSpace
On a slot, opens the draft invite.
Escape
In the draft, goes back to the suggestions.

Accessibility

  • The field is a labeled search form, the chips are a list named What was understood, and the slots are a list of buttons whose text carries the day, the time and the reason.
  • Each strip is an image with a label listing that person's events in the window, with tentative ones marked, or free.
  • Conflicts are never color alone: a warning icon plus a reason in words, and a dashed outline for tentative events.
  • Reading, the parsed request, the number of times found, the draft and the send result are announced in a polite status region; the demo says nothing was sent.
  • Pointer focus draws no ring; keyboard focus shows Arc's shared focus ring.

Motion

  • Chips fade in from 2px, 40ms apart. Reading and checking calendars show a short shimmer on the label.
  • The slot highlight and the strip column slide together on a critically damped spring (0.24s, no bounce) as the pointer or focus moves; busy blocks crossfade when the day changes.
  • Suggestions, states and the draft share one fixed height and swap with a single crossfade (out 100ms, in 160ms), so the card never changes size. Send invite turns into Sent through the button's own label crossfade.
  • The demo loop pauses off screen. Reduced motion drops the loop and the travel and opens on the ranked times.

Responsive behavior

  • Holds from 360px to 600px. Below about 460px the button keeps only its icon, chip details hide and the name column narrows; below 400px the people chip shows avatars only.
  • Long names, reasons and links truncate with an ellipsis; nothing wraps, so rows keep their height.

Performance

  • Pure React and CSS with motion for the highlight, column and crossfades. No canvas, no timers beyond the demo script, and the loop stops off screen.
  • Strips render only the blocks inside the time window.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Use parse for the LLM step (structured output with duration, people ids, range, window) and keep findSlots deterministic: query free/busy (Google Calendar freeBusy, Microsoft Graph getSchedule) and score slots server side.
  • Return busy blocks for every attendee on each slot's day so the strips can draw them; titles can be "Busy" when you only have free/busy access.
  • The built in parseScheduleRequest and findScheduleSlots are exported and work on the sample calendars; they are a reference, not a production parser.
/components/blocks/smart-scheduler/markdown

The full library index for assistants is at /llms.txt.

Related

Availability pickerProBlockFind a meeting time across people and see the choice come together.Week calendarProBlockA week calendar where you drag to create, move, and resize events, with color coded calendars, day and agenda views, and swipes on phones.Booking pillProComponentOne pill that reshapes through party size, date, time, and a ticket.Meeting summaryProComponentAn AI meeting notes card: the header shows the Google Meet or Zoom mark, the attendees and the duration. Summary, Decisions and Action items stream in after a short summarizing pass. Hover any line to see the transcript quote it came from, then check off action items or send them to Linear or Notion.Smart form fillProComponentA paste-to-fill form card where AI reads an email signature or messy notes and fills a contact field by field. Each value flashes in with a confidence dot, its source lights up in the pasted text, low-confidence guesses ask for review, and Undo puts the old values back.Date range pickerComponentA range picker that grows from its trigger into two months with presets and a stretching range highlight.
PreviousAI setup wizardNextTask breakdown
Arc · 129 block pagesllms.txt

On this page

  • Preview
  • When to use
  • When not to use
  • Installation
  • Usage
  • API reference
  • Keyboard
  • Accessibility
  • Motion
  • Responsive behavior
  • Performance
  • Notes for AI
  • Related
View as Markdown

Duration, people, range and time of day

AvailabilityET

Ranked times across everyone’s calendars appear here