macbetter

macOS, iPadOS and iOS.
One web framework.

A set of React components that look and behave like Apple’s own controls. Theme it to any brand, ship it to every screen, and let ui-sdk handle the keyboard, focus and accessibility.

Get startedBrowse components
TaskOwnerDueStatus
Write the theming guideMaya ChenMeNov 18In progress
Right-to-left screenshotsTheo ParkTheoTodayIn progress
Contrast pass on NebulaAna LimaAnaTodayIn review
Record the component walkthroughTheo ParkTheoNov 19Not started
Publish release notesMaya ChenMeNov 21Not started
Ship the floating tab barKofi MensahKofiNov 12Done
Audit focus ringsAna LimaAnaNov 10Done

Projects

Show completed
  • 591components, from push buttons and menus to windows, sheets and the Dock
  • 3platforms from one codebase: macOS, iPadOS and iOS
  • 4built-in themes: Ember, System, Nebula and Graphite
  • 12artwork styles, drawn from a seed for covers and placeholders

Platforms

Emulate all Apple interfaces using the UI SDK.

Put data-platform on any element and the components inside take that platform’s sizes and habits. Here is the same settings form three times, with no changes to its code.

Notifications
Allow notifications
Badge app icon
Show previews
Alert volume
macOS. 13pt text, 28px controls, hover states and compact rows.
Notifications
Allow notifications
Badge app icon
Show previews
Alert volume
iPadOS. Touch-sized rows and capsule controls, with hover kept for the trackpad.
Notifications
Allow notifications
Badge app icon
Show previews
Alert volume
iOS. 17pt text, 44pt targets, inset grouped lists, no hover.

Themes

Easily customize themes for your brand.

A theme answers about a dozen questions: the accent, the ink, the surfaces, a tint for fills, a radius scale and a font. Every other color, shadow and corner derives from those seeds, in light and dark.

acme.css
[data-theme="acme"] {
  --mb-accent: light-dark(#6d3df5, #9b7bff);
  --mb-accent-secondary: light-dark(#c026a8, #ff7ad9);
  --mb-ink: light-dark(#14102b, #f3f1ff);
  --mb-bg: light-dark(#ffffff, #100c24);
  --mb-tint: light-dark(#66618a, #9a94c9);
  --mb-radius-scale: 1.15;
}
EmberOrange on racing green.
SystemApple’s blue on true grays.
NebulaViolet on cool ink, rounder corners.
GraphiteMonochrome and squared off.

Components

Every UI element from the Human Interface Guidelines (and more).

Menus, sliders, calendars, alerts and command palettes that look and behave like the native control, at a glance and under the hand. Every tile below works.

Menu

November 2026

SMTWTFS
1234567
891011121314
15161718192021
22232425262728
2930
Calendar
Switch
Segmented control
72%Battery
88%Storage
Gauge
Syncing 24 files…
Activity indicator
Command palette
Alert

Materials and motion

Glass materials and motion straight from Swift UI, built for the web.

Bars, sidebars and menus are translucent and blur what’s behind them, and turn solid when someone asks for less transparency. Movement runs on spring curves, shipped as CSS tokens.

Ultra thin
Thin
Regular
Thick
Liquid Glass
Materials. Ultra thin to thick for surfaces, Liquid Glass for floating controls.

--mb-spring-bouncyOnly after a gesture that carried momentum.

Springs. Pick one, then tap the track. The curve is read from the token.

Accessibility and agents

Built on ui-sdk.
Ready for people and agents.

macbetter adds the Apple look and feel. Behavior comes from ui-sdk, shadcn’s headless component library, so the hard parts of every control are already built and tested.

  • Keyboard. Arrow keys, typeahead, Escape and shortcuts work the way each control works on a Mac.

  • Focus. Dialogs and menus move focus in and give it back. Keyboard focus shows the accent ring.

  • ARIA. Roles, names and states come from ui-sdk, so screen readers hear a switch as a switch.

  • Right to left. Layouts use logical properties and mirror their glyphs. Set dir="rtl" and it flips.

  • Server rendering. Components render on the server, and the platform is set before the first paint.

  • Agents. ui-sdk’s agent bridge lists every control by name and state, and acts through the same API people use.

pnpm add macbetter @ui-sdk/react @ui-sdk/core
join-network.tsx
import { Button } from "macbetter/button"
import { Switch } from "macbetter/switch"

export function JoinNetwork() {
  return (
    <form data-theme="nebula" data-platform="ios">
      <label>
        Wi-Fi
        <Switch defaultChecked />
      </label>
      <Button variant="filled" type="submit">
        Join network
      </Button>
    </form>
  )
}

Get started

Extremely easy to implement

Install the package, import a button, and add the rest as you need them. Every component has a page with live examples for all three platforms.

Read the docs