suiss/uim · React Native Component

Widget

A rounded card for glanceable information in fixed widget sizes, with an optional drag handle to resize it.

Widget is an open-source mobile component from suiss/uim for React Native and Expo, with SwiftUI and Jetpack Compose versions built from the same design tokens. The @esuiss/uim CLI copies its source into your project, so you own the code.

iOS
Widget on iOS in light mode

Widget is a View with a rounded, filled surface. It comes in four fixed sizes, small (168×168), medium (352×168), large (352×352) and extra-large (720×352), or auto, which fills its parent. Fixed sizes animate with Reanimated when the size changes.

With resizable, a corner handle lets the user drag the widget between sizes: a dashed outline previews the size it will snap to, a selection haptic plays on each new snap, and double-tapping the handle returns to the initial size. Only sizes that fit the available width are offered. Set align="center" to center the content, which also hides WidgetAction.

Installation

$ pnpm dlx @esuiss/uim@latest add widget

The CLI also adds what it builds on: Icon, Text.

Manual

  1. Install the dependencies:
npx expo install cn phosphor-react-native react-native-gesture-handler react-native-reanimated react-native-svg react-native-worklets
  1. Add the pieces it builds on: Icon, Text, and the primitives components/primitives/haptics.tsx.

  2. Copy the source into components/ui/widget.tsx:

uniwind/components/ui/widget.tsx
import { cn } from "cn"
import type { IconProps as PhosphorIconProps } from "phosphor-react-native"
import * as React from "react"
import {
  type AccessibilityActionEvent,
  I18nManager,
  View,
  type ViewProps,
} from "react-native"
import { Gesture, GestureDetector } from "react-native-gesture-handler"
import {
  Easing,
  ReduceMotion,
  runOnJS,
  useAnimatedStyle,
  useSharedValue,
  1. Update the import paths to match your project.

Usage

import { Widget, WidgetHeader, WidgetIcon, WidgetTitle, WidgetAction, WidgetDescription, WidgetValue, WidgetContent, WidgetFooter } from "@/components/ui/widget"
<Widget size="small" align="start">
  <Weather />
</Widget>

Compose the content from WidgetHeader (with WidgetIcon, WidgetTitle and WidgetAction), then WidgetValue, WidgetDescription or WidgetContent, and WidgetFooter, which sticks to the bottom. Plain strings passed to WidgetContent and WidgetFooter are wrapped in Text.

The size is uncontrolled with defaultSize, or controlled with size and onSizeChange. Use sizes to limit which sizes the user can pick. A non-resizable widget defaults to auto; a resizable one defaults to small.

useWidget returns the current size and align so custom content can adapt to the widget size.

Examples

Sizes

The four fixed sizes side by side.

iOS
Widget (sizes) on iOS in light mode

Editing

A resizable widget starting at large.

iOS
Widget (editing) on iOS in light mode

Inside handle

A resizable widget with the handle drawn inside the corner.

iOS
Widget (inside handle) on iOS in light mode

Limited sizes

Resizing limited to small and medium.

iOS
Widget (limited sizes) on iOS in light mode

Controlled

Controls the size with size and onSizeChange.

iOS
Widget (controlled) on iOS in light mode

Centered

Centered content with align="center".

iOS
Widget (centered) on iOS in light mode

Auto

An auto widget that fills its parent.

iOS
Widget (auto) on iOS in light mode

Dashboard

Several auto-sized widgets arranged in a grid.

iOS
Widget (dashboard) on iOS in light mode

API Reference

Widget

The card surface and optional resize handle.

ExtendsViewPropsReact.RefAttributes<View>
PropType
Type
string
Default
—
About
Controlled size: small, medium, large, extra-large or auto.
Type
WidgetSize"auto"
Default
—
About
Initial size when uncontrolled.
Type
WidgetSize"auto"
Default
—
About
Called with the new size after a resize.
Type
(size: WidgetSize | "auto") => void
Default
—
About
Sizes the user can resize to. Defaults to all four.
Type
WidgetSize[]
Default
ALL_SIZES
About
Shows a drag handle for resizing.
Type
boolean
Default
false
About
Handle placement: outside the corner or inside it. Defaults to outside.
Type
WidgetHandlePlacement
Default
"outside"
About
start or center content alignment.
Type
WidgetAlign
Default
"start"
About
Accessibility label for the handle. Defaults to "Resize widget".
Type
string
Default
"Resize widget"

WidgetHeader

Row for the icon, title and action.

ExtendsViewPropsReact.RefAttributes<View>
PropType
Type
string
Default
—

WidgetIcon

Icon frame in default, sm or lg size.

ExtendsViewPropsReact.RefAttributes<View>
PropType
Type
string
Default
—
About
Classes applied to the icon inside.
Type
string
Default
—
About
default, sm or lg.
Type
"default""sm""lg"
Default
"default"

WidgetTitle

Single-line heading.

ExtendsReact.ComponentProps<typeof Text>React.RefAttributes<typeof Text>

WidgetAction

Trailing slot in the header; hidden when centered.

ExtendsViewPropsReact.RefAttributes<View>
PropType
Type
string
Default
—

WidgetDescription

Secondary text.

ExtendsReact.ComponentProps<typeof Text>React.RefAttributes<typeof Text>

WidgetValue

Large number with tabular figures.

ExtendsReact.ComponentProps<typeof Text>React.RefAttributes<typeof Text>

WidgetContent

Flexible body area that clips overflow.

ExtendsViewPropsReact.RefAttributes<View>
PropType
Type
string
Default
—

WidgetFooter

Small secondary text and icons pinned to the bottom.

ExtendsViewPropsReact.RefAttributes<View>
PropType
Type
string
Default
—

Accessibility

  • The resize handle has the adjustable role, its resizeLabel and the current size as its value; increment and decrement actions step through the available sizes, so VoiceOver and TalkBack users can resize without dragging.
  • WidgetTitle has the heading role.
  • WidgetIcon and the resize preview outline are hidden from assistive technology.
  • Size animations respect the system reduce motion setting.

Notes

  • Uses bg-surface-secondary for the surface, bg-control for icon frames, and text-label-quaternary for the handle, which turns text-accent while dragging.
  • The handle and drag direction mirror in right-to-left layouts.
  • Light and dark colors follow the system appearance.