npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@redrobui/vue

v0.4.0

Published

Vue 3 components for Redrob AI Design System

Readme

@redrobui/vue

Vue 3 components for the Redrob AI Design System, built with Vite and Tailwind CSS.

🎨 Live Demo

View Interactive Component Demo →

Explore all Vue components, variants, and design tokens in our interactive Storybook.

🚨 Important: Complete Setup Required

Your styles won't work without proper setup! Follow ALL steps below.

Installation

npm install @redrobui/vue @redrobui/tailwind-config
# or
yarn add @redrobui/vue @redrobui/tailwind-config
# or
pnpm add @redrobui/vue @redrobui/tailwind-config

Setup

Quick Setup (Recommended)

The easiest way - just import the pre-built utilities:

Step 1: Import CSS

/* src/style.css or src/main.css */
@import '@redrobui/tokens/utilities.css';
@import '@redrobui/vue/styles.css';

Step 2: Import in Your App

// src/main.ts
import { createApp } from 'vue';
import './style.css';
import App from './App.vue';

createApp(App).mount('#app');

That's it! All color classes work immediately:

  • bg-primary-600, text-white, hover:bg-primary-700
  • bg-secondary-600, bg-error-600, bg-success-600
  • No Tailwind config needed!

Advanced Setup (Custom Tailwind Config)

If you want to customize the design system:

Step 1: Configure Tailwind CSS

// tailwind.config.js
const redrobConfig = require('@redrobui/tailwind-config');

module.exports = {
  presets: [redrobConfig],
  content: [
    './src/**/*.{vue,js,ts,jsx,tsx}',
    './index.html',
    // Include the component library files
    './node_modules/@redrobui/vue/**/*.{vue,js,ts,jsx,tsx,mjs}',
  ],
};

Step 2: Import Styles

/* src/style.css or src/main.css */
@import '@redrobui/vue/styles.css';
@import 'tailwindcss';

Step 3: Import CSS in Your App

// src/main.ts
import { createApp } from 'vue';
import './style.css';
import App from './App.vue';

createApp(App).mount('#app');

Basic Usage

<script setup lang="ts">
import { ref } from 'vue';
import { Button, Card, Input } from '@redrobui/vue';

const email = ref('');

const handleSubmit = () => {
  console.log('Email:', email.value);
};
</script>

<template>
  <Card>
    <h1>Welcome to Redrob UI</h1>
    <Input 
      v-model="email" 
      label="Email" 
      placeholder="[email protected]"
      helper-text="We'll never share your email"
    />
    <Button variant="primary" @click="handleSubmit">
      Submit
    </Button>
  </Card>
</template>

Components

Button

A versatile button component with multiple variants and states.

<template>
  <Button 
    variant="primary" 
    size="md" 
    :full-width="false" 
    :is-loading="false"
    :disabled="false"
  >
    Click me
  </Button>
</template>

Props:

| Prop | Type | Default | Description | |------|------|---------|-------------| | variant | 'primary' \| 'secondary' \| 'outline' \| 'ghost' \| 'danger' | 'primary' | Visual style variant | | size | 'sm' \| 'md' \| 'lg' | 'md' | Button size | | fullWidth | boolean | false | Make button full width | | isLoading | boolean | false | Show loading spinner | | disabled | boolean | false | Disable the button |

Slots:

<template>
  <!-- Left icon slot -->
  <Button>
    <template #leftIcon>
      <HomeIcon class="w-4 h-4" />
    </template>
    Home
  </Button>

  <!-- Right icon slot -->
  <Button variant="secondary">
    Search
    <template #rightIcon>
      <SearchIcon class="w-4 h-4" />
    </template>
  </Button>
</template>

<script setup lang="ts">
import { Button } from '@redrobui/vue';
import { HomeIcon, SearchIcon } from '@redrobui/icons';
</script>

Examples:

<template>
  <div class="flex flex-col gap-4">
    <!-- Variants -->
    <Button variant="primary">Primary</Button>
    <Button variant="secondary">Secondary</Button>
    <Button variant="outline">Outline</Button>
    <Button variant="ghost">Ghost</Button>
    <Button variant="danger">Danger</Button>

    <!-- Sizes -->
    <Button size="sm">Small</Button>
    <Button size="md">Medium</Button>
    <Button size="lg">Large</Button>

    <!-- States -->
    <Button :is-loading="true">Loading...</Button>
    <Button :disabled="true">Disabled</Button>
    <Button :full-width="true">Full Width</Button>
  </div>
</template>

Card

A container component with consistent padding and shadow.

<template>
  <Card padding="md" :shadow="true">
    <h2>Card Title</h2>
    <p>Card content goes here</p>
  </Card>
</template>

Props:

| Prop | Type | Default | Description | |------|------|---------|-------------| | padding | 'none' \| 'sm' \| 'md' \| 'lg' | 'md' | Internal padding | | shadow | boolean | true | Show drop shadow |

Examples:

<template>
  <div class="grid gap-4">
    <!-- Standard card -->
    <Card>
      <h3 class="text-lg font-semibold mb-2">Standard Card</h3>
      <p class="text-neutral-600">With default padding and shadow</p>
    </Card>

    <!-- Large padding -->
    <Card padding="lg">
      <h3 class="text-lg font-semibold mb-2">Large Padding</h3>
      <p class="text-neutral-600">More spacious layout</p>
    </Card>

    <!-- No shadow -->
    <Card :shadow="false">
      <h3 class="text-lg font-semibold mb-2">Flat Card</h3>
      <p class="text-neutral-600">Without shadow</p>
    </Card>
  </div>
</template>

Input

Form input component with label, helper text, and error states.

<template>
  <Input
    v-model="value"
    label="Email"
    placeholder="Enter your email"
    helper-text="We'll never share your email"
    :error="errorMessage"
    size="md"
    :disabled="false"
    type="text"
  />
</template>

<script setup lang="ts">
import { ref } from 'vue';

const value = ref('');
const errorMessage = ref('');
</script>

Props:

| Prop | Type | Default | Description | |------|------|---------|-------------| | modelValue | string | '' | Input value (use with v-model) | | label | string | undefined | Input label | | placeholder | string | undefined | Placeholder text | | helperText | string | undefined | Helper text below input | | error | string | undefined | Error message (shows red) | | size | 'sm' \| 'md' \| 'lg' | 'md' | Input size | | disabled | boolean | false | Disable input | | type | string | 'text' | HTML input type |

Events:

  • update:modelValue - Emitted when value changes (use with v-model)

Examples:

<template>
  <div class="flex flex-col gap-4">
    <!-- Basic input -->
    <Input 
      v-model="name" 
      label="Name" 
      placeholder="John Doe"
    />

    <!-- With helper text -->
    <Input 
      v-model="email" 
      label="Email"
      type="email"
      placeholder="[email protected]"
      helper-text="We'll never share your email"
    />

    <!-- With error -->
    <Input 
      v-model="password" 
      label="Password"
      type="password"
      :error="passwordError"
    />

    <!-- Disabled -->
    <Input 
      v-model="username" 
      label="Username"
      :disabled="true"
    />

    <!-- Different sizes -->
    <Input v-model="small" label="Small" size="sm" />
    <Input v-model="medium" label="Medium" size="md" />
    <Input v-model="large" label="Large" size="lg" />
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { Input } from '@redrobui/vue';

const name = ref('');
const email = ref('');
const password = ref('');
const passwordError = ref('Password must be at least 8 characters');
const username = ref('locked_user');
const small = ref('');
const medium = ref('');
const large = ref('');
</script>

Form Example

Complete form with validation:

<template>
  <Card>
    <h2 class="text-2xl font-bold mb-6">Sign Up</h2>
    
    <form @submit.prevent="handleSubmit" class="flex flex-col gap-4">
      <Input
        v-model="form.name"
        label="Full Name"
        placeholder="John Doe"
        :error="errors.name"
      />
      
      <Input
        v-model="form.email"
        label="Email"
        type="email"
        placeholder="[email protected]"
        :error="errors.email"
        helper-text="We'll never share your email"
      />
      
      <Input
        v-model="form.password"
        label="Password"
        type="password"
        :error="errors.password"
        helper-text="Must be at least 8 characters"
      />

      <div class="flex gap-2 mt-4">
        <Button 
          type="submit" 
          variant="primary" 
          :is-loading="isSubmitting"
          :full-width="true"
        >
          Sign Up
        </Button>
      </div>
    </form>
  </Card>
</template>

<script setup lang="ts">
import { ref, reactive } from 'vue';
import { Button, Card, Input } from '@redrobui/vue';

const form = reactive({
  name: '',
  email: '',
  password: '',
});

const errors = reactive({
  name: '',
  email: '',
  password: '',
});

const isSubmitting = ref(false);

const validateForm = () => {
  let isValid = true;
  
  // Reset errors
  errors.name = '';
  errors.email = '';
  errors.password = '';
  
  // Validate name
  if (!form.name.trim()) {
    errors.name = 'Name is required';
    isValid = false;
  }
  
  // Validate email
  if (!form.email.trim()) {
    errors.email = 'Email is required';
    isValid = false;
  } else if (!/\S+@\S+\.\S+/.test(form.email)) {
    errors.email = 'Email is invalid';
    isValid = false;
  }
  
  // Validate password
  if (!form.password) {
    errors.password = 'Password is required';
    isValid = false;
  } else if (form.password.length < 8) {
    errors.password = 'Password must be at least 8 characters';
    isValid = false;
  }
  
  return isValid;
};

const handleSubmit = async () => {
  if (!validateForm()) return;
  
  isSubmitting.value = true;
  
  try {
    // Simulate API call
    await new Promise(resolve => setTimeout(resolve, 2000));
    console.log('Form submitted:', form);
    
    // Reset form
    form.name = '';
    form.email = '';
    form.password = '';
  } catch (error) {
    console.error('Submission error:', error);
  } finally {
    isSubmitting.value = false;
  }
};
</script>

TypeScript Support

Full TypeScript support with exported types:

<script setup lang="ts">
import type { ButtonProps, CardProps, InputProps } from '@redrobui/vue';
import { Button, Card, Input } from '@redrobui/vue';

// Use types for custom wrappers
const myButtonProps: ButtonProps = {
  variant: 'primary',
  size: 'lg',
  fullWidth: true,
};
</script>

<template>
  <Button v-bind="myButtonProps">
    Custom Button
  </Button>
</template>

Customization

Using with Icons

npm install @redrobui/icons
<template>
  <Button variant="primary">
    <template #leftIcon>
      <HomeIcon class="w-4 h-4" />
    </template>
    Go Home
  </Button>
</template>

<script setup lang="ts">
import { Button } from '@redrobui/vue';
import { HomeIcon } from '@redrobui/icons';
</script>

Custom Styling

You can add custom classes to any component:

<template>
  <Button class="my-custom-class">
    Custom Button
  </Button>
  
  <Card class="border-2 border-primary-500">
    Custom Card
  </Card>
</template>

Extending Tailwind Theme

// tailwind.config.js
const redrobConfig = require('@redrobui/tailwind-config');

module.exports = {
  presets: [redrobConfig],
  theme: {
    extend: {
      colors: {
        brand: '#your-color',
      },
    },
  },
  content: [
    './src/**/*.{vue,js,ts,jsx,tsx}',
    './node_modules/@redrobui/vue/**/*.{vue,js,ts,jsx,tsx,mjs}',
  ],
};

Troubleshooting

Styles Not Working?

Problem: Components render but have no styling.

Solutions:

  1. Check Tailwind config - Make sure you have the node_modules/@redrobui/vue/**/*.{vue,js,ts,jsx,tsx,mjs} path in your content array.

  2. Import styles - Ensure you're importing @redrobui/vue/styles.css in your CSS file.

  3. Import CSS file - Make sure your CSS file is imported in main.ts.

  4. Check package names - Verify you're using @redrobui/tailwind-config.

  5. Rebuild packages - If working in a monorepo, rebuild the packages:

    npm run build --workspace=@redrobui/tailwind-config
    npm run build --workspace=@redrobui/vue

TypeScript Errors?

Make sure you have Vue TypeScript support:

npm install -D @vue/tsconfig vue-tsc

Vite Not Finding Modules?

If using Vite, make sure your vite.config.ts is properly configured:

// vite.config.ts
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';

export default defineConfig({
  plugins: [vue()],
  optimizeDeps: {
    include: ['@redrobui/vue'],
  },
});

Development

Start dev server

npm run dev

This starts the Vite dev server at http://localhost:3001 with Hot Module Replacement (HMR).

Build

npm run build

Builds the library to dist/ folder with:

  • ES modules (.mjs)
  • CommonJS (.js)
  • TypeScript declarations (.d.ts)
  • Compiled CSS (styles.css)

Preview

npm run preview

Preview the production build locally.

Storybook

To see all components in action, check out the Storybook demo:

# From the repository root
npm run dev --workspace=@redrobui/demo

Visit http://localhost:6006 to browse all components with interactive examples.

Best Practices

  1. Import styles once - Only import @redrobui/vue/styles.css once in your main CSS file
  2. Use v-model - For Input components, always use v-model for two-way binding
  3. Leverage variants - Use component variants instead of custom styling when possible
  4. Type safety - Use TypeScript for better developer experience
  5. Accessibility - Components follow accessibility best practices by default

Complete Minimal Setup Example

Here's a complete working example from scratch:

1. Install dependencies:

npm create vue@latest my-app
cd my-app
npm install @redrobui/vue @redrobui/tailwind-config tailwindcss postcss autoprefixer
npx tailwindcss init -p

2. Configure Tailwind (tailwind.config.js):

const redrobConfig = require('@redrobui/tailwind-config');

module.exports = {
  presets: [redrobConfig],
  content: [
    './index.html',
    './src/**/*.{vue,js,ts,jsx,tsx}',
    './node_modules/@redrobui/vue/**/*.{vue,js,ts,jsx,tsx,mjs}',
  ],
};

3. Create CSS file (src/style.css):

@import '@redrobui/vue/styles.css';
@tailwind base;
@tailwind components;
@tailwind utilities;

4. Update main.ts (src/main.ts):

import { createApp } from 'vue';
import './style.css';
import App from './App.vue';

createApp(App).mount('#app');

5. Use components (src/App.vue):

<script setup lang="ts">
import { ref } from 'vue';
import { Button, Card, Input } from '@redrobui/vue';

const name = ref('');
</script>

<template>
  <div class="min-h-screen bg-neutral-50 p-8">
    <Card class="max-w-md mx-auto">
      <h1 class="text-2xl font-bold mb-4">Hello Redrob UI!</h1>
      <Input v-model="name" label="Your Name" placeholder="Enter name" />
      <Button variant="primary" class="mt-4">Submit</Button>
    </Card>
  </div>
</template>

6. Run dev server:

npm run dev

That's it! You should see styled components. ✅

Related Packages

Examples

See the Storybook demo for complete implementation examples.

License

MIT