Transform strings between 19+ case formats with full TypeScript support
Features β’ Installation β’ Quick Start β’ API Reference β’ Examples β’ Documentation β’ Live Demo
β οΈ Version 2.0 - Complete rewrite for Vue 3 with full TypeScript support and 100% test coverage. For Vue 2, use version 1.x.
import { camelCase, pascalCase, snakeCase } from 'vue-case';
camelCase('hello world') // β 'helloWorld'
pascalCase('hello world') // β 'HelloWorld'
snakeCase('hello world') // β 'hello_world'
|
|
|
npm npm install vue-case |
pnpm pnpm add vue-case |
yarn yarn add vue-case |
<!-- Vue 3 -->
<script src="https://unpkg.com/vue@3"></script>
<!-- vue-case -->
<script src="https://unpkg.com/vue-case@2"></script>
<script>
const { createApp } = Vue;
const app = createApp({
template: '<div>{{ $camelCase("hello world") }}</div>'
});
app.use(VueCase);
app.mount('#app');
</script><template>
<div class="converter">
<input v-model="text" placeholder="Enter text..." />
<div class="results">
<p>camelCase: <code>{{ camelCase(text) }}</code></p>
<p>PascalCase: <code>{{ pascalCase(text) }}</code></p>
<p>snake_case: <code>{{ snakeCase(text) }}</code></p>
<p>kebab-case: <code>{{ paramCase(text) }}</code></p>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useCase } from 'vue-case';
const { camelCase, pascalCase, snakeCase, paramCase } = useCase();
const text = ref('Hello World');
</script><template>
<div>
<p>{{ $camelCase(username) }}</p>
<p>{{ $snakeCase(username) }}</p>
<p>{{ $truncate(description, 50) }}</p>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
data() {
return {
username: 'John Doe',
description: 'A very long description text...'
};
}
});
</script>import { camelCase, pascalCase, snakeCase, constantCase } from 'vue-case';
// Use anywhere in your code
const apiEndpoint = camelCase('user profile'); // 'userProfile'
const className = pascalCase('my component'); // 'MyComponent'
const dbColumn = snakeCase('user name'); // 'user_name'
const envVar = constantCase('api key'); // 'API_KEY'Setup in main.ts:
import { createApp } from 'vue';
import VueCase from 'vue-case';
import App from './App.vue';
const app = createApp(App);
// Install plugin globally
app.use(VueCase);
app.mount('#app');Use in any component:
<template>
<div>
<!-- Available as $camelCase, $pascalCase, $snakeCase, etc. -->
<h1>{{ $titleCase(pageTitle) }}</h1>
<p>{{ $truncate(content, 100) }}</p>
</div>
</template><script setup lang="ts">
import { useCase } from 'vue-case';
import { ref, computed } from 'vue';
// Get all transformation methods
const { camelCase, pascalCase, snakeCase, constantCase, truncate } = useCase();
const inputText = ref('user profile settings');
// Use in computed properties
const apiRoute = computed(() => camelCase(inputText.value));
const component = computed(() => pascalCase(inputText.value));
const database = computed(() => snakeCase(inputText.value));
const environment = computed(() => constantCase(inputText.value));
</script>
<template>
<div>
<input v-model="inputText" />
<ul>
<li>API: {{ apiRoute }}</li>
<li>Component: {{ component }}</li>
<li>Database: {{ database }}</li>
<li>Environment: {{ environment }}</li>
</ul>
</div>
</template>import type {
CaseMethods,
CaseTransformFn,
CaseCheckFn,
TruncateFn,
VueCaseOptions
} from 'vue-case';
import { camelCase, pascalCase, useCase } from 'vue-case';
// Type-safe function
const transformUserInput: CaseTransformFn = (input: string) => {
return camelCase(input);
};
// Type-safe composable usage
const caseMethods: CaseMethods = useCase();
// Use in classes
class StringTransformer {
private transform: CaseTransformFn;
constructor() {
this.transform = pascalCase;
}
process(input: string): string {
return this.transform(input);
}
}| Method | Input | Output | Use Case |
|---|---|---|---|
camelCase |
'hello world' |
'helloWorld' |
JavaScript variables, object keys |
pascalCase |
'hello world' |
'HelloWorld' |
Component names, class names |
snakeCase |
'hello world' |
'hello_world' |
Database columns, Python variables |
constantCase |
'hello world' |
'HELLO_WORLD' |
Environment variables, constants |
paramCase |
'hello world' |
'hello-world' |
URLs, CSS classes, file names |
dotCase |
'hello world' |
'hello.world' |
Object paths, configuration keys |
pathCase |
'hello world' |
'hello/world' |
File paths, routes |
headerCase |
'hello world' |
'Hello-World' |
HTTP headers |
capitalCase |
'hello world' |
'Hello World' |
Titles, display names |
titleCase |
'hello world' |
'Hello World' |
Book titles, headings |
sentenceCase |
'HELLO WORLD' |
'Hello world' |
Sentences, descriptions |
noCase |
'helloWorld' |
'hello world' |
Remove formatting |
lowerCase |
'HELLO WORLD' |
'hello world' |
Normalize to lowercase |
upperCase |
'hello world' |
'HELLO WORLD' |
Normalize to uppercase |
lowerCaseFirst |
'Hello' |
'hello' |
Lowercase first letter |
upperCaseFirst |
'hello' |
'Hello' |
Capitalize first letter |
swapCase |
'Hello World' |
'hELLO wORLD' |
Toggle case |
| Method | Signature | Description | Example |
|---|---|---|---|
truncate |
(text: string, length?: number) |
Truncate text with "..." | truncate('Hello World', 5) β 'Hello...' |
isLowerCase |
(text: string): boolean |
Check if lowercase | isLowerCase('hello') β true |
isUpperCase |
(text: string): boolean |
Check if uppercase | isUpperCase('HELLO') β true |
import { camelCase, snakeCase } from 'vue-case';
// Transform snake_case API responses to camelCase
function transformResponse<T extends Record<string, any>>(data: T): Record<string, any> {
return Object.entries(data).reduce((acc, [key, value]) => {
acc[camelCase(key)] = value;
return acc;
}, {} as Record<string, any>);
}
// Transform camelCase to snake_case for API requests
function transformRequest<T extends Record<string, any>>(data: T): Record<string, any> {
return Object.entries(data).reduce((acc, [key, value]) => {
acc[snakeCase(key)] = value;
return acc;
}, {} as Record<string, any>);
}
// Usage with Axios
import axios from 'axios';
const api = axios.create({
baseURL: 'https://api.example.com',
transformResponse: [(data) => {
const parsed = JSON.parse(data);
return transformResponse(parsed);
}],
transformRequest: [(data) => {
return JSON.stringify(transformRequest(data));
}]
});
// Now your API calls work seamlessly:
const response = await api.get('/user_profile'); // API returns user_name
console.log(response.data.userName); // Access as userName<template>
<component
:is="getComponent(type)"
:class="getClassName(type)"
>
{{ content }}
</component>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { pascalCase, paramCase } from 'vue-case';
interface Props {
type: string;
content: string;
}
const props = defineProps<Props>();
// Convert 'user card' β 'UserCard' for component name
const getComponent = (type: string) => {
return pascalCase(type);
};
// Convert 'user card' β 'user-card' for CSS class
const getClassName = (type: string) => {
return `component-${paramCase(type)}`;
};
</script><template>
<form @submit.prevent="handleSubmit">
<div v-for="field in formFields" :key="field.name">
<label :for="field.id">{{ field.label }}</label>
<input
:id="field.id"
:name="field.name"
v-model="formData[field.name]"
/>
</div>
<button type="submit">Submit</button>
</form>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { camelCase, paramCase, capitalCase } from 'vue-case';
const fieldNames = ['user name', 'email address', 'phone number'];
const formFields = computed(() =>
fieldNames.map(name => ({
name: camelCase(name), // 'userName' for v-model
id: paramCase(name), // 'user-name' for id/for
label: capitalCase(name) // 'User Name' for display
}))
);
const formData = ref(
fieldNames.reduce((acc, name) => {
acc[camelCase(name)] = '';
return acc;
}, {} as Record<string, string>)
);
const handleSubmit = () => {
console.log(formData.value);
// { userName: '...', emailAddress: '...', phoneNumber: '...' }
};
</script><template>
<div class="blog-editor">
<input
v-model="title"
placeholder="Blog post title"
@input="generateSlug"
/>
<p class="slug-preview">
URL: <code>{{ baseUrl }}/{{ slug }}</code>
</p>
<button @click="copySlug">Copy URL</button>
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { paramCase } from 'vue-case';
const title = ref('');
const baseUrl = 'https://myblog.com/posts';
const slug = computed(() => paramCase(title.value));
const generateSlug = () => {
// Automatically updates via computed property
};
const copySlug = async () => {
await navigator.clipboard.writeText(`${baseUrl}/${slug.value}`);
alert('URL copied!');
};
</script>import { constantCase, camelCase } from 'vue-case';
class EnvironmentConfig {
private config: Record<string, string> = {};
// Load from process.env
loadFromEnv() {
this.config = {
[camelCase('API_KEY')]: process.env.API_KEY || '',
[camelCase('DATABASE_URL')]: process.env.DATABASE_URL || '',
[camelCase('APP_NAME')]: process.env.APP_NAME || '',
};
return this.config;
}
// Generate .env content
generateEnvFile(config: Record<string, string>): string {
return Object.entries(config)
.map(([key, value]) => `${constantCase(key)}=${value}`)
.join('\n');
}
}
// Usage
const env = new EnvironmentConfig();
const config = {
apiKey: 'secret123',
databaseUrl: 'postgresql://...',
appName: 'My App'
};
console.log(env.generateEnvFile(config));
// Output:
// API_KEY=secret123
// DATABASE_URL=postgresql://...
// APP_NAME=My App<template>
<div :class="bem('container')">
<div :class="bem('header')">
<h1 :class="bem('title', 'large')">{{ title }}</h1>
</div>
<div :class="bem('content', isActive && 'active')">
<slot />
</div>
</div>
</template>
<script setup lang="ts">
import { paramCase } from 'vue-case';
import { ref } from 'vue';
const componentName = 'UserProfile';
const blockName = paramCase(componentName); // 'user-profile'
// BEM (Block Element Modifier) helper
const bem = (element: string, modifier?: string | boolean) => {
const base = `${blockName}__${paramCase(element)}`;
if (modifier && typeof modifier === 'string') {
return `${base} ${base}--${paramCase(modifier)}`;
}
return base;
};
const title = ref('User Profile');
const isActive = ref(true);
// Generates classes like:
// user-profile__container
// user-profile__header
// user-profile__title user-profile__title--large
// user-profile__content user-profile__content--active
</script>import { snakeCase } from 'vue-case';
interface QueryFilters {
[key: string]: any;
}
class QueryBuilder {
private tableName: string;
private filters: Record<string, any> = {};
constructor(tableName: string) {
this.tableName = snakeCase(tableName);
}
where(filters: QueryFilters) {
this.filters = Object.entries(filters).reduce((acc, [key, value]) => {
acc[snakeCase(key)] = value;
return acc;
}, {} as Record<string, any>);
return this;
}
build(): string {
const conditions = Object.entries(this.filters)
.map(([key, value]) => `${key} = '${value}'`)
.join(' AND ');
return `SELECT * FROM ${this.tableName} WHERE ${conditions}`;
}
}
// Usage
const query = new QueryBuilder('UserProfile')
.where({
firstName: 'John',
emailAddress: 'john@example.com'
})
.build();
console.log(query);
// SELECT * FROM user_profile WHERE first_name = 'John' AND email_address = 'john@example.com'import { dotCase } from 'vue-case';
interface TranslationKeys {
[key: string]: string | TranslationKeys;
}
function generateI18nKeys(prefix: string, keys: string[]): TranslationKeys {
return keys.reduce((acc, key) => {
const i18nKey = dotCase(`${prefix} ${key}`);
acc[i18nKey] = `${prefix}.${key}`;
return acc;
}, {} as TranslationKeys);
}
// Generate translation keys
const userKeys = generateI18nKeys('user', [
'profile settings',
'account details',
'privacy settings'
]);
console.log(userKeys);
// {
// 'user.profile.settings': 'user.profile settings',
// 'user.account.details': 'user.account details',
// 'user.privacy.settings': 'user.privacy settings'
// }
// Use in Vue components
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const title = t(userKeys['user.profile.settings']);Full support for all major testing frameworks:
import { describe, it, expect } from 'vitest'; // or jest
import { camelCase, pascalCase, snakeCase } from 'vue-case';
describe('vue-case transformations', () => {
it('transforms to camelCase', () => {
expect(camelCase('hello world')).toBe('helloWorld');
expect(camelCase('hello-world')).toBe('helloWorld');
expect(camelCase('hello_world')).toBe('helloWorld');
});
it('transforms to PascalCase', () => {
expect(pascalCase('hello world')).toBe('HelloWorld');
});
it('handles edge cases', () => {
expect(camelCase('')).toBe('');
expect(camelCase('a')).toBe('a');
expect(camelCase('hello@world')).toBe('helloWorld');
});
});- β‘ Minimal Bundle Size: ~22KB minified
- π Tree Shakeable: Import only what you need
- π― Zero Dependencies: Built on lightweight
text-caselibrary - π¨ Fast Execution: Optimized for performance
- π¦ Efficient: No runtime overhead
![]() |
![]() |
![]() |
![]() |
|---|---|---|---|
| Latest β | Latest β | Latest β | Latest β |
import { createApp } from 'vue';
import VueCase from 'vue-case';
import type { VueCaseOptions } from 'vue-case';
const app = createApp(App);
// Custom options (currently all methods are included by default)
const options: VueCaseOptions = {
// Future: Configure which methods to include
};
app.use(VueCase, options);import { camelCase, upperCaseFirst, lowerCase } from 'vue-case';
// Create custom transformations
const customTransform = (text: string) => {
return upperCaseFirst(camelCase(lowerCase(text)));
};
customTransform('HELLO WORLD'); // 'HelloWorld'// All available types exported
export type CaseTransformFn = (value: string) => string;
export type TruncateFn = (value: string, length?: number) => string;
export type CaseCheckFn = (value: string) => boolean;
export interface CaseMethods {
camelCase: CaseTransformFn;
pascalCase: CaseTransformFn;
capitalCase: CaseTransformFn;
headerCase: CaseTransformFn;
titleCase: CaseTransformFn;
pathCase: CaseTransformFn;
paramCase: CaseTransformFn;
dotCase: CaseTransformFn;
snakeCase: CaseTransformFn;
constantCase: CaseTransformFn;
lowerCase: CaseTransformFn;
lowerCaseFirst: CaseTransformFn;
upperCase: CaseTransformFn;
upperCaseFirst: CaseTransformFn;
swapCase: CaseTransformFn;
sentenceCase: CaseTransformFn;
noCase: CaseTransformFn;
isLowerCase: CaseCheckFn;
isUpperCase: CaseCheckFn;
truncate: TruncateFn;
}
export interface VueCaseOptions {
// Plugin configuration options
}
// Global property types for Options API
declare module 'vue' {
interface ComponentCustomProperties {
$case: CaseMethods;
$camelCase: CaseTransformFn;
$pascalCase: CaseTransformFn;
// ... all other methods
}
}Q: Can I use this with Vue 2?
A: No, version 2.0+ is for Vue 3 only. For Vue 2, use version 1.x:
npm install vue-case@1Q: Does this work with Nuxt 3?
A: Yes! Just install and use it like any other Vue 3 plugin:
// plugins/vue-case.ts
import VueCase from 'vue-case';
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.use(VueCase);
});Q: Can I use this without Vue?
A: Yes! Use direct imports:
import { camelCase, snakeCase } from 'vue-case';
// Works in any JavaScript/TypeScript projectQ: Is this tree-shakeable?
A: Yes! When you use direct imports, only the methods you import will be included in your bundle.
Q: What's the difference between paramCase and kebab-case?
A: They're the same! paramCase produces kebab-case format (hello-world).
We welcome contributions! Here's how you can help:
- π΄ Fork the repository
- π§ Create your feature branch (
git checkout -b feature/AmazingFeature) - β
Test your changes (
pnpm test) - πΎ Commit your changes (
git commit -m 'Add some AmazingFeature') - π€ Push to the branch (
git push origin feature/AmazingFeature) - π Open a Pull Request
# Clone the repository
git clone https://github.com/idimetrix/vue-case.git
cd vue-case
# Install dependencies
pnpm install
# Run tests
pnpm test
# Run tests with coverage
pnpm test --coverage
# Build library
pnpm run build
# Type check
pnpm run typecheck
# Run dev server
pnpm serveSee CHANGELOG.md for detailed release notes.
If you find vue-case helpful, please consider:
- β Star the repository on GitHub
- π Report any bugs you find
- π Contribute to documentation
- π‘ Suggest new features
- π’ Share with the community
- π Sponsor the development
Built with β€οΈ using:
- Vue 3 - The Progressive JavaScript Framework
- TypeScript - JavaScript with syntax for types
- text-case - Text transformation utilities
Made with β€οΈ for the Vue.js community



