Component
Component
Component
Component
Galaxy Button Component
Galaxy Button Component
Galaxy Button Component
Galaxy Button Component
This is a remake of the galaxy button first showcased on the Genius website. It's a truly engaging effect that can certainly elevate your site to new heights.
This is a remake of the galaxy button first showcased on the Genius website. It's a truly engaging effect that can certainly elevate your site to new heights.
This is a remake of the galaxy button first showcased on the Genius website. It's a truly engaging effect that can certainly elevate your site to new heights.
This is a remake of the galaxy button first showcased on the Genius website. It's a truly engaging effect that can certainly elevate your site to new heights.




Features
This button component utilizes two variants: a "default" and a "hover" variant. In the hover state, the background image (the galaxy) becomes visible. This has a code override applied, causing it to move with the cursor.

Step / 01
Remix the project.

Step / 02
See how it's built.

Step / 03
Try recreating it for practice.
Code override
You can also copy this code to create a new code override in your project, which will make the galaxy background move as you hover over the button.
// © Framer University. All rights reserved.
import type { ComponentType } from "react"
import { useRef, useState } from "react"
import { useEffect } from "react"
import { useSpring, animated } from "react-spring"
export function withCursorFollow(Component): ComponentType {
return (props) => {
const ref = useRef(null)
const [isHovering, setIsHovering] = useState(false)
const [originalPosition, setOriginalPosition] = useState({
left: 0,
top: 0,
})
const [centerPosition, setCenterPosition] = useState({
left: 0,
top: 0,
})
const springProps = useSpring({
left: isHovering ? originalPosition.left : centerPosition.left,
top: isHovering ? originalPosition.top : centerPosition.top,
config: { mass: 1, tension: 170, friction: 26 },
})
useEffect(() => {
if (!ref.current) return
const buttonRect = ref.current.getBoundingClientRect()
const elementRect = ref.current.getBoundingClientRect()
setCenterPosition({
left: buttonRect.width / 2 - elementRect.width / 2,
top: buttonRect.height / 2 - elementRect.height / 2,
})
const handleMouseMove = (e) => {
if (!ref.current) return
if (e.target.closest("button")) {
setIsHovering(true)
const buttonRect = e.target.getBoundingClientRect()
const elementRect = ref.current.getBoundingClientRect()
setOriginalPosition({
left:
buttonRect.left +
buttonRect.width / 2 -
(e.clientX + elementRect.width / 2),
top:
buttonRect.top +
buttonRect.height / 2 -
(e.clientY + elementRect.height / 2),
})
setCenterPosition({
left: buttonRect.width / 2 - elementRect.width / 2,
top: buttonRect.height / 2 - elementRect.height / 2,
})
} else {
setIsHovering(false)
}
}
window.addEventListener("mousemove", handleMouseMove)
return () => {
window.removeEventListener("mousemove", handleMouseMove)
}
}, [])
return (
<animated.div
ref={ref}
style={{
position: "absolute",
pointerEvents: "none",
left: springProps.left,
top: springProps.top,
transform: "translate3d(0, 0, 0)",
transformStyle: "preserve-3d",
}}
>
<Component {...props} />
</animated.div>
)
}
}
// © Framer University. All rights reserved.
import type { ComponentType } from "react"
import { useRef, useState } from "react"
import { useEffect } from "react"
import { useSpring, animated } from "react-spring"
export function withCursorFollow(Component): ComponentType {
return (props) => {
const ref = useRef(null)
const [isHovering, setIsHovering] = useState(false)
const [originalPosition, setOriginalPosition] = useState({
left: 0,
top: 0,
})
const [centerPosition, setCenterPosition] = useState({
left: 0,
top: 0,
})
const springProps = useSpring({
left: isHovering ? originalPosition.left : centerPosition.left,
top: isHovering ? originalPosition.top : centerPosition.top,
config: { mass: 1, tension: 170, friction: 26 },
})
useEffect(() => {
if (!ref.current) return
const buttonRect = ref.current.getBoundingClientRect()
const elementRect = ref.current.getBoundingClientRect()
setCenterPosition({
left: buttonRect.width / 2 - elementRect.width / 2,
top: buttonRect.height / 2 - elementRect.height / 2,
})
const handleMouseMove = (e) => {
if (!ref.current) return
if (e.target.closest("button")) {
setIsHovering(true)
const buttonRect = e.target.getBoundingClientRect()
const elementRect = ref.current.getBoundingClientRect()
setOriginalPosition({
left:
buttonRect.left +
buttonRect.width / 2 -
(e.clientX + elementRect.width / 2),
top:
buttonRect.top +
buttonRect.height / 2 -
(e.clientY + elementRect.height / 2),
})
setCenterPosition({
left: buttonRect.width / 2 - elementRect.width / 2,
top: buttonRect.height / 2 - elementRect.height / 2,
})
} else {
setIsHovering(false)
}
}
window.addEventListener("mousemove", handleMouseMove)
return () => {
window.removeEventListener("mousemove", handleMouseMove)
}
}, [])
return (
<animated.div
ref={ref}
style={{
position: "absolute",
pointerEvents: "none",
left: springProps.left,
top: springProps.top,
transform: "translate3d(0, 0, 0)",
transformStyle: "preserve-3d",
}}
>
<Component {...props} />
</animated.div>
)
}
}



Free Framer Course
Learn how to create stunning websites with ease by learning the fundamentals of Framer.



Free
Framer Course
Learn how to create stunning websites with ease by learning the fundamentals of Framer.



Free Framer Course
Learn how to create stunning websites with ease by learning the fundamentals of Framer.