Description
Thank you for GPUI Kit. I built an on-device test gallery for GPUI Kit v0.7.0 on Android (gpui-mobile host entry point, a SurfaceView Activity, phone in portrait) with a demo screen for every user-facing component, and went through each one by touch. Most components work well; this issue collects what does not, in case it helps. I'm happy to split it into focused issues, add details or recordings, or test fixes on the device. Full per-component notes are in the gallery's COMPONENT_MATRIX.md (77 working / 18 partial / 4 broken / 4 not applicable), and the APK is on the v0.1.2 release.
Fixes already proposed (one PR per repository):
- Slider cannot be dragged by touch → #3313 (merged)
- gpui-fps HUD panics on Android (
monospacefont does not exist) → #3313 (merged) - gpui-mobile: clipboard never reaches the system → longbridge/gpui-mobile#24
- gpui-mobile: black screen after Activity recreation (late
surfaceDestroyed) → longbridge/gpui-mobile#24
Try it on a device
The test app is open source and meant to be used as a playground: Bombatomica64/Gpui-android.
- Prebuilt APK (arm64-v8a + x86_64, sideloadable, signed with a debug key): gpui-kit-mobile-lab-v0.1.2.apk
- Build from source:
./build.sh android --release --install(Rust + cargo-ndk + Android SDK/NDK; see the README). - Each component has its own screen with its states, current value and an event log; there are also Touch Lab, Scroll Stress, Diagnostics, Stress Test and Themes screens. To try a Kit change on Android, add the changed Kit crates (e.g.
gpui-base = { path = "…/gpui-kit/crates/base" }) to the[patch.crates-io]section of itsCargo.tomland rebuild. The app is on Kit 0.7.0 /gpui-pre0.3.7, so the patched crates need to stay on that GPUI snapshot.
Environment
- GPUI:
gpui-pre0.3.7 (the snapshot Kit 0.7.0 pins),wgpu29.0.4 - GPUI Kit: 0.7.0 (
0c830f4d) - gpui-mobile:
f379bc8(plus the patches above) - Platform: Android 13 (API 33) on Redroid, 1080×2340 at 420 dpi (411×819 pt, scale 2.625), AOSP keyboard. Interactions were driven with
adb shell input(taps, swipes, rawmotioneventsequences, IME typing). SwiftShader rendering, so no performance claims.
Steps to Reproduce
Install the release APK and open a component's screen from the catalog, or directly:
adb shell am start -n dev.gpui.mobile.lab/.LabActivity --es screen "'Number & OTP'"Each screen shows the current value and an event log (also on logcat, tag GPUI_MOBILE_LAB).
Actual
Broken on a touch-only device
- OtpInput and TimeField (and the time part of a date+time
DatePicker): tapping shows no soft keyboard. They have no text-input handler (EntityInputHandler) and never request the virtual keyboard, so they can only be edited with a hardware keyboard. - Context menus (
ContextMenuExt) open only on the right mouse button; a long-press does nothing, so there is no way to open one on a phone.LongPressEvent(claimed withprevent_defaultonStarted) looks like the natural mapping. - Everything built on
on_dragignores finger drags, because GPUI's drag-and-drop is mouse-only and a touch drag arrives asTouchDragEvent: Resizable dividers, Dock splitters and tab drag/split, DataTable column resize/reorder. The Slider PR shows one way to handle it for a single component.
Layout at phone width (411 pt)
- Popover near the right edge and PopupMenu submenus are not moved back into the viewport and are clipped.
- Breadcrumb never wraps; the last items are clipped.
- Full Pagination overflows (Next is clipped); the compact variant fits.
- Static
Tableclips its last column (no shrinking or horizontal scroll). DescriptionListhorizontal two-column layout andSettingscontent break words mid-word; the Settings sidebar takes about 70% of the width.- Accordion: a long title does not wrap and pushes the chevron out of view.
- Carousel: prev/next buttons render outside the card and are clipped at the screen edges.
Touch behaviour
- Carousel: one fling skips several slides, because every momentum scroll delta counts as a step.
- Kit's scroll containers do not set
restrict_scroll_to_axis(), so a horizontal pan on a vertical-only list scrolls it vertically (GPUI converts the pan). Setting it on the app's own containers fixes it there. - TextView long-press selection shows handles and Copy / Select All, but the initial selection is often not the pressed word (collapsed, or starting mid-word).
- DataTable emits a stray
RightClickedRow(None)on a plain tap. - After a tap, the touched menu/list row keeps its hover highlight until the next touch elsewhere.
- Nothing scrolls a focused input above the soft keyboard; the app has to do it.
Not Android-specific
Split into focused issues:
- #3324: RadioGroup, a disabled Radio item can still be selected (fix: #3331)
- #3325: Textarea,
rows(n)does not set the height of a plain multi-line Textarea (fix: #3330) - #3326: Bubble, TextView inside a Filled bubble ignores the bubble text color (fix: #3329)
- #3327: ShimmerText, default highlight is invisible on foreground text in dark mode (fix: #3328)
gpui-mobile integration (listed for completeness; they may belong in gpui-mobile)
- Bold and italic text render as regular weight: Android's Roboto is a variable font and the text system does not apply weight/italic variations. Headings are larger but not bold.
- Dismissing the IME with back injects an
escapekeystroke, which apps also handle as navigation/close. NumberInputand numeric masks open the full text keyboard; gpui-mobile always requests the default keyboard type.show_soft_keyboardis a no-op, so components that call it get no keyboard.- On the host-driven entry point, night mode is not reported to
window.appearance(), and the bundled-emoji fallback cannot read APK assets (it needs anAndroidApp); without a host workaround, emoji do not render on Android 13+. - Closing a sheet while a fling is still running hands the remaining momentum to the page behind it.
window.request_animation_frame()panics when called outside rendering (e.g. in a click handler).
Expected
Components are usable by touch alone: text-like fields raise the soft keyboard, context menus and drag interactions have touch equivalents, and popovers and wide components stay inside a phone-width viewport.
The gallery and this report were produced with AI assistance (Claude Code), and every item was reproduced on the emulated device.
🤖 Generated with Claude Code
Activity
5#3313 is merged as 9c369db6f9b0f3754fdf5d2e4027acb1f68b1146. Main now contains the Slider touch-drag path and Android FPS font fix; these are after the v0.7.0 tag.
The rest of this report is still open. In particular, current source still overwrites each Radio's disabled state with the RadioGroup state, and the dark-mode ShimmerText default still mixes foreground text toward the same foreground color. Those are desktop-relevant too.
Please split the remaining reproducible items into focused issues, starting with disabled RadioGroup items, Textarea rows, Bubble/TextView contrast and ShimmerText contrast. That will let each fix be verified independently of the Android integration work.
Thank you for merging #3313 and for the guidance! I've split out the four you mentioned, each with a repro against main (201b55a4):
- #3324: RadioGroup, a disabled Radio item can still be selected (confirmed with a
#[gpui_kit::test]) - #3325: Textarea,
rows(n)does not set the height of a plain multi-line Textarea (confirmed with a#[gpui_kit::test]:rows(1)androws(5)are both 38px) - #3326: Bubble, TextView inside a Filled bubble ignores the bubble text color
- #3327: ShimmerText, default highlight is invisible on foreground text in dark mode
I'll continue with the remaining items the same way, each with its own repro, and keep this issue as the index.
Welcome, keep going.
On Sep 30, 2026 15:30, Lorenzo wrote:
Bombatomica64 left a comment (longbridge/gpui-kit#3310)
Thank you for merging #3313 and for the guidance! I've split out the four you mentioned, each with a repro against
main(201b55a4):
- #3324: RadioGroup, a disabled Radio item can still be selected (confirmed with a
#[gpui_kit::test])- #3325: Textarea,
rows(n)does not set the height of a plain multi-line Textarea (confirmed with a#[gpui_kit::test]:rows(1)androws(5)are both 38px)- #3326: Bubble, TextView inside a Filled bubble ignores the bubble text color
- #3327: ShimmerText, default highlight is invisible on foreground text in dark mode
I'll continue with the remaining items the same way, each with its own repro, and keep this issue as the index.
-- Reply to this email directly or view it on GitHub: https://github.com/longbridge/gpui-kit/issues/3310#issuecomment-5906375825 You are receiving this because you commented.
Message ID: @.***>
Fixes are now up for all four split issues, each with a regression test that fails on main:
- #3331 for #3324 (RadioGroup disabled item)
- #3330 for #3325 (Textarea
rows; the root cause wasupdate_auto_growoverwritingrowsfor non-auto-grow inputs) - #3329 for #3326 (
BubbleVariant::text_view_style) - #3328 for #3327 (ShimmerText dark-mode highlight)
Each issue has a comment with the details, including two corrections to my original reports. The playground APK is now v0.1.2.
A small update after checking the app on a physical phone (360×736 pt, dark mode): I added two items under Not Android-specific:
TextViewinside aFilledBubblerenders white on white, because TextView paints the themeforegroundover the bubble'sprimary_foregroundShimmerTexthighlight is invisible onforegroundtext in dark modeBoth include the cause and a workaround. The playground APK is now v0.1.1. Thanks again for the library!