Overview
Noteverse includes specialized button components that extend the base Button component with additional visual effects and loading states.
An eye-catching button with animated rainbow gradient border and glow effect.
Import
import { RainbowButton } from '@/components/ui/rainbow-button'
Props
...props
React.ButtonHTMLAttributes<HTMLButtonElement>
All standard HTML button attributes (onClick, disabled, type, etc.)
Basic Usage
import { RainbowButton } from '@/components/ui/rainbow-button'
export default function Example() {
return (
<RainbowButton onClick={() => console.log('Clicked!')}>
Click Me
</RainbowButton>
)
}
Visual Design
The RainbowButton features several layers of visual effects:
Gradient Border
Glow Effect
Theme Support
Animated rainbow gradient border using CSS variables:background: linear-gradient(
90deg,
hsl(var(--color-1)),
hsl(var(--color-5)),
hsl(var(--color-3)),
hsl(var(--color-4)),
hsl(var(--color-2))
)
background-size: 200%
animation: rainbow
Blurred gradient underneath the button:before:absolute
before:bottom-[-20%]
before:left-1/2
before:h-1/5
before:w-3/5
before:animate-rainbow
before:[filter:blur(calc(0.8*1rem))]
Different gradients for light and dark modes:Light Mode:bg-[linear-gradient(#121213,#121213),
linear-gradient(#121213_50%,rgba(18,18,19,0.6)_80%,rgba(18,18,19,0)),
linear-gradient(90deg,hsl(var(--color-1)),...)]]
Dark Mode:dark:bg-[linear-gradient(#fff,#fff),
linear-gradient(#fff_50%,rgba(255,255,255,0.6)_80%,rgba(0,0,0,0)),
linear-gradient(90deg,hsl(var(--color-1)),...)]]
CSS Variables
Define these color variables in your CSS:
:root {
--color-1: 0 100% 63%;
--color-2: 270 100% 63%;
--color-3: 210 100% 63%;
--color-4: 195 100% 63%;
--color-5: 90 100% 63%;
}
@keyframes rainbow {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
}
.animate-rainbow {
animation: rainbow 8s linear infinite;
}
Styling
The button uses Tailwind classes with the cn utility:
className={cn(
'h-11 px-8 py-2',
'inline-flex items-center justify-center',
'rounded-xl font-medium',
'transition-colors',
'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring',
'disabled:pointer-events-none disabled:opacity-50',
'relative group animate-rainbow cursor-pointer',
'border-0 bg-[length:200%]',
'text-primary-foreground',
'[background-clip:padding-box,border-box,border-box]',
'[background-origin:border-box]',
'[border:calc(0.08*1rem)_solid_transparent]',
// ... gradient backgrounds
)}
TypeScript Interface
interface RainbowButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement> {}
A button that displays a loading spinner and custom text during async operations.
Import
import LoadingButton from '@/components/ui/loading-button'
Props
Whether to show loading state
Button content when not loading
All props from the base Button component (variant, size, etc.)
Basic Usage
import LoadingButton from '@/components/ui/loading-button'
import { useState } from 'react'
export default function Form() {
const [isLoading, setIsLoading] = useState(false)
const handleSubmit = async () => {
setIsLoading(true)
try {
await submitForm()
} finally {
setIsLoading(false)
}
}
return (
<LoadingButton
loading={isLoading}
onClick={handleSubmit}
>
Submit
</LoadingButton>
)
}
Loading State
When loading={true}, the button displays:
<Loader2 className="mr-2 h-4 w-4 animate-spin" /> Creating...
The loading text “Creating…” is hardcoded. To customize it:
Custom Loading Text
Usage with Custom Text
Modify the component to accept a loadingText prop:type LoadingButtonProps = {
loading: boolean
loadingText?: string
} & ButtonProps
export default function LoadingButton({
children,
loading,
loadingText = 'Loading...',
...props
}: LoadingButtonProps) {
return (
<Button {...props} disabled={props.disabled || loading}>
{loading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
{loadingText}
</>
) : (
children
)}
</Button>
)
}
<LoadingButton
loading={isLoading}
loadingText="Saving..."
>
Save
</LoadingButton>
<LoadingButton
loading={isDeleting}
loadingText="Deleting..."
>
Delete
</LoadingButton>
Disabled State
The button is automatically disabled during loading:
<Button {...props} disabled={props.disabled || loading}>
This prevents multiple submissions and provides clear feedback.
TypeScript Interface
import { ButtonProps } from './button'
type LoadingButtonProps = {
loading: boolean
} & ButtonProps
Customization
Replace the Loader2 icon:import { Spinner } from 'lucide-react'
{loading ? (
<>
<Spinner className="mr-2 h-4 w-4 animate-spin" />
Creating...
</>
) : (
children
)}
Show only the spinner without text:{loading ? (
<Loader2 className="h-4 w-4 animate-spin" />
) : (
children
)}
Adjust spinner size based on button size:const spinnerSize = props.size === 'sm' ? 'h-3 w-3' : 'h-4 w-4'
<Loader2 className={`mr-2 animate-spin ${spinnerSize}`} />
Both specialized buttons extend the base Button component from shadcn/ui:
import { Button } from '@/components/ui/button'
<Button variant="default" size="default">
Click me
</Button>
default: Primary button style
destructive: For dangerous actions
outline: Outlined button
secondary: Secondary button style
ghost: Transparent button
link: Link-styled button
default: Standard size
sm: Small
lg: Large
icon: Square button for icons
Best Practices
Use RainbowButton sparingly
Always use LoadingButton for async actions
Provide meaningful loading text
Make it clear what’s happening:// Good
<LoadingButton loading={isSaving} loadingText="Saving changes...">
Save
</LoadingButton>
// Not helpful
<LoadingButton loading={isSaving} loadingText="Loading...">
Save
</LoadingButton>
Accessibility
Both components support standard button accessibility features:
// Disabled state
<LoadingButton loading={false} disabled>
Disabled
</LoadingButton>
// ARIA label
<RainbowButton aria-label="Get started with Noteverse">
Get Started
</RainbowButton>
// Keyboard navigation
<LoadingButton
loading={false}
onKeyDown={(e) => {
if (e.key === 'Enter') {
handleSubmit()
}
}}
>
Submit
</LoadingButton>
Next Steps
Forms
Learn about form input components
Dialogs
Explore modal and drawer components