Button

Buttons are used to trigger actions.

tsx
'use client'

import { Button } from '@nerdfish/ui'

export function ButtonExample() {
	return <Button>Button</Button>
}

Usage

tsx
import { Button } from '@nerdfish/ui'
tsx
<Button variant="outline">Button</Button>

Examples

Default

tsx
'use client'

import { Button } from '@nerdfish/ui'

export function ButtonExample() {
	return <Button>Button</Button>
}

Variants

tsx
'use client'

import { Button } from '@nerdfish/ui'

export function ButtonVariantsExample() {
	return (
		<div className="space-x-sm flex">
			<Button variant="default">Default</Button>
			<Button variant="brand">Nerdfish</Button>
			<Button variant="secondary">Secondary</Button>
			<Button variant="danger" onClick={() => {}}>
				Danger
			</Button>
			<Button variant="success">Success</Button>
			<Button variant="ghost">Ghost</Button>
			<Button variant="outline">Outline</Button>
			<Button variant="accentuate">Accentuate</Button>
			<Button variant="link">Link</Button>
		</div>
	)
}

Disabled

tsx
'use client'

import { Button } from '@nerdfish/ui'

export function ButtonDisabledExample() {
	return (
		<div className="space-x-sm flex">
			<Button disabled variant="default">
				Default
			</Button>
			<Button disabled variant="brand">
				Nerdfish
			</Button>
			<Button disabled variant="secondary">
				Secondary
			</Button>
			<Button disabled variant="danger">
				Danger
			</Button>
			<Button disabled variant="success">
				Success
			</Button>
			<Button disabled variant="ghost">
				Ghost
			</Button>
			<Button disabled variant="outline">
				Outline
			</Button>
			<Button disabled variant="link">
				Link
			</Button>
		</div>
	)
}

Sizes

tsx
'use client'

import { Button, ButtonGroup } from '@nerdfish/ui'
import { Mail } from 'lucide-react'

export function ButtonSizesExample() {
	return (
		<div className="gap-sm flex flex-col">
			<div className="space-x-sm flex items-center">
				<Button variant="brand" size="sm">
					Small
				</Button>
				<Button variant="brand" size="default">
					Default
				</Button>
				<Button variant="brand" size="lg">
					Large
				</Button>
				<Button variant="brand" size="xl">
					Extra Large
				</Button>
				<Button variant="brand" icon>
					<Mail />
					<span className="sr-only">Mail</span>
				</Button>
			</div>
			<div className="space-x-sm flex items-center">
				<ButtonGroup>
					<Button size="sm">Small</Button>
					<Button size="sm" icon>
						<Mail />
					</Button>
				</ButtonGroup>
				<ButtonGroup>
					<Button>Default</Button>
					<Button icon>
						<Mail />
					</Button>
				</ButtonGroup>
				<ButtonGroup>
					<Button size="lg">Large</Button>
					<Button size="lg" icon>
						<Mail />
					</Button>
				</ButtonGroup>
				<ButtonGroup>
					<Button size="xl">Extra Large</Button>
					<Button size="xl" icon>
						<Mail />
					</Button>
				</ButtonGroup>
			</div>
			<div className="space-x-sm flex items-center">
				<Button variant="brand" size="sm" icon>
					<Mail />
				</Button>
				<Button variant="brand" size="default" icon>
					<Mail />
				</Button>
				<Button variant="brand" size="lg" icon>
					<Mail />
				</Button>
				<Button variant="brand" size="xl" icon>
					<Mail />
				</Button>
			</div>
		</div>
	)
}

With Icon

tsx
'use client'

import { Button } from '@nerdfish/ui'
import { Mail } from 'lucide-react'

export function ButtonWithIconExample() {
	return (
		<Button>
			<Mail className="mr-sm size-4" /> Login with Email
		</Button>
	)
}

Loading

tsx
'use client'

import { Button } from '@nerdfish/ui'
import { Loader2 } from 'lucide-react'

export function ButtonLoadingExample() {
	return (
		<Button disabled>
			<Loader2 className="mr-sm size-4 animate-spin" />
			Please wait
		</Button>
	)
}

Icon only

tsx
'use client'

import { Button } from '@nerdfish/ui'
import { Mail } from 'lucide-react'

export function ButtonIconOnlyExample() {
	return (
		<Button icon>
			<Mail className="size-4" />
			<span className="sr-only">Mail</span>
		</Button>
	)
}

As Child

tsx
'use client'

import { Button } from '@nerdfish/ui'
import Link from 'next/link'

export function ButtonAsChildExample() {
	return (
		<Button asChild>
			<Link href="https://nerdfish.be">Nerdfish</Link>
		</Button>
	)
}

Button Group

Horizontal

Vertical

tsx
'use client'

import { Button, ButtonGroup, H3 } from '@nerdfish/ui'

export function ButtonGroupExample() {
	return (
		<div className="gap2 flex flex-col">
			<H3>Horizontal</H3>
			<ButtonGroup>
				<Button>Button 1</Button>
				<Button>Button 2</Button>
				<Button>Button 3</Button>
			</ButtonGroup>
			<H3>Vertical</H3>
			<ButtonGroup orientation="vertical">
				<Button>Button 1</Button>
				<Button>Button 2</Button>
				<Button>Button 3</Button>
			</ButtonGroup>
		</div>
	)
}

Button Group Use Case

tsx
'use client'

import {
	Button,
	ButtonGroup,
	Description,
	DropdownMenu,
	DropdownMenuContent,
	DropdownMenuItem,
	DropdownMenuTrigger,
} from '@nerdfish/ui'
import { ChevronDownIcon } from 'lucide-react'
import React from 'react'

const descriptionsMap = {
	merge:
		'All commits from the source branch are added to the destination branch via a merge commit.',
	squash:
		'All commits from the source branch are added to the destination branch as a single commit.',
	rebase:
		'All commits from the source branch are added to the destination branch individually.',
}

const labelsMap = {
	merge: 'Create a merge commit',
	squash: 'Squash and merge',
	rebase: 'Rebase and merge',
}

export function ButtonGroupUseCase() {
	const [selectedOption, setSelectedOption] =
		React.useState<keyof typeof labelsMap>('merge')

	return (
		<ButtonGroup>
			<Button variant="success">{labelsMap[selectedOption]}</Button>

			<DropdownMenu>
				<DropdownMenuTrigger asChild>
					<Button variant="success" icon>
						<ChevronDownIcon className="size-4" />
					</Button>
				</DropdownMenuTrigger>
				<DropdownMenuContent className="max-w-[300px]">
					{Object.entries(labelsMap).map(([key, label]) => {
						const option = key as keyof typeof labelsMap
						return (
							<DropdownMenuItem
								onSelect={() => setSelectedOption(option)}
								key={key}
							>
								<div className="gap-sm flex flex-col">
									<span className="font-bold">{label}</span>
									<Description>{descriptionsMap[option]}</Description>
								</div>
							</DropdownMenuItem>
						)
					})}
				</DropdownMenuContent>
			</DropdownMenu>
		</ButtonGroup>
	)
}