Validates data with Yup schema builder using chainable methods, custom rules, and TypeScript inference. Use when validating forms with React Hook Form or Formik, or when needing flexible schema validation.
Validates data with Yup schema builder using chainable methods, custom rules, and TypeScript inference. Use when validating forms with React Hook Form or Formik, or when needing flexible schema validation.
/plugin marketplace add mgd34msu/goodvibes-plugin/plugin install goodvibes@goodvibes-marketThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/methods.mdSchema validation library with a fluent, chainable API for JavaScript and TypeScript.
npm install yup
import * as yup from 'yup';
const schema = yup.object({
name: yup.string().required(),
email: yup.string().email().required(),
age: yup.number().positive().integer(),
});
// Validate
const data = await schema.validate({ name: 'John', email: 'john@example.com' });
// Check validity
const isValid = await schema.isValid(data);
yup.string()
.required('Name is required')
.min(2, 'At least 2 characters')
.max(50, 'At most 50 characters')
.matches(/^[a-zA-Z]+$/, 'Only letters')
.email('Invalid email')
.url('Invalid URL')
.uuid('Invalid UUID')
.lowercase()
.uppercase()
.trim()
.default('Anonymous')
yup.number()
.required('Required')
.min(0, 'Must be positive')
.max(100, 'Max 100')
.positive('Must be positive')
.negative('Must be negative')
.integer('Must be integer')
.moreThan(0, 'Greater than 0')
.lessThan(100, 'Less than 100')
.truncate()
.round()
.default(0)
yup.boolean()
.required()
.isTrue('Must accept terms')
.isFalse()
.default(false)
yup.date()
.required()
.min(new Date(), 'Must be in the future')
.max(new Date('2030-12-31'), 'Too far ahead')
.default(() => new Date())
yup.array()
.of(yup.string().required())
.min(1, 'At least one item')
.max(5, 'At most 5 items')
.required()
.default([])
// Tuple-like array
yup.tuple([
yup.string().required(),
yup.number().required(),
])
yup.object({
name: yup.string().required(),
age: yup.number().positive(),
})
.noUnknown() // Reject unknown keys
.strict() // Don't coerce types
yup.mixed()
.oneOf(['option1', 'option2'], 'Must be option1 or option2')
.notOneOf(['forbidden'])
.required()
const registrationSchema = yup.object({
email: yup.string()
.email('Invalid email')
.required('Email is required'),
password: yup.string()
.min(8, 'At least 8 characters')
.matches(/[a-z]/, 'Need lowercase letter')
.matches(/[A-Z]/, 'Need uppercase letter')
.matches(/[0-9]/, 'Need number')
.required('Password is required'),
confirmPassword: yup.string()
.oneOf([yup.ref('password')], 'Passwords must match')
.required('Confirm password'),
age: yup.number()
.positive()
.integer()
.min(18, 'Must be 18+')
.required('Age is required'),
terms: yup.boolean()
.isTrue('Must accept terms'),
});
const addressSchema = yup.object({
street: yup.string().required(),
city: yup.string().required(),
state: yup.string().length(2).required(),
zip: yup.string()
.matches(/^\d{5}(-\d{4})?$/, 'Invalid ZIP')
.required(),
country: yup.string().default('US'),
});
const paymentSchema = yup.object({
cardNumber: yup.string()
.matches(/^\d{16}$/, 'Invalid card number')
.required(),
expiry: yup.string()
.matches(/^(0[1-9]|1[0-2])\/\d{2}$/, 'MM/YY format')
.required(),
cvv: yup.string()
.matches(/^\d{3,4}$/, 'Invalid CVV')
.required(),
amount: yup.number()
.positive()
.required(),
});
const schema = yup.object({
hasCompany: yup.boolean(),
companyName: yup.string().when('hasCompany', {
is: true,
then: (schema) => schema.required('Company name required'),
otherwise: (schema) => schema.notRequired(),
}),
});
const schema = yup.object({
type: yup.string().oneOf(['personal', 'business']),
taxId: yup.string(),
ssn: yup.string(),
}).test('tax-info', 'Tax info required', function(value) {
if (value.type === 'business') {
return !!value.taxId;
}
return !!value.ssn;
});
const schema = yup.string().test(
'is-valid-username',
'Username already taken',
async (value) => {
if (!value) return true;
const available = await checkUsername(value);
return available;
}
);
const schema = yup.object({
password: yup.string().required(),
confirmPassword: yup.string()
.test('passwords-match', 'Passwords must match', function(value) {
return value === this.parent.password;
}),
});
yup.addMethod(yup.string, 'phone', function(message) {
return this.test('phone', message || 'Invalid phone', (value) => {
if (!value) return true;
return /^\+?[\d\s-()]+$/.test(value);
});
});
// Usage
const schema = yup.object({
phone: yup.string().phone('Invalid phone number'),
});
const userSchema = yup.object({
name: yup.string().required(),
email: yup.string().email().required(),
age: yup.number().positive(),
});
type User = yup.InferType<typeof userSchema>;
// { name: string; email: string; age: number | undefined }
const schema = yup.object({
role: yup.string().default('user'),
active: yup.boolean().default(true),
});
type Config = yup.InferType<typeof schema>;
// { role: string; active: boolean }
const schema = yup.string().trim().lowercase();
const result = schema.cast(' HELLO '); // 'hello'
const schema = yup.string().transform((value) => {
return value?.replace(/\s+/g, ' ').trim();
});
const schema = yup.object({
firstName: yup.string(),
lastName: yup.string(),
}).transform((value) => ({
...value,
fullName: `${value.firstName} ${value.lastName}`,
}));
try {
const result = await schema.validate(data, {
abortEarly: false, // Collect all errors
stripUnknown: true, // Remove unknown keys
strict: false, // Allow coercion
context: { user: currentUser },
});
} catch (err) {
if (err instanceof yup.ValidationError) {
console.log(err.errors); // All error messages
console.log(err.inner); // Detailed errors
}
}
try {
const result = schema.validateSync(data);
} catch (err) {
// Handle error
}
const valid = await schema.isValid(data);
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
const schema = yup.object({
email: yup.string().email().required(),
password: yup.string().min(8).required(),
});
type FormData = yup.InferType<typeof schema>;
function Form() {
const { register, handleSubmit, formState: { errors } } = useForm<FormData>({
resolver: yupResolver(schema),
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register('email')} />
{errors.email && <span>{errors.email.message}</span>}
<input {...register('password')} type="password" />
{errors.password && <span>{errors.password.message}</span>}
<button type="submit">Submit</button>
</form>
);
}
import { Formik, Form, Field, ErrorMessage } from 'formik';
const schema = yup.object({
email: yup.string().email().required(),
});
function MyForm() {
return (
<Formik
initialValues={{ email: '' }}
validationSchema={schema}
onSubmit={handleSubmit}
>
<Form>
<Field name="email" type="email" />
<ErrorMessage name="email" />
<button type="submit">Submit</button>
</Form>
</Formik>
);
}
See references/methods.md for complete method reference.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.