Overview
When a user clicks on the input box, the keyboard will pop up, which can easily lead to issues such as the page being compressed, bottom buttons floating, and inability to scroll if not handled properly. This article organizes a set of practices and runnable demos based on common business scenarios (such as full-screen forms, input within pop-ups, multiple input fields, etc.) according to the Tuya UED specifications, to facilitate direct reuse and avoid common pitfalls. Github demo code
Environment Requirements
Note: The APIs mentioned in this article, such as
ty.enablePageScroll, are supported only in APP versions 7.3.0 and above; please ensure compatibility with lower versions.
I. Business Scenarios and Key Points Overview
Scenario Selection Guide
flowchart TD
A["Is it inside a popup?"] -->|No| B["Number of input fields?"]
A -->|Yes| C["Type of popup?"]
B -->|"Single/Few"| D["Scenario 1: Browse / Lightweight Input + Keyboard Auto-hide"]
B -->|Multiple| E["Scenario 2: Multi-input Form + Fixed Keyboard"]
B -->|"Card Layout"| I["Does it exceed one screen?"]
I -->|No| J["Scenario 6: Card Fixed Height + One Screen Fixed"]
I -->|Yes| K["Scenario 7: Card Adaptive + Scroll Beyond One Screen"]
C -->|"System Popup"| H["Scenario 5: Popup Focus"]
C -->|"Custom Popup + Few Input Fields"| F["Scenario 3: Popup Lightweight Input + Keyboard Auto-hide"]
C -->|"Custom Popup + Multiple Input Fields"| G["Scenario 4: Popup Multi-input Form + Fixed Keyboard"]II. General Best Practices
The following general knowledge will be repeatedly used in various scenarios, and it is recommended to familiarize yourself with it beforehand.
1. useWindowHeight — Get Safe One Screen Height
100vh represents the height of the entire WebView container, but the WebView will be compressed when the keyboard pops up on Android devices, causing the bottom content to float up. To keep the page at full screen height during focus, a fixed pixel value needs to be obtained.
Notes:
- The usable height of the page container can be obtained via
getSystemInfoSync().useableWindowHeight. - On Android devices, during page initialization, the
useableWindowHeightvalue is 0 (the logical layer asynchronously obtains the container height), so it needs to be acquired later. - It is recommended to acquire it during the first focus event.
Suggest wrapping it into a custom hook:
Subsequent scenario codes will directly use
useWindowHeight, without repeating the retrieval logic.
2. Keyboard Auto-hide
By using the controlled focus of the Input component + calling setFocus(false) on the container's onTouchMove.
Note: If there are behaviors that prevent bubbling inside, the
onTouchMoveevent may not trigger.
3. Single Container Scrolling on Focus [iOS]
During focus, iOS defaults to wrap the outer layer of the WebView with a scrolling container. If an internal ScrollView is also used, it creates a double-layer scroll container—the page may get stuck when scrolling too fast.
Solution: Use page-level scrolling, set in index.config.ts:
At this point, the top navigation, bottom buttons, etc., need to be positioned using fixed, and the content area should leave padding for scrolling.
4. Popup Position Fixed Relative to External Page [Android]
When focused in a popup scenario on Android devices, the root node can use 100vh as a calculation baseline to allow the container to adaptively compress, keeping the popup's vertical position unchanged.
iOS's focus position is uncontrollable, this solution is only valid for Android.
5. Prohibit Scrolling During Focus [iOS]
On iOS, scrolling is allowed by default during focus and cannot be controlled. In APP versions 7.3.0 and above, you can call the following in the onFocus callback:
Note: Once scrolling is set to be disabled, it will also be effective in non-focused scenarios. It is recommended to restore it in onBlur:
Note on @ts-ignore
Some API calls in the documentation may encounter TypeScript type errors for the following reasons:
Recommended Approach: Extend type definitions through module declaration to avoid directly using @ts-ignore:
III. Detailed Explanation of Each Scenario
1. Browse / Lightweight Input Form + Keyboard Auto-hide
Automatically hide the keyboard when the page is scrolled
Utilizing the focus property of the Input component + onTouchMove of the container, the input field automatically loses focus to hide the keyboard when scrolling the page. (See "General Best Practices — Keyboard Auto-hide")
Use useWindowHeight for page height [Android]
Use the useWindowHeight hook to get the accurate one screen height, preventing the page from compressing when the keyboard pops up on Android devices. (See "General Best Practices — useWindowHeight")
Fix the position of the bottom button [Android]
Do not use position: fixed; otherwise, the button will float up when the keyboard pops up on Android.
You can use a fixed height for the root node + position: relative, and the button area can use position: absolute; or use a flex adaptive layout to fill the full screen.
2. Multi-input Form + Fixed Keyboard
Bottom buttons fix to the bottom; keyboard appears, buttons float up automatically on Android [Android]
Fixed positioning for the bottom operation area using position: fixed, which does not scroll with content. Remember to leave bottom padding for the scroll container to prevent the bottom button from blocking the scroll content.
Avoid double scrolling container [iOS]
iOS defaults to wrap the outer layer of the mini-program container with a scrolling container during focus; if the internal scroll container also exists, double scrolling is easily encountered—scrolling too fast may cause the page to get stuck. It is recommended to use page-level scrolling. (See "General Best Practices — Single Container Scrolling on Focus")
Set in index.config.ts:
If using a custom navigation bar, set position: fixed to stick to the top, and the content area should use CSS variables to leave statusBar + navbar height to avoid being blocked:
Maintain the keyboard's residence
No additional handling is required, conforming to the system's default behavior.
3. Popup Lightweight Input Form + Keyboard Auto-hide
Controlled focus inside the popup + onTouchMove to lose focus
This is consistent with Scenario 1's "Keyboard Auto-hide." Inside the Popup, use ScrollView + controlled focus, and listen for onTouchMove on the popup content container to lose focus and hide the keyboard during focus.
Use useWindowHeight to calculate the bottom button position [Android]
Use useWindowHeight on Android devices to get the height and calculate the button top, ensuring it remains fixed relative to the visible area.
Popup position fixed relative to external container [Android]
Do not set fixed px or rpx values as this will cause the popup to be pushed up when the keyboard appears on Android devices. Setting a height of calc(100vh - 50px) allows the container to adaptively compress. (See "General Best Practices — Popup Position Fixed Relative to External Page")
4. Popup Multi-input Form + Fixed Keyboard
Allow background to scroll by controlling Popup
Use lockScroll={false} to enable background scrolling. In keyboard-focused scenarios, users can slide slowly to scroll the outer container.
The bottom buttons inside the popup automatically float up when the keyboard pops up [Android]
On Android devices, set the layout with position: fixed, allowing the bottom buttons to float just above the keyboard when it pops up. Remember to leave space at the bottom of the scroll container to prevent content from being blocked by the button.
Popup position fixed relative to external page [Android]
Do not set fixed px or rpx values; this will cause the entire popup to be pushed up when the keyboard appears on Android devices. Setting a height of calc(100vh - 50px) allows the container to adaptively compress. (See "General Best Practices — Popup Position Fixed Relative to External Page")
5. Popup Focus
Prohibit page scrolling during popup input focus
Solution A: Using SmartUI Dialog Component (Recommended)
Call SmartUI's DialogInstance.input system-level input popup, as its internal setup already disables the page scroll, requiring no additional handling.
Common parameter example:
Solution B: Using Custom Popup
If using a custom popup, you need to manually manage the page scrolling state:
Note: It is essential to restore scrolling after closing the popup; otherwise, the page will be unscrollable.
6. Fixed Card Height + One Screen Fixed + Fixed Keyboard
Use useWindowHeight to set container height, strictly one screen
Set the container height through useWindowHeight, avoiding the use of 100vh, which causes the container to compress when the keyboard appears.
Disable page scrolling during textarea focus [iOS]
Call ty.enablePageScroll({ scrollEnable: false }) in the Field's onFocus to prevent the iOS system's default scroll behavior during focus.
Position the bottom button absolutely within a one screen container
Use position: absolute + bottom for buttons, positioning them relative to the root container with a fixed height to prevent floating up when the keyboard appears.
7. Adaptive Card Height + Scroll Beyond One Screen + Fixed Keyboard
Container height using useWindowHeight; internal ScrollView occupies remaining space
Use useWindowHeight for the outer container with fixed height, the inner ScrollView scrollY uses flex: 1 to fill and enable scrolling within one screen.
Field textarea using autosize, card height changes with content
Control multi-line input height with autosize's maxHeight / minHeight to avoid overly fixed heights that lead to content being clipped or excessive whitespace.
The bottom button remains at the bottom outside of the ScrollView
Place the button container outside the ScrollView, inside the root container, using flex or fixed height to ensure it stays at the bottom when the keyboard appears and remains in view.
IV. Frequently Asked Questions (FAQ)
Q1: Why is the useableWindowHeight 0 on Android devices for the first time?
On Android, the logical layer asynchronously retrieves the container height, and it has not completed this retrieval during page initialization. It is recommended to retrieve it during the first focus event when the container height is ready.
Q2: Will lockScroll={false} cause the background page to scroll?
Yes. After setting lockScroll={false}, slow dragging by the user may trigger scrolling of the outer page. If this behavior is undesirable, please keep the default lockScroll={true}, but be aware that this may affect keyboard focus experience within the popup.
Q3: Why can't the page scroll even after setting disableScroll: false?
Check the following points:
- Whether the content height exceeds the viewport height
- Whether
ty.enablePageScroll?.({ scrollEnable: false })was called elsewhere without being restored - Whether CSS styles like
overflow: hiddenprevent scrolling
Q4: What are the main differences in focus scenarios between iOS and Android?
Q5: When to use position: fixed and when to use position: absolute?
fixed: Used in scenarios where the button is expected to float with the keyboard (such as scenarios 2 and 4), positioning the button relative to the viewport.absolute: Used in scenarios where the button position is expected to remain the same (such as scenarios 1 and 6), positioning the button relative to a fixed height parent container.