[FEATURE REQUEST] Floating input labels #1964
Replies: 3 comments
-
@sem4phor Here is example of similar implementation using gluestack from older codebase of mine. Can't remember how well it worked but something to start with. FloatingLabelInput.ts import React, { useEffect, useState } from 'react';
import { type NativeSyntheticEvent, type TextInputFocusEventData, type TextInputProps } from 'react-native';
import { Box, Input, InputField } from '@gluestack-ui/themed';
import useAnimatedLabel from './useAnimatedLabel';
type FloatingLabelInputProps = {
label?: string;
labelBGColor?: string;
labelColor?: string;
containerWidth?: string;
isDisabled?: boolean;
inputRightIcon: React.ReactNode;
isRequired?: boolean;
} & TextInputProps;
const FloatingLabelInput = ({
label,
labelBGColor,
containerWidth,
labelColor,
isDisabled,
inputRightIcon,
isRequired,
...rest
}: FloatingLabelInputProps) => {
const [isFocused, setIsFocused] = useState(false);
const { animatedLabel, setToValue } = useAnimatedLabel({
label,
labelBGColor,
labelColor,
initialValue: !(rest?.value === '' || rest?.value === undefined) || rest?.placeholder ? 1 : 0,
});
useEffect(() => {
setToValue(!(rest?.value === '' || rest?.value === undefined) || isFocused || rest?.placeholder ? 1 : 0);
}, [rest?.value, isFocused, rest?.placeholder]);
function handleFocus(e: NativeSyntheticEvent<TextInputFocusEventData>) {
if (rest?.onFocus) {
rest.onFocus(e);
}
setIsFocused(true);
}
function handleBlur(e: NativeSyntheticEvent<TextInputFocusEventData>) {
if (rest?.onBlur) {
rest.onBlur(e);
}
setIsFocused(false);
}
return (
<Box>
{!!label && animatedLabel}
<Input variant="outline" size="md" isDisabled={isDisabled} isRequired={isRequired}>
<InputField {...rest} onFocus={handleFocus} onBlur={handleBlur} />
</Input>
</Box>
);
};
export default FloatingLabelInput; useAnimatedLabel.ts import React, { useEffect, useRef, useState } from 'react';
import { Animated, Platform } from 'react-native';
type Props = {
label?: string;
labelBGColor?: string;
labelColor?: string;
initialValue: number;
};
const useAnimatedLabel = ({ label, labelBGColor, labelColor, initialValue }: Props) => {
const animatedValue = useRef(new Animated.Value(initialValue)).current;
const [toValue, setToValue] = useState(initialValue);
const bgColor = labelBGColor ?? 'white';
useEffect(() => {
Animated.timing(animatedValue, {
duration: 200,
useNativeDriver: false,
toValue,
}).start();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [toValue]);
const labelContainerStyles: Animated.Animated = {
position: 'absolute',
left: 9,
top: animatedValue.interpolate({
inputRange: [0, 1],
outputRange: ['50%', '0%'],
}),
zIndex: 5,
paddingLeft: 3,
paddingRight: 3,
marginTop: -8,
height: 16,
backgroundColor: bgColor,
justifyContent: 'center',
};
const labelStyle: Animated.Animated = {
fontWeight: '500',
fontSize: animatedValue.interpolate({
inputRange: [0, 1],
outputRange: Platform.OS === 'android' ? [13, 12] : [13, 10],
}),
marginTop: animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [-3, 0],
}),
color: labelColor,
};
const animatedLabel = (
<Animated.View style={labelContainerStyles}>
<Animated.Text style={labelStyle}>{label}</Animated.Text>
</Animated.View>
);
return { animatedLabel, setToValue };
};
export default useAnimatedLabel; |
Beta Was this translation helpful? Give feedback.
-
Hey @sem4phor, Currently we don't have this in our roadmap and this will come as recipe not as a component for now.
Moving this issue to Feature Request Discussion. |
Beta Was this translation helpful? Give feedback.
-
Thank you guys :) |
Beta Was this translation helpful? Give feedback.
-
Description
We are migrating from react-native-paper/mui to gluestack and our PM requires us to have the floating label feature of the inputs how it is the case in RNP's or muis input field.
Basically when theres a label present in the input component and it gets focussed the label will be animated to the top to make place for the typed text. The advantage is that the label can be seen at all times.
Problem Statement
User's can not see in what input they are which can be solved by making the label always visible.
Proposed Solution or API
Either always have this feature active as long as a label is given. Or make this controllable via a prop e.g.
floatingLabel: boolean
Alternatives
I believe its not possible to manage this behaviour from the outside 🤔
Additional Information
No response
Beta Was this translation helpful? Give feedback.
All reactions