Motion

Fade in

A block that rises into place as it scrolls into view.

betav0.1.0 Chromium 103 ui-scale safe

Install

Copies the file into components/ds/, with its registry dependencies and npm packages. See Installation for the one-time setup.
bunx shadcn@3 add @fastrp/fade-in

Examples

Default

Open alone
01

Hesabını bağla

02

Karakterini yarat

03

Şehre gir

from={{ x: -60 }} soldan kayarak gelir.

API

<FadeIn />

Fades a block into place the first time it scrolls into view. Under reduced motion it is a fade with no travel. The travel is a CSS calc on `--fade` (1 → 0) times `--ui-px`, not motion's own `x`/`y`: an inline transform in pixels would stay 1080p-sized in the FiveM NUI, which scales every length through `--ui-px`. `transform`, not the `translate` property, which Chromium 103 lacks.

PropTypeDefaultNotes
aboutstring—
accessKeystring—
aria-activedescendantstring—
aria-atomicBooleanish—
aria-autocomplete"none" | "list" | "inline" | "both"—
aria-braillelabelstring—
aria-brailleroledescriptionstring—
aria-busyBooleanish—
aria-checkedboolean | "true" | "false" | "mixed"—
aria-colcountnumber—
aria-colindexnumber—
aria-colindextextstring—
aria-colspannumber—
aria-controlsstring—
aria-currentboolean | "true" | "false" | "time" | "page" | "step" | "location" | "date"—
aria-describedbystring—
aria-descriptionstring—
aria-detailsstring—
aria-disabledBooleanish—
aria-dropeffect"link" | "none" | "copy" | "execute" | "move" | "popup"—
aria-errormessagestring—
aria-expandedBooleanish—
aria-flowtostring—
aria-grabbedBooleanish—
aria-haspopupboolean | "true" | "false" | "dialog" | "menu" | "grid" | "listbox" | "tree"—
aria-hiddenBooleanish—
aria-invalidboolean | "true" | "false" | "grammar" | "spelling"—
aria-keyshortcutsstring—
aria-labelstring—
aria-labelledbystring—
aria-levelnumber—
aria-live"off" | "assertive" | "polite"—
aria-modalBooleanish—
aria-multilineBooleanish—
aria-multiselectableBooleanish—
aria-orientation"horizontal" | "vertical"—
aria-ownsstring—
aria-placeholderstring—
aria-posinsetnumber—
aria-pressedboolean | "true" | "false" | "mixed"—
aria-readonlyBooleanish—
aria-relevant"text" | "additions" | "additions removals" | "additions text" | "all" | "removals" | "removals additions" | "removals text" | "text additions" | "text removals"—
aria-requiredBooleanish—
aria-roledescriptionstring—
aria-rowcountnumber—
aria-rowindexnumber—
aria-rowindextextstring—
aria-rowspannumber—
aria-selectedBooleanish—
aria-setsizenumber—
aria-sort"none" | "ascending" | "descending" | "other"—
aria-valuemaxnumber—
aria-valueminnumber—
aria-valuenownumber—
aria-valuetextstring—
autoCapitalize"off" | "none" | "on" | "sentences" | "words" | "characters" | (string & {})—
autoCorrectstring—
autoFocusboolean—
autoSavestring—
classNamestring—
colorstring—
contentstring—
contentEditableBooleanish | "inherit" | "plaintext-only"—
contextMenustring—
dangerouslySetInnerHTML{ __html: string | TrustedHTML; }—
datatypestring—
defaultCheckedboolean—
defaultValuestring | number | readonly string[]—
delaynumber0Seconds.
dirstring—
draggableBooleanish—
durationnumberDURATION_S.slowerSeconds; `DURATION_S.slower` by default.
enterKeyHint"search" | "enter" | "done" | "go" | "next" | "previous" | "send"—
exportpartsstring—
from{ x?: number; y?: number; } | undefined{ y: 40 }Where it comes from, in pixels at 1080p: `y` rises, `x` slides in from that side.
hiddenboolean—
idstring—
inertboolean—
inlistany—
inputMode"search" | "text" | "none" | "tel" | "url" | "email" | "numeric" | "decimal"—
isstring—
itemIDstring—
itemPropstring—
itemRefstring—
itemScopeboolean—
itemTypestring—
keyKey—
langstring—
noncestring—
onAbortReactEventHandler<HTMLDivElement>—
onAbortCaptureReactEventHandler<HTMLDivElement>—
onAnimationEndAnimationEventHandler<HTMLDivElement>—
onAnimationEndCaptureAnimationEventHandler<HTMLDivElement>—
onAnimationIterationAnimationEventHandler<HTMLDivElement>—
onAnimationIterationCaptureAnimationEventHandler<HTMLDivElement>—
onAnimationStartCaptureAnimationEventHandler<HTMLDivElement>—
onAuxClickMouseEventHandler<HTMLDivElement>—
onAuxClickCaptureMouseEventHandler<HTMLDivElement>—
onBeforeInputInputEventHandler<HTMLDivElement>—
onBeforeInputCaptureInputEventHandler<HTMLDivElement>—
onBeforeToggleToggleEventHandler<HTMLDivElement>—
onBlurFocusEventHandler<HTMLDivElement>—
onBlurCaptureFocusEventHandler<HTMLDivElement>—
onCanPlayReactEventHandler<HTMLDivElement>—
onCanPlayCaptureReactEventHandler<HTMLDivElement>—
onCanPlayThroughReactEventHandler<HTMLDivElement>—
onCanPlayThroughCaptureReactEventHandler<HTMLDivElement>—
onChangeChangeEventHandler<HTMLDivElement, Element>—
onChangeCaptureChangeEventHandler<HTMLDivElement, Element>—
onClickMouseEventHandler<HTMLDivElement>—
onClickCaptureMouseEventHandler<HTMLDivElement>—
onCompositionEndCompositionEventHandler<HTMLDivElement>—
onCompositionEndCaptureCompositionEventHandler<HTMLDivElement>—
onCompositionStartCompositionEventHandler<HTMLDivElement>—
onCompositionStartCaptureCompositionEventHandler<HTMLDivElement>—
onCompositionUpdateCompositionEventHandler<HTMLDivElement>—
onCompositionUpdateCaptureCompositionEventHandler<HTMLDivElement>—
onContextMenuMouseEventHandler<HTMLDivElement>—
onContextMenuCaptureMouseEventHandler<HTMLDivElement>—
onCopyClipboardEventHandler<HTMLDivElement>—
onCopyCaptureClipboardEventHandler<HTMLDivElement>—
onCutClipboardEventHandler<HTMLDivElement>—
onCutCaptureClipboardEventHandler<HTMLDivElement>—
onDoubleClickMouseEventHandler<HTMLDivElement>—
onDoubleClickCaptureMouseEventHandler<HTMLDivElement>—
onDragCaptureDragEventHandler<HTMLDivElement>—
onDragEndCaptureDragEventHandler<HTMLDivElement>—
onDragEnterDragEventHandler<HTMLDivElement>—
onDragEnterCaptureDragEventHandler<HTMLDivElement>—
onDragExitDragEventHandler<HTMLDivElement>—
onDragExitCaptureDragEventHandler<HTMLDivElement>—
onDragLeaveDragEventHandler<HTMLDivElement>—
onDragLeaveCaptureDragEventHandler<HTMLDivElement>—
onDragOverDragEventHandler<HTMLDivElement>—
onDragOverCaptureDragEventHandler<HTMLDivElement>—
onDragStartCaptureDragEventHandler<HTMLDivElement>—
onDropDragEventHandler<HTMLDivElement>—
onDropCaptureDragEventHandler<HTMLDivElement>—
onDurationChangeReactEventHandler<HTMLDivElement>—
onDurationChangeCaptureReactEventHandler<HTMLDivElement>—
onEmptiedReactEventHandler<HTMLDivElement>—
onEmptiedCaptureReactEventHandler<HTMLDivElement>—
onEncryptedReactEventHandler<HTMLDivElement>—
onEncryptedCaptureReactEventHandler<HTMLDivElement>—
onEndedReactEventHandler<HTMLDivElement>—
onEndedCaptureReactEventHandler<HTMLDivElement>—
onErrorReactEventHandler<HTMLDivElement>—
onErrorCaptureReactEventHandler<HTMLDivElement>—
onFocusFocusEventHandler<HTMLDivElement>—
onFocusCaptureFocusEventHandler<HTMLDivElement>—
onGotPointerCapturePointerEventHandler<HTMLDivElement>—
onGotPointerCaptureCapturePointerEventHandler<HTMLDivElement>—
onInputInputEventHandler<HTMLDivElement>—
onInputCaptureInputEventHandler<HTMLDivElement>—
onInvalidReactEventHandler<HTMLDivElement>—
onInvalidCaptureReactEventHandler<HTMLDivElement>—
onKeyDownKeyboardEventHandler<HTMLDivElement>—
onKeyDownCaptureKeyboardEventHandler<HTMLDivElement>—
onKeyPressKeyboardEventHandler<HTMLDivElement>—
onKeyPressCaptureKeyboardEventHandler<HTMLDivElement>—
onKeyUpKeyboardEventHandler<HTMLDivElement>—
onKeyUpCaptureKeyboardEventHandler<HTMLDivElement>—
onLoadReactEventHandler<HTMLDivElement>—
onLoadCaptureReactEventHandler<HTMLDivElement>—
onLoadedDataReactEventHandler<HTMLDivElement>—
onLoadedDataCaptureReactEventHandler<HTMLDivElement>—
onLoadedMetadataReactEventHandler<HTMLDivElement>—
onLoadedMetadataCaptureReactEventHandler<HTMLDivElement>—
onLoadStartReactEventHandler<HTMLDivElement>—
onLoadStartCaptureReactEventHandler<HTMLDivElement>—
onLostPointerCapturePointerEventHandler<HTMLDivElement>—
onLostPointerCaptureCapturePointerEventHandler<HTMLDivElement>—
onMouseDownMouseEventHandler<HTMLDivElement>—
onMouseDownCaptureMouseEventHandler<HTMLDivElement>—
onMouseEnterMouseEventHandler<HTMLDivElement>—
onMouseLeaveMouseEventHandler<HTMLDivElement>—
onMouseMoveMouseEventHandler<HTMLDivElement>—
onMouseMoveCaptureMouseEventHandler<HTMLDivElement>—
onMouseOutMouseEventHandler<HTMLDivElement>—
onMouseOutCaptureMouseEventHandler<HTMLDivElement>—
onMouseOverMouseEventHandler<HTMLDivElement>—
onMouseOverCaptureMouseEventHandler<HTMLDivElement>—
onMouseUpMouseEventHandler<HTMLDivElement>—
onMouseUpCaptureMouseEventHandler<HTMLDivElement>—
onPasteClipboardEventHandler<HTMLDivElement>—
onPasteCaptureClipboardEventHandler<HTMLDivElement>—
onPauseReactEventHandler<HTMLDivElement>—
onPauseCaptureReactEventHandler<HTMLDivElement>—
onPlayReactEventHandler<HTMLDivElement>—
onPlayCaptureReactEventHandler<HTMLDivElement>—
onPlayingReactEventHandler<HTMLDivElement>—
onPlayingCaptureReactEventHandler<HTMLDivElement>—
onPointerCancelPointerEventHandler<HTMLDivElement>—
onPointerCancelCapturePointerEventHandler<HTMLDivElement>—
onPointerDownPointerEventHandler<HTMLDivElement>—
onPointerDownCapturePointerEventHandler<HTMLDivElement>—
onPointerEnterPointerEventHandler<HTMLDivElement>—
onPointerLeavePointerEventHandler<HTMLDivElement>—
onPointerMovePointerEventHandler<HTMLDivElement>—
onPointerMoveCapturePointerEventHandler<HTMLDivElement>—
onPointerOutPointerEventHandler<HTMLDivElement>—
onPointerOutCapturePointerEventHandler<HTMLDivElement>—
onPointerOverPointerEventHandler<HTMLDivElement>—
onPointerOverCapturePointerEventHandler<HTMLDivElement>—
onPointerUpPointerEventHandler<HTMLDivElement>—
onPointerUpCapturePointerEventHandler<HTMLDivElement>—
onProgressReactEventHandler<HTMLDivElement>—
onProgressCaptureReactEventHandler<HTMLDivElement>—
onRateChangeReactEventHandler<HTMLDivElement>—
onRateChangeCaptureReactEventHandler<HTMLDivElement>—
onResetReactEventHandler<HTMLDivElement>—
onResetCaptureReactEventHandler<HTMLDivElement>—
onScrollUIEventHandler<HTMLDivElement>—
onScrollCaptureUIEventHandler<HTMLDivElement>—
onScrollEndUIEventHandler<HTMLDivElement>—
onScrollEndCaptureUIEventHandler<HTMLDivElement>—
onSeekedReactEventHandler<HTMLDivElement>—
onSeekedCaptureReactEventHandler<HTMLDivElement>—
onSeekingReactEventHandler<HTMLDivElement>—
onSeekingCaptureReactEventHandler<HTMLDivElement>—
onSelectReactEventHandler<HTMLDivElement>—
onSelectCaptureReactEventHandler<HTMLDivElement>—
onStalledReactEventHandler<HTMLDivElement>—
onStalledCaptureReactEventHandler<HTMLDivElement>—
onSubmitSubmitEventHandler<HTMLDivElement>—
onSubmitCaptureSubmitEventHandler<HTMLDivElement>—
onSuspendReactEventHandler<HTMLDivElement>—
onSuspendCaptureReactEventHandler<HTMLDivElement>—
onTimeUpdateReactEventHandler<HTMLDivElement>—
onTimeUpdateCaptureReactEventHandler<HTMLDivElement>—
onToggleToggleEventHandler<HTMLDivElement>—
onTouchCancelTouchEventHandler<HTMLDivElement>—
onTouchCancelCaptureTouchEventHandler<HTMLDivElement>—
onTouchEndTouchEventHandler<HTMLDivElement>—
onTouchEndCaptureTouchEventHandler<HTMLDivElement>—
onTouchMoveTouchEventHandler<HTMLDivElement>—
onTouchMoveCaptureTouchEventHandler<HTMLDivElement>—
onTouchStartTouchEventHandler<HTMLDivElement>—
onTouchStartCaptureTouchEventHandler<HTMLDivElement>—
onTransitionCancelTransitionEventHandler<HTMLDivElement>—
onTransitionCancelCaptureTransitionEventHandler<HTMLDivElement>—
onTransitionEndTransitionEventHandler<HTMLDivElement>—
onTransitionEndCaptureTransitionEventHandler<HTMLDivElement>—
onTransitionRunTransitionEventHandler<HTMLDivElement>—
onTransitionRunCaptureTransitionEventHandler<HTMLDivElement>—
onTransitionStartTransitionEventHandler<HTMLDivElement>—
onTransitionStartCaptureTransitionEventHandler<HTMLDivElement>—
onVolumeChangeReactEventHandler<HTMLDivElement>—
onVolumeChangeCaptureReactEventHandler<HTMLDivElement>—
onWaitingReactEventHandler<HTMLDivElement>—
onWaitingCaptureReactEventHandler<HTMLDivElement>—
onWheelWheelEventHandler<HTMLDivElement>—
onWheelCaptureWheelEventHandler<HTMLDivElement>—
partstring—
popover"" | "auto" | "manual" | "hint"—
popoverTargetstring—
popoverTargetAction"toggle" | "show" | "hide"—
prefixstring—
propertystring—
radioGroupstring—
refRef<HTMLDivElement>—
relstring—
repeatbooleanfalsePlay again every time it re-enters, instead of once.
resourcestring—
resultsnumber—
revstring—
roleAriaRole—
securitystring—
slotstring—
spellCheckBooleanish—
suppressContentEditableWarningboolean—
suppressHydrationWarningboolean—
tabIndexnumber—
titlestring—
translate"yes" | "no"—
typeofstring—
unselectable"off" | "on"—
vocabstring—

Dependencies

npm

  • @fastrp/design-tokens
  • motion@^12.40.0

Source

components/ds/fade-in.tsxShow
'use client';

import { DURATION_S, EASE } from '@fastrp/design-tokens/motion';
import { type HTMLMotionProps, motion, useReducedMotion } from 'motion/react';
import { useScrollRoot } from '@/components/ds/scroll-root';

// @fast-ds [email protected]

export type FadeInProps = Omit<
  HTMLMotionProps<'div'>,
  'initial' | 'whileInView' | 'viewport' | 'animate'
> & {
  /** Where it comes from, in pixels at 1080p: `y` rises, `x` slides in from that side. */
  from?: { x?: number; y?: number };
  /** Seconds. */
  delay?: number;
  /** Seconds; `DURATION_S.slower` by default. */
  duration?: number;
  /** Play again every time it re-enters, instead of once. */
  repeat?: boolean;
};

/**
 * Fades a block into place the first time it scrolls into view. Under reduced motion it is a fade
 * with no travel.
 *
 * The travel is a CSS calc on `--fade` (1 → 0) times `--ui-px`, not motion's own `x`/`y`: an inline
 * transform in pixels would stay 1080p-sized in the FiveM NUI, which scales every length through
 * `--ui-px`. `transform`, not the `translate` property, which Chromium 103 lacks.
 */
function FadeIn({
  from = { y: 40 },
  delay = 0,
  duration = DURATION_S.slower,
  repeat = false,
  style,
  children,
  ...props
}: FadeInProps) {
  const reduceMotion = useReducedMotion();
  const root = useScrollRoot();
  const x = from.x ?? 0;
  const y = from.y ?? 0;

  return (
    <motion.div
      data-slot="fade-in"
      initial={{ opacity: 0, '--fade': reduceMotion ? 0 : 1 }}
      whileInView={{ opacity: 1, '--fade': 0 }}
      viewport={{ once: !repeat, margin: '0px 0px -10% 0px', root }}
      transition={{ duration, delay, ease: EASE }}
      style={{
        transform: `translate3d(calc(var(--fade, 0) * ${x} * var(--ui-px, 1px)), calc(var(--fade, 0) * ${y} * var(--ui-px, 1px)), 0)`,
        ...style,
      }}
      {...props}
    >
      {children}
    </motion.div>
  );
}

export { FadeIn };