Patterns from production · Streams that hold still
Keep the anchor
Content above the viewport can change without moving the visible row.
Keep the anchor
Try the controls to see the rule.
The rule
Before inserting or changing rows above the viewport, remember the first visible row and its screen position. Restore that position after the patch.
Tokens used
space.md12pxmotion.duration.fast180mssize.tap44pxmotion.duration.base260ms
Native spec · generated from this pattern and the shared token registry
struct OvKeepAnchor: View {
let status: String
@Environment(\.accessibilityReduceMotion) private var reduceMotion
var body: some View {
HStack(spacing: OvScale.spaceMd) {
Text(status).font(.body)
}
.frame(minHeight: OvScale.sizeTap)
.animation(reduceMotion ? .none : .easeOut(duration: OvScale.motionDurationBase), value: status)
}
}
// Tokens: space.md=12px, motion.duration.fast=180ms, size.tap=44px, motion.duration.base=260ms@Composable
fun OvKeepAnchor(status: String, reduceMotion: Boolean) {
Row(
modifier = Modifier.defaultMinSize(minHeight = OvScale.SizeTap),
horizontalArrangement = Arrangement.spacedBy(OvScale.SpaceMd),
) {
Text(status, style = MaterialTheme.typography.bodyMedium)
}
// Apply motion only when !reduceMotion.
}
// Tokens: space.md=12px, motion.duration.fast=180ms, size.tap=44px, motion.duration.base=260ms