# PeriodSelector A selector component for choosing time periods in charts. ## Import ```tsx import { PeriodSelector } from '@coinbase/cds-web-visualization' ``` ## Examples ### Basic Example ```jsx live function BasicExample() { const tabs = [ { id: '1H', label: '1H' }, { id: '1D', label: '1D' }, { id: '1W', label: '1W' }, { id: '1M', label: '1M' }, { id: '1Y', label: '1Y' }, { id: 'YTD', label: 'YTD' }, { id: 'All', label: 'All' }, ]; const [activeTab, setActiveTab] = useState(tabs[0]); return ( ); } ``` ### Minimum Width You can set the `width` prop to `fit-content` to make the period selector as small as possible. ```jsx live function MinimumWidthExample() { const tabs = [ { id: '1W', label: '1W' }, { id: '1M', label: '1M' }, { id: 'YTD', label: 'YTD' }, ]; const [activeTab, setActiveTab] = useState(tabs[0]); return ( ); } ``` ### Many Periods with Overflow ```jsx live function ManyPeriodsExample() { const tabs = useMemo( () => [ { id: '1H', label: '1H' }, { id: '1D', label: '1D' }, { id: '1W', label: '1W' }, { id: '1M', label: '1M' }, { id: 'YTD', label: 'YTD' }, { id: '1Y', label: '1Y' }, { id: '5Y', label: '5Y' }, { id: 'All', label: 'All' }, ], [], ); const [activeTab, setActiveTab] = useState(tabs[0]); const isLive = useMemo(() => activeTab?.id === '1H', [activeTab]); return ( ); } ``` ### Live Indicator ```jsx live function LiveExample() { const tabs = useMemo( () => [ // LiveTabLabel is exported from PeriodSelector { id: '1H', label: }, { id: '1D', label: '1D' }, { id: '1W', label: '1W' }, { id: '1M', label: '1M' }, { id: '1Y', label: '1Y' }, { id: 'All', label: 'All' }, ], [], ); const [activeTab, setActiveTab] = useState(tabs[0]); const isLive = useMemo(() => activeTab?.id === '1H', [activeTab]); const activeBackground = useMemo(() => (isLive ? 'bgNegativeWash' : 'bgPrimaryWash'), [isLive]); return ( ); } ``` ### Customization #### Custom Colors ```jsx live function LiveExample() { const tabs = useMemo( () => [ { id: '1H', label: '1H' }, { id: '1D', label: '1D' }, { id: '1W', label: '1W' }, { id: '1M', label: '1M' }, { id: '1Y', label: '1Y' }, { id: 'All', label: 'All' }, ], [], ); const [activeTab, setActiveTab] = useState(tabs[0]); const isLive = useMemo(() => activeTab?.id === 'live', [activeTab]); const activeBackground = useMemo(() => (isLive ? 'bgNegativeWash' : 'bgPrimaryWash'), [isLive]); return ( ); } ``` #### Color Shifting ```jsx live function ColorShiftingExample() { const TabLabel = memo(({ label }) => ( {label} )); const tabs = useMemo( () => [ { id: '1H', label: , }, { id: '1D', label: , }, { id: '1W', label: , }, { id: '1M', label: , }, { id: '1Y', label: , }, { id: 'All', label: , }, ], [], ); const [activeTab, setActiveTab] = useState(tabs[0]); const [chartActiveColor, setChartActiveColor] = useState('positive'); const toggleColor = useCallback(() => { setChartActiveColor((activeColor) => (activeColor === 'positive' ? 'negative' : 'positive')); }, []); const activeForegroundColor = useMemo(() => { return chartActiveColor === 'positive' ? 'var(--color-fgPositive)' : 'var(--color-fgNegative)'; }, [chartActiveColor]); const activeBackground = useMemo(() => { return chartActiveColor === 'positive' ? 'bgPositiveWash' : 'bgNegativeWash'; }, [chartActiveColor]); return ( ); } ``` #### Asset Price Chart You can use a PeriodSelector to control the time period of a LineChart, with a settings icon to enable extra customization for users. ```jsx live function CustomizableAssetPriceExample() { const tabs = [ { id: 'hour', label: '1H' }, { id: 'day', label: '1D' }, { id: 'week', label: '1W' }, { id: 'month', label: '1M' }, { id: 'year', label: '1Y' }, { id: 'all', label: 'All' }, ]; const PeriodSelectorWrapper = memo(({ activeTab, setActiveTab, tabs, onClickSettings }) => ( )); const AssetPriceChart = memo(() => { const [activeTab, setActiveTab] = useState(tabs[0]); const [showSettings, setShowSettings] = useState(false); const [showYAxis, setShowYAxis] = useState(true); const [showXAxis, setShowXAxis] = useState(true); const [scrubIndex, setScrubIndex] = useState(); const breakpoints = useBreakpoints(); const formatPrice = useCallback((price: number) => { return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', }).format(price); }, []); const formatYAxisPrice = useCallback((price: number) => { if (breakpoints.isPhone) { // Compact format for mobile: $45k, $1.2M, etc. if (price >= 1000000) { return `$${(price / 1000000).toFixed(1)}M`; } else if (price >= 1000) { return `$${(price / 1000).toFixed(0)}k`; } return `$${price.toFixed(0)}`; } return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(price); }, [breakpoints.isPhone]); const toggleShowYAxis = useCallback(() => setShowYAxis((show) => !show), []); const toggleShowXAxis = useCallback(() => setShowXAxis((show) => !show), []); const data = useMemo(() => sparklineInteractiveData[activeTab.id], [activeTab.id]); const currentPrice = useMemo(() => sparklineInteractiveData.hour[sparklineInteractiveData.hour.length - 1].value, []); const currentTimePrice = useMemo(() => { if (scrubIndex !== undefined) { return data[scrubIndex].value; } return currentPrice; }, [data, scrubIndex, currentPrice]); const formatDate = useCallback((date) => { const dayOfWeek = date.toLocaleDateString('en-US', { weekday: 'short' }); const monthDay = date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', }); const time = date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true, }); return `${dayOfWeek}, ${monthDay}, ${time}`; }, []); const scrubberLabel = useMemo(() => { if (scrubIndex === undefined) return; return formatDate(data[scrubIndex].date); }, [scrubIndex, data, formatDate]); const accessibilityLabel = useMemo(() => { if (scrubIndex === undefined) return; const price = new Intl.NumberFormat('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(data[scrubIndex].value); const date = formatDate(data[scrubIndex].date); return `Asset price: ${price} USD on ${date}`; }, [scrubIndex, data, formatDate]); const onClickSettings = useCallback(() => setShowSettings(!showSettings), [showSettings]); const seriesData = useMemo(() => [{ id: 'price', data: data.map((d) => d.value) }], [data]); const getFormattingConfigForPeriod = useCallback((period) => { switch (period) { case 'hour': case 'day': return { hour: 'numeric', minute: 'numeric', }; case 'week': case 'month': return { month: 'numeric', day: 'numeric', }; case 'year': case 'all': return { month: 'numeric', year: 'numeric', }; } }, []); const formatXAxisDate = useCallback((index) => { if (!data[index]) return ''; const date = data[index].date; const formatConfig = getFormattingConfigForPeriod(activeTab.id); if (activeTab.id === 'hour' || activeTab.id === 'day') { return date.toLocaleTimeString('en-US', formatConfig); } else { return date.toLocaleDateString('en-US', formatConfig); } }, [data, activeTab.id, getFormattingConfigForPeriod]); const isMobile = breakpoints.isPhone || breakpoints.isTabletPortrait; return ( Asset Price} balance={} end={isMobile ? undefined : ( ) } /> {isMobile && ( )} {showSettings && ( setShowSettings(false)}> {({ handleClose }) => ( Show Y-Axis Show X-Axis )} )} ); }, []); return ; } ``` ## Props | Prop | Type | Required | Default | Description | | --- | --- | --- | --- | --- | | `activeTabRect` | `Rect` | Yes | `-` | - | | `_dragX` | `MotionValue` | No | `-` | Usually, dragging uses the layout project engine, and applies transforms to the underlying VisualElement. Passing MotionValues as _dragX and _dragY instead applies drag updates to these motion values. This allows you to manually control how updates from a drag gesture on an element is applied. | | `_dragY` | `MotionValue` | No | `-` | Usually, dragging uses the layout project engine, and applies transforms to the underlying VisualElement. Passing MotionValues as _dragX and _dragY instead applies drag updates to these motion values. This allows you to manually control how updates from a drag gesture on an element is applied. | | `alignContent` | `ResponsiveProp
` | No | `-` | - | | `alignItems` | `ResponsiveProp
` | No | `-` | - | | `alignSelf` | `ResponsiveProp
` | No | `-` | - | | `animate` | `boolean \| VariantLabels \| AnimationControls \| TargetAndTransition` | No | `-` | Values to animate to, variant label(s), or AnimationControls. jsx // As values // As variant // Multiple variants // AnimationControls | | `as` | `div` | No | `-` | - | | `aspectRatio` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `background` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `-` | - | | `borderBottomLeftRadius` | `0 \| 100 \| 200 \| 300 \| 400 \| 500 \| 600 \| 700 \| 800 \| 900 \| 1000` | No | `-` | - | | `borderBottomRightRadius` | `0 \| 100 \| 200 \| 300 \| 400 \| 500 \| 600 \| 700 \| 800 \| 900 \| 1000` | No | `-` | - | | `borderBottomWidth` | `0 \| 100 \| 200 \| 300 \| 400 \| 500` | No | `-` | - | | `borderColor` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `-` | - | | `borderEndWidth` | `0 \| 100 \| 200 \| 300 \| 400 \| 500` | No | `-` | - | | `borderRadius` | `0 \| 100 \| 200 \| 300 \| 400 \| 500 \| 600 \| 700 \| 800 \| 900 \| 1000` | No | `-` | - | | `borderStartWidth` | `0 \| 100 \| 200 \| 300 \| 400 \| 500` | No | `-` | - | | `borderTopLeftRadius` | `0 \| 100 \| 200 \| 300 \| 400 \| 500 \| 600 \| 700 \| 800 \| 900 \| 1000` | No | `-` | - | | `borderTopRightRadius` | `0 \| 100 \| 200 \| 300 \| 400 \| 500 \| 600 \| 700 \| 800 \| 900 \| 1000` | No | `-` | - | | `borderTopWidth` | `0 \| 100 \| 200 \| 300 \| 400 \| 500` | No | `-` | - | | `borderWidth` | `0 \| 100 \| 200 \| 300 \| 400 \| 500` | No | `-` | - | | `bordered` | `boolean` | No | `-` | Add a border around all sides of the box. | | `borderedBottom` | `boolean` | No | `-` | Add a border to the bottom side of the box. | | `borderedEnd` | `boolean` | No | `-` | Add a border to the trailing side of the box. | | `borderedHorizontal` | `boolean` | No | `-` | Add a border to the leading and trailing sides of the box. | | `borderedStart` | `boolean` | No | `-` | Add a border to the leading side of the box. | | `borderedTop` | `boolean` | No | `-` | Add a border to the top side of the box. | | `borderedVertical` | `boolean` | No | `-` | Add a border to the top and bottom sides of the box. | | `bottom` | `ResponsiveProp>` | No | `-` | - | | `color` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `-` | - | | `columnGap` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - | | `custom` | `any` | No | `-` | Custom data to use to resolve dynamic variants differently for each animating component. jsx const variants = { visible: (custom) => ({ opacity: 1, transition: { delay: custom * 0.2 } }) } | | `dangerouslySetBackground` | `string` | No | `-` | - | | `display` | `ResponsiveProp` | No | `-` | - | | `drag` | `boolean \| x \| y` | No | `-` | Enable dragging for this element. Set to false by default. Set true to drag in both directions. Set x or y to only drag in a specific direction. jsx | | `dragConstraints` | `false \| Partial \| RefObject` | No | `-` | Applies constraints on the permitted draggable area. It can accept an object of optional top, left, right, and bottom values, measured in pixels. This will define a distance the named edge of the draggable component. Alternatively, it can accept a ref to another component created with Reacts useRef hook. This ref should be passed both to the draggable components dragConstraints prop, and the ref of the component you want to use as constraints. jsx // In pixels // As a ref to another component const MyComponent = () => { const constraintsRef = useRef(null) return ( ) } | | `dragControls` | `DragControls` | No | `-` | Usually, dragging is initiated by pressing down on a component and moving it. For some use-cases, for instance clicking at an arbitrary point on a video scrubber, we might want to initiate dragging from a different component than the draggable one. By creating a dragControls using the useDragControls hook, we can pass this into the draggable components dragControls prop. It exposes a start method that can start dragging from pointer events on other components. jsx const dragControls = useDragControls() function startDrag(event) { dragControls.start(event, { snapToCursor: true }) } return ( <>
) | | `dragDirectionLock` | `boolean` | No | `-` | If true, this will lock dragging to the initially-detected direction. Defaults to false. jsx | | `dragElastic` | `number \| false \| true \| Partial` | No | `-` | The degree of movement allowed outside constraints. 0 = no movement, 1 = full movement. Set to 0.5 by default. Can also be set as false to disable movement. By passing an object of top/right/bottom/left, individual values can be set per constraint. Any missing values will be set to 0. jsx | | `dragListener` | `boolean` | No | `-` | By default, if drag is defined on a component then an event listener will be attached to automatically initiate dragging when a user presses down on it. By setting dragListener to false, this event listener will not be created. jsx const dragControls = useDragControls() function startDrag(event) { dragControls.start(event, { snapToCursor: true }) } return ( <>
) | | `dragMomentum` | `boolean` | No | `-` | Apply momentum from the pan gesture to the component when dragging finishes. Set to true by default. jsx | | `dragPropagation` | `boolean` | No | `-` | Allows drag gesture propagation to child components. Set to false by default. jsx | | `dragSnapToOrigin` | `boolean` | No | `-` | If true, element will snap back to its origin when dragging ends. Enabling this is the equivalent of setting all dragConstraints axes to 0 with dragElastic={1}, but when used together dragConstraints can define a wider draggable area and dragSnapToOrigin will ensure the element animates back to its origin on release. | | `dragTransition` | `Partial>` | No | `-` | Allows you to change dragging inertia parameters. When releasing a draggable Frame, an animation with type inertia starts. The animation is based on your dragging velocity. This property allows you to customize it. See {@link https://framer.com/api/animation/#inertia Inertia} for all properties you can use. jsx | | `elevation` | `0 \| 1 \| 2` | No | `-` | - | | `exit` | `VariantLabels \| TargetAndTransition` | No | `-` | A target to animate to when this component is removed from the tree. This component **must** be the first animatable child of an AnimatePresence to enable this exit animation. This limitation exists because React doesnt allow components to defer unmounting until after an animation is complete. Once this limitation is fixed, the AnimatePresence component will be unnecessary. jsx import { AnimatePresence, motion } from framer-motion export const MyComponent = ({ isVisible }) => { return ( {isVisible && ( )} ) } | | `flexBasis` | `ResponsiveProp>` | No | `-` | - | | `flexDirection` | `ResponsiveProp` | No | `-` | - | | `flexGrow` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset` | No | `-` | - | | `flexShrink` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset` | No | `-` | - | | `flexWrap` | `ResponsiveProp` | No | `-` | - | | `font` | `ResponsiveProp` | No | `-` | - | | `fontFamily` | `ResponsiveProp` | No | `-` | - | | `fontSize` | `ResponsiveProp` | No | `-` | - | | `fontWeight` | `ResponsiveProp` | No | `-` | - | | `gap` | `0 \| 5 \| 10 \| 0.25 \| 0.5 \| 0.75 \| 1 \| 1.5 \| 2 \| 3 \| 4 \| 6 \| 7 \| 8 \| 9` | No | `-` | - | | `globalTapTarget` | `boolean` | No | `-` | If true, the tap gesture will attach its start listener to window. Note: This is not supported publically. | | `grid` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| none` | No | `-` | - | | `gridArea` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridAutoColumns` | `ResponsiveProp>` | No | `-` | - | | `gridAutoFlow` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| row \| column \| dense` | No | `-` | - | | `gridAutoRows` | `ResponsiveProp>` | No | `-` | - | | `gridColumn` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridColumnEnd` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridColumnStart` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridRow` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridRowEnd` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridRowStart` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| auto` | No | `-` | - | | `gridTemplate` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| none` | No | `-` | - | | `gridTemplateAreas` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset \| none` | No | `-` | - | | `gridTemplateColumns` | `ResponsiveProp>` | No | `-` | - | | `gridTemplateRows` | `ResponsiveProp>` | No | `-` | - | | `height` | `ResponsiveProp>` | No | `-` | - | | `ignoreStrict` | `boolean` | No | `-` | - | | `inherit` | `boolean` | No | `-` | - | | `initial` | `boolean \| MakeCustomValueType \| VariantLabels` | No | `-` | Properties, variant label or array of variant labels to start in. Set to false to initialise with the values in animate (disabling the mount animation) jsx // As values // As variant // Multiple variants // As false (disable mount animation) | | `justifyContent` | `ResponsiveProp` | No | `-` | - | | `key` | `Key \| null` | No | `-` | - | | `layout` | `boolean \| position \| size \| preserve-aspect` | No | `-` | If true, this component will automatically animate to its new position when its layout changes. jsx This will perform a layout animation using performant transforms. Part of this technique involved animating an elements scale. This can introduce visual distortions on children, boxShadow and borderRadius. To correct distortion on immediate children, add layout to those too. boxShadow and borderRadius will automatically be corrected if they are already being animated on this component. Otherwise, set them directly via the initial prop. If layout is set to position, the size of the component will change instantly and only its position will animate. If layout is set to size, the position of the component will change instantly but its size will animate. If layout is set to size, the position of the component will change instantly and only its size will animate. If layout is set to preserve-aspect, the component will animate size & position if the aspect ratio remains the same between renders, and just position if the ratio changes. | | `layoutDependency` | `any` | No | `-` | - | | `layoutId` | `string` | No | `-` | Enable shared layout transitions between different components with the same layoutId. When a component with a layoutId is removed from the React tree, and then added elsewhere, it will visually animate from the previous components bounding box and its latest animated values. jsx {items.map(item => ( {item.name} {item.isSelected && } ))} If the previous component remains in the tree it will crossfade with the new component. | | `layoutRoot` | `boolean` | No | `-` | Whether an element should be considered a layout root, where all children will be forced to resolve relatively to it. Currently used for position: sticky elements in Framer. | | `layoutScroll` | `boolean` | No | `-` | Whether a projection node should measure its scroll when it or its descendants update their layout. | | `left` | `ResponsiveProp>` | No | `-` | - | | `lineHeight` | `ResponsiveProp` | No | `-` | - | | `margin` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginBottom` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginEnd` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginStart` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginTop` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginX` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `marginY` | `ResponsiveProp<0 \| -5 \| -10 \| -0.25 \| -0.5 \| -0.75 \| -1 \| -1.5 \| -2 \| -3 \| -4 \| -6 \| -7 \| -8 \| -9>` | No | `-` | - | | `maxHeight` | `ResponsiveProp>` | No | `-` | - | | `maxWidth` | `ResponsiveProp>` | No | `-` | - | | `minHeight` | `ResponsiveProp>` | No | `-` | - | | `minWidth` | `ResponsiveProp>` | No | `-` | - | | `onAnimationComplete` | `((definition: AnimationDefinition) => void)` | No | `-` | Callback when animation defined in animate is complete. The provided callback will be called with the triggering animation definition. If this is a variant, itll be the variant name, and if a target object then itll be the target object. This way, its possible to figure out which animation has completed. jsx function onComplete() { console.log(Animation completed) } { console.log(Completed animating, definition) }} /> | | `onBeforeLayoutMeasure` | `((box: Box) => void)` | No | `-` | - | | `onChange` | `FormEventHandler` | No | `-` | - | | `onDirectionLock` | `((axis: x \| y) => void)` | No | `-` | Callback function that fires a drag direction is determined. jsx console.log(axis)} /> | | `onDragTransitionEnd` | `(() => void)` | No | `-` | Callback function that fires when drag momentum/bounce transition finishes. jsx console.log(Drag transition complete)} /> | | `onHoverEnd` | `((event: MouseEvent, info: EventInfo) => void)` | No | `-` | Callback function that fires when pointer stops hovering over the component. jsx console.log(Hover ends)} /> | | `onHoverStart` | `((event: MouseEvent, info: EventInfo) => void)` | No | `-` | Callback function that fires when pointer starts hovering over the component. jsx console.log(Hover starts)} /> | | `onLayoutAnimationComplete` | `(() => void)` | No | `-` | A callback that will fire when a layout animation on this component completes. | | `onLayoutAnimationStart` | `(() => void)` | No | `-` | A callback that will fire when a layout animation on this component starts. | | `onLayoutMeasure` | `((box: Box, prevBox: Box) => void)` | No | `-` | - | | `onMeasureDragConstraints` | `((constraints: BoundingBox) => void \| BoundingBox)` | No | `-` | If dragConstraints is set to a React ref, this callback will call with the measured drag constraints. | | `onPan` | `((event: PointerEvent, info: PanInfo) => void)` | No | `-` | Callback function that fires when the pan gesture is recognised on this element. **Note:** For pan gestures to work correctly with touch input, the element needs touch scrolling to be disabled on either x/y or both axis with the [touch-action](https://developer.mozilla.org/en-US/docs/Web/CSS/touch-action) CSS rule. jsx function onPan(event, info) { console.log(info.point.x, info.point.y) } | | `onPanEnd` | `((event: PointerEvent, info: PanInfo) => void)` | No | `-` | Callback function that fires when the pan gesture ends on this element. jsx function onPanEnd(event, info) { console.log(info.point.x, info.point.y) } | | `onPanSessionStart` | `((event: PointerEvent, info: EventInfo) => void)` | No | `-` | Callback function that fires when we begin detecting a pan gesture. This is analogous to onMouseStart or onTouchStart. jsx function onPanSessionStart(event, info) { console.log(info.point.x, info.point.y) } | | `onPanStart` | `((event: PointerEvent, info: PanInfo) => void)` | No | `-` | Callback function that fires when the pan gesture begins on this element. jsx function onPanStart(event, info) { console.log(info.point.x, info.point.y) } | | `onTap` | `((event: MouseEvent \| TouchEvent \| PointerEvent, info: TapInfo) => void)` | No | `-` | Callback when the tap gesture successfully ends on this element. jsx function onTap(event, info) { console.log(info.point.x, info.point.y) } | | `onTapCancel` | `((event: MouseEvent \| TouchEvent \| PointerEvent, info: TapInfo) => void)` | No | `-` | Callback when the tap gesture ends outside this element. jsx function onTapCancel(event, info) { console.log(info.point.x, info.point.y) } | | `onTapStart` | `((event: MouseEvent \| TouchEvent \| PointerEvent, info: TapInfo) => void)` | No | `-` | Callback when the tap gesture starts on this element. jsx function onTapStart(event, info) { console.log(info.point.x, info.point.y) } | | `onUpdate` | `((latest: ResolvedValues) => void)` | No | `-` | Callback with latest motion values, fired max once per frame. jsx function onUpdate(latest) { console.log(latest.x, latest.opacity) } | | `onViewportEnter` | `ViewportEventHandler` | No | `-` | - | | `onViewportLeave` | `ViewportEventHandler` | No | `-` | - | | `opacity` | `-moz-initial \| inherit \| initial \| revert \| revert-layer \| unset` | No | `-` | - | | `overflow` | `ResponsiveProp