@redrobui/vue
v0.4.0
Published
Vue 3 components for Redrob AI Design System
Maintainers
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-configSetup
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-700bg-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 withv-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:
Check Tailwind config - Make sure you have the
node_modules/@redrobui/vue/**/*.{vue,js,ts,jsx,tsx,mjs}path in yourcontentarray.Import styles - Ensure you're importing
@redrobui/vue/styles.cssin your CSS file.Import CSS file - Make sure your CSS file is imported in
main.ts.Check package names - Verify you're using
@redrobui/tailwind-config.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-tscVite 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 devThis starts the Vite dev server at http://localhost:3001 with Hot Module Replacement (HMR).
Build
npm run buildBuilds the library to dist/ folder with:
- ES modules (.mjs)
- CommonJS (.js)
- TypeScript declarations (.d.ts)
- Compiled CSS (styles.css)
Preview
npm run previewPreview 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/demoVisit http://localhost:6006 to browse all components with interactive examples.
Best Practices
- Import styles once - Only import
@redrobui/vue/styles.cssonce in your main CSS file - Use v-model - For Input components, always use
v-modelfor two-way binding - Leverage variants - Use component variants instead of custom styling when possible
- Type safety - Use TypeScript for better developer experience
- 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 -p2. 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 devThat's it! You should see styled components. ✅
Related Packages
- @redrobui/tokens - Design tokens
- @redrobui/tailwind-config - Tailwind preset
- @redrobui/icons - Icon library
- @redrobui/react - React components
Examples
See the Storybook demo for complete implementation examples.
License
MIT
