diff --git a/apps/web/client/src/stories/Alert.stories.tsx b/apps/web/client/src/stories/Alert.stories.tsx
new file mode 100644
index 0000000000..53f4c04347
--- /dev/null
+++ b/apps/web/client/src/stories/Alert.stories.tsx
@@ -0,0 +1,113 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { Alert, AlertDescription, AlertTitle } from '@onlook/ui/alert';
+import { AlertCircle, CheckCircle2, Info, AlertTriangle } from 'lucide-react';
+
+const meta = {
+ component: Alert,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ argTypes: {
+ variant: {
+ description: 'Visual style variant of the alert',
+ control: { type: 'select' },
+ options: ['default', 'destructive'],
+ },
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => (
+
+
+ Information
+
+ This is an informational alert message.
+
+
+ ),
+};
+
+export const Destructive: Story = {
+ render: () => (
+
+
+ Error
+
+ Something went wrong. Please try again later.
+
+
+ ),
+};
+
+export const Success: Story = {
+ render: () => (
+
+
+ Success
+
+ Your changes have been saved successfully.
+
+
+ ),
+};
+
+export const Warning: Story = {
+ render: () => (
+
+
+ Warning
+
+ This action may have unintended consequences.
+
+
+ ),
+};
+
+export const TitleOnly: Story = {
+ render: () => (
+
+
+ Alert with title only
+
+ ),
+};
+
+export const DescriptionOnly: Story = {
+ render: () => (
+
+
+
+ Alert with description only, no title.
+
+
+ ),
+};
+
+export const AllVariants: Story = {
+ render: () => (
+
+
+
+ Default Alert
+ This is the default alert style.
+
+
+
+ Destructive Alert
+ This is the destructive alert style.
+
+
+ ),
+};
diff --git a/apps/web/client/src/stories/Avatar.stories.tsx b/apps/web/client/src/stories/Avatar.stories.tsx
new file mode 100644
index 0000000000..adff485840
--- /dev/null
+++ b/apps/web/client/src/stories/Avatar.stories.tsx
@@ -0,0 +1,93 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { Avatar, AvatarFallback, AvatarImage } from '@onlook/ui/avatar';
+
+const meta = {
+ component: Avatar,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => (
+
+
+ JD
+
+ ),
+};
+
+export const WithFallback: Story = {
+ render: () => (
+
+
+ AB
+
+ ),
+};
+
+export const FallbackOnly: Story = {
+ render: () => (
+
+ CD
+
+ ),
+};
+
+export const Sizes: Story = {
+ render: () => (
+
+
+
+ SM
+
+
+
+ DF
+
+
+
+ LG
+
+
+
+ XL
+
+
+ ),
+};
+
+export const Group: Story = {
+ render: () => (
+
+
+
+ U1
+
+
+
+ U2
+
+
+
+ U3
+
+
+ +5
+
+
+ ),
+};
+
+export const WithRealImage: Story = {
+ render: () => (
+
+
+ JD
+
+ ),
+};
diff --git a/apps/web/client/src/stories/Badge.stories.tsx b/apps/web/client/src/stories/Badge.stories.tsx
new file mode 100644
index 0000000000..0b51229d20
--- /dev/null
+++ b/apps/web/client/src/stories/Badge.stories.tsx
@@ -0,0 +1,78 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { Badge } from '@onlook/ui/badge';
+
+const meta = {
+ component: Badge,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+ argTypes: {
+ variant: {
+ description: 'Visual style variant of the badge',
+ control: { type: 'select' },
+ options: ['default', 'secondary', 'destructive', 'outline'],
+ },
+ asChild: {
+ description: 'Whether to render as a child component',
+ control: 'boolean',
+ },
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ children: 'Badge',
+ variant: 'default',
+ },
+};
+
+export const Secondary: Story = {
+ args: {
+ children: 'Secondary',
+ variant: 'secondary',
+ },
+};
+
+export const Destructive: Story = {
+ args: {
+ children: 'Destructive',
+ variant: 'destructive',
+ },
+};
+
+export const Outline: Story = {
+ args: {
+ children: 'Outline',
+ variant: 'outline',
+ },
+};
+
+export const AllVariants: Story = {
+ render: () => (
+
+ Default
+ Secondary
+ Destructive
+ Outline
+
+ ),
+};
+
+export const WithIcon: Story = {
+ render: () => (
+
+
+ *
+ New
+
+
+ !
+ Warning
+
+
+ ),
+};
diff --git a/apps/web/client/src/stories/Card.stories.tsx b/apps/web/client/src/stories/Card.stories.tsx
new file mode 100644
index 0000000000..5c7b478a1b
--- /dev/null
+++ b/apps/web/client/src/stories/Card.stories.tsx
@@ -0,0 +1,104 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { Button } from '@onlook/ui/button';
+import {
+ Card,
+ CardAction,
+ CardContent,
+ CardDescription,
+ CardFooter,
+ CardHeader,
+ CardTitle,
+} from '@onlook/ui/card';
+
+const meta = {
+ component: Card,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => (
+
+
+ Card Title
+ Card description goes here
+
+
+ Card content with some text explaining the purpose of this card.
+
+
+
+
+
+ ),
+};
+
+export const WithAction: Story = {
+ render: () => (
+
+
+ Card with Action
+ This card has an action button in the header
+
+
+
+
+
+ The action button appears in the top right corner of the header.
+
+
+ ),
+};
+
+export const Simple: Story = {
+ render: () => (
+
+
+ Simple Card
+
+
+ A simple card with just a title and content.
+
+
+ ),
+};
+
+export const WithFooterActions: Story = {
+ render: () => (
+
+
+ Confirm Action
+ Are you sure you want to proceed?
+
+
+ This action cannot be undone. Please review before confirming.
+
+
+
+
+
+
+ ),
+};
+
+export const ContentOnly: Story = {
+ render: () => (
+
+
+ A card with only content, no header or footer.
+
+
+ ),
+};
diff --git a/apps/web/client/src/stories/Checkbox.stories.tsx b/apps/web/client/src/stories/Checkbox.stories.tsx
new file mode 100644
index 0000000000..d8cc39cea2
--- /dev/null
+++ b/apps/web/client/src/stories/Checkbox.stories.tsx
@@ -0,0 +1,95 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { fn } from '@storybook/test';
+import { Checkbox } from '@onlook/ui/checkbox';
+import { Label } from '@onlook/ui/label';
+
+const meta = {
+ component: Checkbox,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+ argTypes: {
+ checked: {
+ description: 'Whether the checkbox is checked',
+ control: 'boolean',
+ },
+ disabled: {
+ description: 'Whether the checkbox is disabled',
+ control: 'boolean',
+ },
+ },
+ args: {
+ onCheckedChange: fn(),
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ checked: false,
+ },
+};
+
+export const Checked: Story = {
+ args: {
+ checked: true,
+ },
+};
+
+export const Disabled: Story = {
+ args: {
+ disabled: true,
+ },
+};
+
+export const DisabledChecked: Story = {
+ args: {
+ checked: true,
+ disabled: true,
+ },
+};
+
+export const WithLabel: Story = {
+ render: () => (
+
+
+
+
+ ),
+};
+
+export const WithDescription: Story = {
+ render: () => (
+
+
+
+
+
+ Get notified about new features and updates.
+
+
+
+ ),
+};
+
+export const CheckboxGroup: Story = {
+ render: () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ),
+};
diff --git a/apps/web/client/src/stories/HighlightText.stories.tsx b/apps/web/client/src/stories/HighlightText.stories.tsx
new file mode 100644
index 0000000000..956d4b7a25
--- /dev/null
+++ b/apps/web/client/src/stories/HighlightText.stories.tsx
@@ -0,0 +1,86 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { HighlightText } from '@/app/projects/_components/select/highlight-text';
+
+const meta = {
+ component: HighlightText,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+ argTypes: {
+ text: {
+ description: 'The text to display',
+ control: 'text',
+ },
+ searchQuery: {
+ description: 'The search query to highlight within the text',
+ control: 'text',
+ },
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ text: 'E-commerce Dashboard',
+ searchQuery: 'dash',
+ },
+};
+
+export const NoMatch: Story = {
+ args: {
+ text: 'E-commerce Dashboard',
+ searchQuery: 'xyz',
+ },
+};
+
+export const EmptyQuery: Story = {
+ args: {
+ text: 'E-commerce Dashboard',
+ searchQuery: '',
+ },
+};
+
+export const FullMatch: Story = {
+ args: {
+ text: 'Dashboard',
+ searchQuery: 'Dashboard',
+ },
+};
+
+export const CaseInsensitive: Story = {
+ args: {
+ text: 'E-commerce Dashboard',
+ searchQuery: 'DASH',
+ },
+};
+
+export const MultipleMatches: Story = {
+ args: {
+ text: 'Dashboard for dashboard analytics',
+ searchQuery: 'dashboard',
+ },
+};
+
+export const PartialWord: Story = {
+ args: {
+ text: 'Portfolio Website Project',
+ searchQuery: 'port',
+ },
+};
+
+export const SpecialCharacters: Story = {
+ args: {
+ text: 'Project (v2.0) - Beta',
+ searchQuery: '(v2',
+ },
+};
+
+export const LongText: Story = {
+ args: {
+ text: 'This is a very long project name that contains the word dashboard somewhere in the middle of the text',
+ searchQuery: 'dashboard',
+ },
+};
diff --git a/apps/web/client/src/stories/Input.stories.tsx b/apps/web/client/src/stories/Input.stories.tsx
new file mode 100644
index 0000000000..b85fa3c6d8
--- /dev/null
+++ b/apps/web/client/src/stories/Input.stories.tsx
@@ -0,0 +1,109 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { Input } from '@onlook/ui/input';
+import { Label } from '@onlook/ui/label';
+
+const meta = {
+ component: Input,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ argTypes: {
+ type: {
+ description: 'The type of input',
+ control: { type: 'select' },
+ options: ['text', 'email', 'password', 'number', 'search', 'tel', 'url'],
+ },
+ placeholder: {
+ description: 'Placeholder text',
+ control: 'text',
+ },
+ disabled: {
+ description: 'Whether the input is disabled',
+ control: 'boolean',
+ },
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ type: 'text',
+ placeholder: 'Enter text...',
+ },
+};
+
+export const WithLabel: Story = {
+ render: () => (
+
+
+
+
+ ),
+};
+
+export const Password: Story = {
+ args: {
+ type: 'password',
+ placeholder: 'Enter password',
+ },
+};
+
+export const Disabled: Story = {
+ args: {
+ type: 'text',
+ placeholder: 'Disabled input',
+ disabled: true,
+ },
+};
+
+export const WithValue: Story = {
+ args: {
+ type: 'text',
+ defaultValue: 'Pre-filled value',
+ },
+};
+
+export const Search: Story = {
+ args: {
+ type: 'search',
+ placeholder: 'Search...',
+ },
+};
+
+export const Number: Story = {
+ args: {
+ type: 'number',
+ placeholder: '0',
+ },
+};
+
+export const File: Story = {
+ args: {
+ type: 'file',
+ },
+};
+
+export const Invalid: Story = {
+ render: () => (
+
+
+
+
+ ),
+};
diff --git a/apps/web/client/src/stories/Progress.stories.tsx b/apps/web/client/src/stories/Progress.stories.tsx
new file mode 100644
index 0000000000..6deed46b69
--- /dev/null
+++ b/apps/web/client/src/stories/Progress.stories.tsx
@@ -0,0 +1,89 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { Progress } from '@onlook/ui/progress';
+
+const meta = {
+ component: Progress,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ argTypes: {
+ value: {
+ description: 'Progress value (0-100)',
+ control: { type: 'range', min: 0, max: 100, step: 1 },
+ },
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ value: 50,
+ },
+};
+
+export const Empty: Story = {
+ args: {
+ value: 0,
+ },
+};
+
+export const Quarter: Story = {
+ args: {
+ value: 25,
+ },
+};
+
+export const Half: Story = {
+ args: {
+ value: 50,
+ },
+};
+
+export const ThreeQuarters: Story = {
+ args: {
+ value: 75,
+ },
+};
+
+export const Complete: Story = {
+ args: {
+ value: 100,
+ },
+};
+
+export const AllStates: Story = {
+ render: () => (
+
+ ),
+};
diff --git a/apps/web/client/src/stories/Skeleton.stories.tsx b/apps/web/client/src/stories/Skeleton.stories.tsx
new file mode 100644
index 0000000000..f80a3526e4
--- /dev/null
+++ b/apps/web/client/src/stories/Skeleton.stories.tsx
@@ -0,0 +1,102 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { Skeleton } from '@onlook/ui/skeleton';
+
+const meta = {
+ component: Skeleton,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => ,
+};
+
+export const Circle: Story = {
+ render: () => ,
+};
+
+export const Card: Story = {
+ render: () => (
+
+ ),
+};
+
+export const Avatar: Story = {
+ render: () => (
+
+ ),
+};
+
+export const List: Story = {
+ render: () => (
+
+ {[1, 2, 3].map((i) => (
+
+ ))}
+
+ ),
+};
+
+export const Form: Story = {
+ render: () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ),
+};
+
+export const Table: Story = {
+ render: () => (
+
+
+
+
+
+
+
+ {[1, 2, 3, 4].map((i) => (
+
+
+
+
+
+
+ ))}
+
+ ),
+};
diff --git a/apps/web/client/src/stories/Switch.stories.tsx b/apps/web/client/src/stories/Switch.stories.tsx
new file mode 100644
index 0000000000..b5930a8bf7
--- /dev/null
+++ b/apps/web/client/src/stories/Switch.stories.tsx
@@ -0,0 +1,95 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { fn } from '@storybook/test';
+import { Switch } from '@onlook/ui/switch';
+import { Label } from '@onlook/ui/label';
+
+const meta = {
+ component: Switch,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+ argTypes: {
+ checked: {
+ description: 'Whether the switch is checked',
+ control: 'boolean',
+ },
+ disabled: {
+ description: 'Whether the switch is disabled',
+ control: 'boolean',
+ },
+ },
+ args: {
+ onCheckedChange: fn(),
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ checked: false,
+ },
+};
+
+export const Checked: Story = {
+ args: {
+ checked: true,
+ },
+};
+
+export const Disabled: Story = {
+ args: {
+ disabled: true,
+ },
+};
+
+export const DisabledChecked: Story = {
+ args: {
+ checked: true,
+ disabled: true,
+ },
+};
+
+export const WithLabel: Story = {
+ render: () => (
+
+
+
+
+ ),
+};
+
+export const WithDescription: Story = {
+ render: () => (
+
+
+
+
+
+ Receive push notifications for important updates.
+
+
+
+ ),
+};
+
+export const SwitchGroup: Story = {
+ render: () => (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ),
+};
diff --git a/apps/web/client/src/stories/TemplateCard.stories.tsx b/apps/web/client/src/stories/TemplateCard.stories.tsx
new file mode 100644
index 0000000000..5a12a10692
--- /dev/null
+++ b/apps/web/client/src/stories/TemplateCard.stories.tsx
@@ -0,0 +1,160 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { fn } from '@storybook/test';
+import { TemplateCard } from '@/app/projects/_components/templates/template-card';
+
+const meta = {
+ component: TemplateCard,
+ parameters: {
+ layout: 'centered',
+ backgrounds: {
+ default: 'dark',
+ },
+ },
+ tags: ['autodocs'],
+ argTypes: {
+ title: {
+ description: 'Title of the template',
+ control: 'text',
+ },
+ description: {
+ description: 'Description of the template',
+ control: 'text',
+ },
+ image: {
+ description: 'Preview image URL',
+ control: 'text',
+ },
+ isNew: {
+ description: 'Whether to show the "New" badge',
+ control: 'boolean',
+ },
+ isStarred: {
+ description: 'Whether the template is starred/favorited',
+ control: 'boolean',
+ },
+ },
+ args: {
+ onClick: fn(),
+ onToggleStar: fn(),
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ title: 'Next.js Starter',
+ description: 'A full-featured Next.js template with authentication and database integration.',
+ image: 'https://images.unsplash.com/photo-1633356122544-f134324a6cee?w=800&q=80',
+ isNew: false,
+ isStarred: false,
+ },
+};
+
+export const WithNewBadge: Story = {
+ args: {
+ title: 'React Dashboard',
+ description: 'Modern dashboard template with charts, tables, and analytics components.',
+ image: 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=800&q=80',
+ isNew: true,
+ isStarred: false,
+ },
+};
+
+export const Starred: Story = {
+ args: {
+ title: 'Portfolio Template',
+ description: 'Clean and minimal portfolio template for showcasing your work.',
+ image: 'https://images.unsplash.com/photo-1507238691740-187a5b1d37b8?w=800&q=80',
+ isNew: false,
+ isStarred: true,
+ },
+};
+
+export const NewAndStarred: Story = {
+ args: {
+ title: 'E-commerce Starter',
+ description: 'Complete e-commerce solution with cart, checkout, and payment integration.',
+ image: 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800&q=80',
+ isNew: true,
+ isStarred: true,
+ },
+};
+
+export const NoImage: Story = {
+ args: {
+ title: 'Blank Template',
+ description: 'Start from scratch with a minimal setup.',
+ image: undefined,
+ isNew: false,
+ isStarred: false,
+ },
+};
+
+export const LongTitle: Story = {
+ args: {
+ title: 'Super Long Template Name That Should Truncate Properly',
+ description: 'A template with a very long name to test truncation behavior.',
+ image: 'https://images.unsplash.com/photo-1547658719-da2b51169166?w=800&q=80',
+ isNew: false,
+ isStarred: false,
+ },
+};
+
+export const LongDescription: Story = {
+ args: {
+ title: 'Documentation Site',
+ description: 'A comprehensive documentation template with search functionality, versioning support, multiple language support, and beautiful syntax highlighting for code blocks.',
+ image: 'https://images.unsplash.com/photo-1504868584819-f8e8b4b6d7e3?w=800&q=80',
+ isNew: false,
+ isStarred: false,
+ },
+};
+
+export const WithoutStarButton: Story = {
+ args: {
+ title: 'Simple Template',
+ description: 'A template without the star/favorite functionality.',
+ image: 'https://images.unsplash.com/photo-1512941937669-90a1b58e7e9c?w=800&q=80',
+ isNew: false,
+ isStarred: false,
+ onToggleStar: undefined,
+ },
+};
+
+export const AllVariants: Story = {
+ render: () => (
+
+
+
+
+
+
+ ),
+};
diff --git a/apps/web/client/src/stories/Textarea.stories.tsx b/apps/web/client/src/stories/Textarea.stories.tsx
new file mode 100644
index 0000000000..0c696afc1a
--- /dev/null
+++ b/apps/web/client/src/stories/Textarea.stories.tsx
@@ -0,0 +1,84 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { Textarea } from '@onlook/ui/textarea';
+import { Label } from '@onlook/ui/label';
+
+const meta = {
+ component: Textarea,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ argTypes: {
+ placeholder: {
+ description: 'Placeholder text',
+ control: 'text',
+ },
+ disabled: {
+ description: 'Whether the textarea is disabled',
+ control: 'boolean',
+ },
+ rows: {
+ description: 'Number of visible text lines',
+ control: 'number',
+ },
+ },
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ args: {
+ placeholder: 'Enter your message...',
+ },
+};
+
+export const WithLabel: Story = {
+ render: () => (
+
+
+
+
+ ),
+};
+
+export const Disabled: Story = {
+ args: {
+ placeholder: 'Disabled textarea',
+ disabled: true,
+ },
+};
+
+export const WithValue: Story = {
+ args: {
+ defaultValue: 'This is some pre-filled content in the textarea that spans multiple lines to demonstrate how the component handles longer text.',
+ },
+};
+
+export const WithRows: Story = {
+ args: {
+ placeholder: 'Textarea with 6 rows',
+ rows: 6,
+ },
+};
+
+export const Invalid: Story = {
+ render: () => (
+
+
+
+
+ ),
+};
diff --git a/apps/web/client/src/stories/Tooltip.stories.tsx b/apps/web/client/src/stories/Tooltip.stories.tsx
new file mode 100644
index 0000000000..fa350c8bf5
--- /dev/null
+++ b/apps/web/client/src/stories/Tooltip.stories.tsx
@@ -0,0 +1,118 @@
+import type { Meta, StoryObj } from '@storybook/nextjs-vite';
+import { Button } from '@onlook/ui/button';
+import { Tooltip, TooltipContent, TooltipTrigger } from '@onlook/ui/tooltip';
+
+const meta = {
+ component: Tooltip,
+ parameters: {
+ layout: 'centered',
+ },
+ tags: ['autodocs'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {
+ render: () => (
+
+
+
+
+
+ This is a tooltip
+
+
+ ),
+};
+
+export const WithArrow: Story = {
+ render: () => (
+
+
+
+
+
+ Tooltip with arrow
+
+
+ ),
+};
+
+export const WithoutArrow: Story = {
+ render: () => (
+
+
+
+
+
+ Tooltip without arrow
+
+
+ ),
+};
+
+export const Positions: Story = {
+ render: () => (
+
+
+
+
+
+
+ Top tooltip
+
+
+
+
+
+
+
+ Bottom tooltip
+
+
+
+
+
+
+
+ Left tooltip
+
+
+
+
+
+
+
+ Right tooltip
+
+
+
+ ),
+};
+
+export const WithDelay: Story = {
+ render: () => (
+
+
+
+
+
+ This tooltip has a 500ms delay
+
+
+ ),
+};
+
+export const LongContent: Story = {
+ render: () => (
+
+
+
+
+
+ This is a longer tooltip message that wraps to multiple lines when it exceeds the maximum width.
+
+
+ ),
+};