Motion link
100xui/motion-linkFreeBlock
Exclusive to Next.js. A reusable component that extends the <Link/> component from "next/link" to power interactive animations using motion.dev. It includes three predefined variants: <MotionLinkUnderline/>, <MotionLinkSlideText/>, and <MotionLinkWithIcon/>, while the base <MotionLink/> provides full flexibility to define custom animations with MotionProps like whileFocus, whileHover, and whileInView.
Live preview
live · rendered by the registry
Rendered by 100xui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://100xui.com/r/motion-link.jsonSource
1"use client";23import React from "react";4import Link, { type LinkProps } from "next/link";5import { motion, stagger, MotionConfig, type MotionProps } from "motion/react";67import { cn } from "@/lib/utils";89const MLink = motion.create(Link);1011type CombinedAnchorProps = Omit<12 React.AnchorHTMLAttributes<HTMLAnchorElement>,13 keyof LinkProps | "href"14>;1516export type MotionLinkBaseProps = LinkProps & MotionProps & CombinedAnchorProps;17export function MotionLink(props: MotionLinkBaseProps) {18 return <MLink {...props} />;19}2021export interface MotionLinkUnderlineProps extends MotionLinkBaseProps {22 underlineColor?: React.CSSProperties["background"];23 underlineHeight?: React.CSSProperties["height"];24 startDirection?: "left" | "right";25 endDirection?: "left" | "right";26}27export function MotionLinkUnderline({28 className,29 children,30 underlineColor = "var(--color-foreground)",31 underlineHeight = "2px",32 startDirection = "left",33 endDirection = "right",34 ...rest35}: MotionLinkUnderlineProps) {36 const isStartDirectionLeft = startDirection === "left";37 const isEndDirectionRight = endDirection === "right";3839 const underlineActiveStyles = {40 width: "100%",41 ...(isStartDirectionLeft42 ? { left: "0px", right: "auto" }43 : { left: "auto", right: "0px" }),44 };4546 return (47 <MotionLink48 initial="initial"49 whileFocus="whileFocus"50 whileHover="whileHover"51 className={cn(52 "!relative w-fit !text-nowrap text-inherit focus-visible:!outline-0",53 className,54 )}55 {...rest}56 >57 {children}58 <motion.div59 style={{60 height: underlineHeight,61 background: underlineColor,62 }}63 className="absolute bottom-0"64 variants={{65 initial: {66 width: "0%",67 ...(isEndDirectionRight68 ? { left: "auto", right: "0px" }69 : { left: "0px", right: "auto" }),70 },71 whileHover: underlineActiveStyles,72 whileFocus: underlineActiveStyles,73 }}74 transition={{75 left: { duration: 0 },76 right: { duration: 0 },77 default: { ease: "easeInOut" },78 }}79 />80 </MotionLink>81 );82}8384export interface MotionLinkSlideTextProps extends MotionLinkBaseProps {85 children: string;86}8788export function MotionLinkSlideText({89 children,90 className,91 ...rest92}: MotionLinkSlideTextProps) {93 const characters = children.split("");94// … truncated
What it pulls in
npm packages
Files it writes
More from 100xui
All 14 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Apple galleryapple-gallery | 100xui | Blocks | Free | 1 dep | |
| Chat bento cardchat-bento-card | 100xui | Blocks | Free | 1 dep | |
| demosdemos | 100xui | Blocks | Free | no deps · 12 files | |
| In-page navbarin-page-navbar | 100xui | Blocks | Free | 1 dep · 2 files | |
| internalsinternals | 100xui | Blocks | Free | no deps · 4 files | |
| iPhone 3D mockupiphone-3d-mockup | 100xui | Blocks | Free | no deps | |
| Menu wheelmenu-wheel | 100xui | Blocks | Free | 1 dep | |
| Morph modalmorph-modal | 100xui | Blocks | Free | 1 dep |
