Components / Clinical

Medication schedule

A day of doses on a 24-hour timeline, with a checklist to mark each one taken or skipped and warnings for interactions you supply.

Medication schedule
Medication schedule, Monday, October 19, 2026
  1. Levothyroxine 75 mcg

    On an empty stomach

    Within the separation window of Calcium carbonate at 08:30

  2. Calcium carbonate 500 mg

    With meals

    Within the separation window of Levothyroxine at 07:00

  3. Metformin 500 mg

    With breakfast and dinner

  4. Ibuprofen 200 mg

    Mondays and Thursdays, for 2 weeks

  5. Warfarin 5 mg

  6. Calcium carbonate 500 mg

    With meals

  7. Metformin 500 mg

    With breakfast and dinner

Interaction warnings come only from the data this schedule is given. This is not medical advice.

Your app state

Step through the days or mark doses taken or skipped. These callbacks can save to your own records.

Date: 2026-10-19

{}

Illustrative example data, not a treatment plan or a complete list of interactions.

Installation

In a project set up as in Installation, run:

bunx shadcn@4.22.1 add https://organui.com/r/medication-schedule.json

Or by name: bunx shadcn@4.22.1 add @organui/medication-schedule.

The source installs into your configured UI directory, along with shadcn's alert, button and empty if you do not have them yet. It uses your existing theme tokens and installs no global styles, date library or drug database.

View registry item JSON

Usage

"use client"
import { useState } from "react"
import {
  MedicationSchedule,
  type DoseStatus,
} from "@/components/ui/medication-schedule"

const medications = [
  { id: "levothyroxine", name: "Levothyroxine", dose: "75 mcg", times: ["07:00"] },
  { id: "calcium", name: "Calcium carbonate", times: ["08:30", "19:00"] },
]
// From your own interaction source. None are bundled.
const interactions = [{
  id: "levothyroxine-calcium",
  medicationIds: ["levothyroxine", "calcium"],
  severity: "moderate" as const,
  summary: "Calcium can reduce levothyroxine absorption.",
  separationHours: 4,
}]

export function Schedule() {
  const [date, setDate] = useState("2026-10-19")
  const [doseStatus, setDoseStatus] = useState<Record<string, DoseStatus>>({})
  return <MedicationSchedule medications={medications}
    interactions={interactions} date={date} onDateChange={setDate}
    doseStatus={doseStatus} onDoseStatusChange={setDoseStatus} />
}

Each medication has a unique id, a name and its local dosing times as "HH:MM". Optional days (0 for Sunday to 6 for Saturday), start and end dates limit when it is due. Dates are "YYYY-MM-DD" calendar days with no time zone, so the schedule renders the same on the server and the client. Invalid times, dates or repeated IDs throw an error.

The date is controlled. Pass onDateChange to show previous and next day buttons. Pass now from client state to mark the current time on the timeline; the component never reads the clock itself.

Dose tracking

Dose status is a map from dose keys, such as levothyroxine@2026-10-19T07:00, to "taken" or "skipped". Missing doses are still to take. With onDoseStatusChange, each dose in the list becomes a button that cycles from to take, to taken, to skipped and back; the callback receives the whole new map for you to store. Without it the status is shown as text.

The timeline is a visual summary and is hidden from assistive technology. The ordered dose list carries the same times, names, statuses and warnings, and each status button names its medication and time.

Interaction warnings

The component ships no drug database and makes no clinical judgement. It shows only the interactions you pass, each naming two or more medication IDs, a severity of minor, moderate or major, and a summary. A warning appears on days when every medication it names is due, most severe first, and major ones get a destructive border and title. Give separationHours to flag same-day doses of those medications that are closer than that, on the timeline and in the dose list.

Source your interactions from a reviewed clinical service, and keep the default disclaimer or replace it with your own through disclaimer. Doses across midnight are not compared.

Customize

Set label for the accessible name, locale for the date heading, className for the outer container and color on a medication for its swatch and markers. The helpers dosesOn, activeInteractions, doseConflicts and nextDoseStatus are exported for your own views, such as reminders or a weekly summary.

A display component, not a medical device. No reminders, notifications, as-needed dosing, titration or dose calculations. Built on shadcn's Base UI components; compatibility with Radix-based presets is not claimed.