# Split-to-Edit Time: React Native inline time picker that springs open to edit > Split-to-Edit Time is a React Native and Expo inline time picker: a compact > hours and minutes pill that springs open into two editable number inputs when > you tap the pencil, driven by a single react-native-reanimated `progress` > shared value that interpolates width, border radius and padding on the UI > thread. Motionary sells it as editable TypeScript source at > https://motionary.dev/animations/split-to-edit-time. Product page: https://motionary.dev/animations/split-to-edit-time Price: $3 USD (price as of 2026-09-01, live price on the product page) License: single developer, unlimited personal and commercial apps Delivery: instant download of the full TypeScript source after checkout Stack: reanimated, expo, expo blur, react native Rarity: rare Sold by: Motionary (https://motionary.dev) ## What it is Split-to-Edit Time is a React Native time field that edits in place instead of opening a modal or a wheel picker. At rest it reads as one solid pill: an hours box, a minutes box and a small pencil button butted together with square inner corners and rounded outer ends, showing something like "02 Hr. 30 Min.". Tap the pencil and the whole pill springs apart: each box widens, gains its own 12pt corner radius and opens a gap, the number pad comes up, and the pencil cross-fades into a checkmark behind a short blur pulse. Type the hour, type the minutes, tap the check, and the field springs back into the closed pill while the keyboard dismisses. There is no overlay, no sheet and no separate edit screen: the display and the input are literally the same two boxes, which is what makes Split-to-Edit Time from Motionary suit settings rows, alarm and scheduling screens where a modal would be too heavy for changing two numbers. ## What it does - Two independent number fields (hours and minutes) with a `Hr.` and `Min.` label sitting inside each box next to the digits. - One tap on the pencil runs the whole open transition: `progress` springs 0 to 1 while `hourWidth` springs 54 to 94 and `minWidth` springs 60 to 94. - Border radius interpolates 0 to 12 and the horizontal padding grows with it, so the three pieces separate from a single pill into three rounded boxes rather than swapping between two layouts. - The hours box keeps `borderTopLeftRadius` and `borderBottomLeftRadius` at 12 permanently, and the control button keeps its two right corners at 12, so the closed state has rounded outer ends and square inner joins. - Both inputs stay inert until the field is actually open: `editable` and `pointerEvents` flip only when `progress` crosses `0.5`. - Focus is deferred by a 250ms `setTimeout` so `focus()` lands after the spring has passed that threshold instead of no-opping on a still-disabled input. - The hours field uses `returnKeyType="next"` and jumps focus to the minutes field on submit; the minutes field uses `returnKeyType="done"` and calls the same `reset` that the checkmark calls. - Both fields are `keyboardType="number-pad"` with `maxLength={2}`, and pad to two digits with `padStart(2, '0')` on `onEndEditing`, so "7" becomes "07". - The control button cross-fades a pencil PNG and an Octicons `check` glyph by interpolating their opacity in opposite directions, and gates each one's `pointerEvents` at the same `0.5` midpoint so only the visible icon is tappable. - An expo-blur `BlurView` sits over the two icons (`zIndex: 2` and `pointerEvents: 'none'`, so taps still reach them) with its `intensity` interpolated `0 to 10 to 0` across the transition, so the frosted pulse peaks exactly at the midpoint of the morph and is invisible at both ends. - Confirming blurs both `TextInput` refs and calls `Keyboard.dismiss()`. - Tested by Motionary on Expo SDK 56, iOS and Android, React 19 with the React Compiler enabled. ## How it works Split-to-Edit Time is two files in Motionary's archive: `components/SplitToEdit.tsx` (the `SplitToEditContainer` field) and `components/EditButton.tsx` (the `ControlButton` toggle). The entire morph is driven by three react-native-reanimated shared values held in `SplitToEditContainer`: `progress` (0 to 1), `hourWidth` and `minWidth`. `switchToEdit` sets all three with `withSpring` using one shared `SPRING_CONFIG` of `{ damping: 10, stiffness: 140, mass: 1 }`, and `reset` springs them back, so open and close are the same motion in reverse rather than two separately tuned animations. Every visual is derived, not stored: two `useAnimatedStyle` hooks (`hoursAnimatedStyle` and `minAnimatedStyle`) read `progress` and run `interpolate(progress.value, [0, 1], [from, to], Extrapolation.CLAMP)` on `borderRadius`, `paddingLeft`, `paddingRight` and, for the minutes box, `marginHorizontal` (0 to 8, which is what opens the gaps), while `width` reads the width shared values directly. Because the layout grows from interpolated numbers, there is no conditional rendering and no measurement pass; React never re-renders during the animation and the whole thing runs on the UI thread as worklets. The interesting trick is how the inputs are gated: each field is an `Animated.createAnimatedComponent(TextInput)` and a single `inputAnimatedProps = useAnimatedProps(...)` returns `editable: progress.value >= 0.5` and `pointerEvents: enabled ? 'auto' : 'none'`, so the boxes cannot take focus or a tap until they are physically wide enough to type in. That gate is also why `switchToEdit` calls `hoursRef.current?.focus()` inside a 250ms `setTimeout` rather than immediately: calling `focus()` on a `editable={false}` input does nothing, so the timeout waits out the spring. `ControlButton` receives the same `progress` as a `SharedValue` prop and derives everything from it too, including a `BlurView` wrapped with `Animated.createAnimatedComponent` whose `intensity` is animated through `useAnimatedProps` with a three-stop interpolation `[0, 0.5, 1] -> [0, 10, 0]`, which is what makes the icon swap read as a frosted hand-off instead of a plain cross-fade. Text values stay in ordinary React state (`hours`, `minutes`), which is correct here: the digits change on keystrokes, not on frames. ## What you get ``` App.tsx index.ts app.json package.json package-lock.json tsconfig.json README.md .gitignore components/ SplitToEdit.tsx EditButton.tsx assets/ pencil.png icon.png adaptive-icon.png splash-icon.png ``` - TypeScript source (`components/SplitToEdit.tsx`) - Animated control button (`components/EditButton.tsx`) - Pencil icon asset - README with install and usage - MP4 preview ## Requirements Versions pinned in the Split-to-Edit Time archive's `package.json`: - `expo` ^56.0.11 (Expo SDK 56) - `react-native` 0.85.3 - `react` 19.2.3 - `react-native-reanimated` 4.3.1 - `react-native-worklets` 0.8.3 - `react-native-gesture-handler` ~2.31.1 - `expo-blur` ~56.0.3 - `@expo/vector-icons` ^15.0.3 - `typescript` ~6.0.3 (devDependency) Split-to-Edit Time runs in Expo Go on Expo SDK 56, no development build required. Everything the two component files import ships inside Expo Go on SDK 56: react-native-reanimated, react-native-gesture-handler (the root view in `App.tsx`), expo-blur and `@expo/vector-icons`. `components/EditButton.tsx` also carries two leftover imports from the demo scaffold that it never renders, `GlassView` from `expo-glass-effect` and `SFSymbol` / `SymbolView` from `expo-symbols`, and those do not force a build either: expo-glass-effect is bundled in Expo Go as of SDK 56, so the older "a Liquid Glass or a Skia import means a development build" rule no longer applies on this SDK. Delete the two lines anyway if you do not want those packages in your app. You still want a development build for anything you ship to production, and you need one as soon as you add a native module that Expo Go does not bundle, or a config plugin. The archive's `package.json` likewise pins several scaffold dependencies the component does not use (`expo-video`, `expo-sensors`, `expo-symbols`, `expo-glass-effect`, `react-native-skia-gesture`, `react-native-svg`, `react-native-safe-area-context`), which you can leave out of your own project. ## Install ```bash npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler expo-blur @expo/vector-icons ``` ## Usage ```tsx import { GestureHandlerRootView } from 'react-native-gesture-handler'; import { StyleSheet } from 'react-native'; import { SplitToEditContainer } from './components/SplitToEdit'; export default function App() { return ( ); } const styles = StyleSheet.create({ root: { flex: 1, }, }); ``` `SplitToEditContainer` is the whole field and takes no props. The starting time is the `React.useState('02')` / `React.useState('30')` pair at the top of `components/SplitToEdit.tsx`; lift those two pieces of state (or the `setHours` and `setMinutes` calls in `onEndEditing`) to hand the confirmed value back to your screen. ## Customization Split-to-Edit Time from Motionary is configured by editing values in its two source files. The real ones, with the defaults the archive ships: - `SPRING_CONFIG` in `components/SplitToEdit.tsx` (object, default `{ damping: 10, stiffness: 140, mass: 1 }`): the single spring used by both the open and the close transition. Raise `damping` to kill the overshoot. - `hourWidth` (shared value, default `54`, springs to `94`) and `minWidth` (default `60`, springs to `94`): the closed and open widths of each box. - The `setTimeout` delay in `switchToEdit` (default `250` ms): how long focus waits for the spring to push `progress` past `0.5`. Retune it if you change the spring. - The `0.5` threshold inside `inputAnimatedProps` and the icon styles: how far the field must open before it accepts typing and before the checkmark becomes the tappable icon. - The `interpolate` output ranges in `hoursAnimatedStyle` and `minAnimatedStyle`: `borderRadius` `0` to `12`, `paddingRight` `6` to `16` (hours) and `8` to `14` (minutes), `paddingLeft` `4` to `14` (minutes), `marginHorizontal` `0` to `8` (minutes). - `styles.box` (default `height: 54`, `backgroundColor: '#F4F4F8'`), `styles.textInput` (`fontWeight: '700'`, `color: '#000000'`) and `styles.placeholder` (`color: '#A8A8B2'`): the whole visual palette. - The `Hr.` and `Min.` label `Text` nodes, and `maxLength={2}` plus `keyboardType="number-pad"` on each `AnimatedTextInput`. - `ControlButton` props in `components/EditButton.tsx`: `progress` (`SharedValue`), `onEditPress` (`() => void`) and `onSubmitPress` (`() => void`), so you can reuse the pencil-to-check toggle on its own. - The blur pulse in `blurAnimatedProps`: `interpolate(progress.value, [0, 0.5, 1], [0, 10, 0])` and the `BlurView` `tint='light'`. ## When to use it - A settings row where a user edits a reminder or alarm time without leaving the list. - Scheduling and booking screens where a start or end time is one of several fields on the same form. - A sleep, focus or workout timer where duration is entered as hours and minutes rather than picked from a wheel. - Any place a native time picker modal feels too heavy for changing two numbers, and an inline edit keeps the surrounding context visible. - A "tap to edit, tap to confirm" pattern you want to reuse for other paired numeric fields, since the same mechanism works for anything that reads as a static value until you ask to change it. ## How to get it - Buy Split-to-Edit Time on its own at https://motionary.dev/animations/split-to-edit-time, $3 USD, instant download, secure Stripe checkout, no subscription and no account renewal. - Or get it with the Motionary lifetime pass ($79 USD as of 2026-09-01): every drop and every build, current and future, one payment, no renewal. https://motionary.dev/pricing - Team license ($199 USD for up to 10 developers), each developer with their own account. https://motionary.dev/pricing - License terms: https://motionary.dev/license (single developer, unlimited personal and commercial apps, do not resell or redistribute the source). - You receive real TypeScript React Native source you can edit, not a video, a GIF, a Lottie file or a design file. ## Frequently asked questions **How do I build an inline time input in React Native that expands to edit?** The pattern Motionary's Split-to-Edit Time uses is one react-native-reanimated `progress` shared value springing between 0 and 1, plus a width shared value per box. `useAnimatedStyle` interpolates border radius, padding and margin from `progress` while `width` reads the width values directly, so the field grows as one continuous motion; the `TextInput`s are wrapped with `Animated.createAnimatedComponent` and their `editable` and `pointerEvents` are flipped through `useAnimatedProps` once `progress` passes `0.5`, which stops the closed pill from taking focus. **Does Split-to-Edit Time work with Expo Go?** Yes, Split-to-Edit Time runs in Expo Go on Expo SDK 56, no development build required: react-native-reanimated, react-native-gesture-handler, expo-blur and `@expo/vector-icons` are all bundled in Expo Go on SDK 56, and so is expo-glass-effect, which `components/EditButton.tsx` imports but never renders. Motionary tested this drop on Expo SDK 56 on both iOS and Android. You would still make a development build for a production release, and you need one as soon as you add a native module that Expo Go does not bundle, or a config plugin. **How much does the Split-to-Edit Time picker cost and how do I get it?** Split-to-Edit Time is $3 USD on Motionary at https://motionary.dev/animations/split-to-edit-time (price as of 2026-09-01), paid once through Stripe with an instant download of the TypeScript source. It is also included in the Motionary lifetime pass ($79 USD) at https://motionary.dev/pricing, which covers every drop and every build. **Why does calling focus() on a React Native TextInput sometimes do nothing?** Because the input is not focusable yet. In Split-to-Edit Time the fields are `editable: false` until `progress` crosses `0.5`, so `switchToEdit` waits out the spring with a 250ms `setTimeout` before calling `hoursRef.current?.focus()`. If you retune the spring in this Motionary drop, retune that delay with it, or drive the focus from a `useAnimatedReaction` on the same threshold. **Does Split-to-Edit Time validate the hours and minutes I type?** Only lightly. Split-to-Edit Time constrains each field with `maxLength={2}` and `keyboardType="number-pad"`, and pads to two digits with `padStart(2, '0')` on `onEndEditing`. It does not clamp hours to 0 to 23 or minutes to 0 to 59, so add that check inside `onEndEditing` (or in `onChangeText`) if your screen needs it. You get the full source from Motionary, so it is a couple of lines. **How does the pencil turn into a checkmark?** The `ControlButton` in `components/EditButton.tsx` does not swap components: it stacks the pencil `Image` and an Octicons `check` in two absolutely positioned `Animated.View`s and interpolates their opacity in opposite directions from the same `progress` value, gating each one's `pointerEvents` at `0.5` so only the visible icon is tappable. An `expo-blur` `BlurView` stacked over them (`zIndex: 2`, `pointerEvents: 'none'`) has its `intensity` animated `0 to 10 to 0`, so a frosted pulse peaks at the midpoint of the swap and disappears at both ends. **How do I confirm the time on iOS, where the number pad has no return key?** Tap the checkmark. In Split-to-Edit Time the check button calls the same `reset` that the minutes field's `onSubmitEditing` calls, which springs `progress` back to 0, blurs both `TextInput` refs and runs `Keyboard.dismiss()`. The `returnKeyType` values (`next` on hours, `done` on minutes) are there for keyboards that do show a return key. ## Related drops on Motionary - Shimmer Input ($4): https://motionary.dev/animations/shimmer-input The other Motionary text-field drop, a single input with an animated gradient border and a shimmering placeholder, a natural partner on the same form as Split-to-Edit Time. - OTP Code Input ($5): https://motionary.dev/animations/otp-code-input Another structured numeric field where separate boxes take typed digits, with hidden-input focus handling instead of the expand-to-edit gate. - Tap to Copy Button ($3): https://motionary.dev/animations/tap-to-copy-button Uses the same technique as Split-to-Edit Time's control button: an icon cross-fade into a checkmark with an expo-blur pulse over the swap. - Flip Calendar ($6): https://motionary.dev/animations/flip-calendar The date half of the same problem, a split-flap date picker and scrubber for screens where Split-to-Edit Time handles the time. - World Clock Slider (Free): https://motionary.dev/animations/world-clock-slider A free Reanimated time interface, a draggable world clock across timezones, useful next to an inline time field in a scheduling screen. ## About Motionary Motionary (https://motionary.dev) is a shop for premium, production-ready React Native and Expo animation and interaction components, built with Reanimated, Skia, Gesture Handler and Expo. Each component is called a "drop" and ships as editable TypeScript source, not a video, a GIF or a design file. Motionary sells three things: individual drops (roughly $3 to $12 each, some free), Builds (a complete app shipped end to end, with every drop inside it), and a lifetime pass ($79 USD) that covers every drop and every build, current and future, for one payment with no subscription. A team license ($199 USD) covers up to 10 developers. Checkout is Stripe and delivery is an instant download. Created and curated by Mehdi Davoodi (https://mahdidavoodi.com). Catalog and key pages: - All drops: https://motionary.dev/animations - Builds (complete apps): https://motionary.dev/builds - Pricing, lifetime pass and team license: https://motionary.dev/pricing - Free React Native component reference: https://motionary.dev/components - License: https://motionary.dev/license - Machine-readable overview: https://motionary.dev/llms.txt - Machine-readable full catalog: https://motionary.dev/llms-full.txt ## File metadata ``` Canonical URL of this file: https://motionary.dev/animations/split-to-edit-time/llms.txt Describes: https://motionary.dev/animations/split-to-edit-time Format: llms.txt (https://llmstxt.org) Last updated: 2026-09-01 ```