inclusive-kit
v0.3.1
Published
Inclusive forms toolkit — field factories, validators, text analyzer, and form auditor
Maintainers
Readme
inclusive-kit
Inclusive forms toolkit for Node.js and browsers — field factories, validators, a text analyzer, and a form auditor.
Zero dependencies · ESM + CJS · Tree-shakeable · TypeScript-first
📖 Documentation & live playground →
Try every module in the browser: search 52 gender identities, render pride flags, analyze and rewrite text, and score a form live.
Why this exists
Most "inclusive options" resources are copy-paste lists. inclusive-kit ships executable value: factories that build accessible form fields, validators that drop exclusionary assumptions, a text analyzer that flags non-inclusive language, and an auditor that scores your entire form definition and tells you exactly what to fix.
Install
npm install inclusive-kit
# or
pnpm add inclusive-kitQuickstart
import { genderField, validatePersonName, analyze, auditForm } from "inclusive-kit";
// Build an inclusive gender field for your form
const field = genderField({ locale: "en", allowSelfDescribe: true });
console.log(field.options); // ordered: prefer-not-to-say, non-binary, …, woman, man
console.log(field.why); // explains the design decision
// Validate a name without excluding mononyms or Unicode
const result = validatePersonName("María-José O'Neill 陳");
// → { valid: true }
// Analyze label/copy text for non-inclusive language
const findings = analyze("Fill in the form, guys!", { locale: "en" });
// → { findings: [{ term: "guys", suggestions: ["everyone", "folks", …], … }] }
// Audit an entire form definition
const audit = auditForm({
fields: [
{ id: "gender", type: "select", label: "Gender", options: ["Male", "Female"], hasPreferNotToSay: false, required: true },
{ id: "first-name", type: "text", label: "First name" },
{ id: "last-name", type: "text", label: "Last name" },
],
});
console.log(audit.score); // 0–100
console.log(audit.issues); // [{ code, severity, message, fix }, …]Modules
inclusive-kit/fields — Field factories
Each factory returns form-ready metadata: options (ordered with inclusive choices first), accessibility attributes, and a why string that explains the design decision so your team learns as they integrate.
import { genderField, pronounsField, honorificField, nameField } from "inclusive-kit/fields";
genderField({ locale: "en" | "es", allowSelfDescribe?: boolean, required?: boolean })
pronounsField({ locale, allowSelfDescribe? })
honorificField({ locale })
nameField({ locale, required? })All fields return:
id— stable HTML idoptions—{ value, label, group }[]— inclusive options firstpreferNotToSay— always present and enabledselfDescribe— configurablea11y—{ ariaLabel, hint, autocomplete, required }— alwaysrequired: falsefor sensitive fieldswhy— string explaining the inclusive design rationale
Gender field note: required is accepted as a parameter for API consistency but is always coerced to false. Gender must never be required.
inclusive-kit/validate — Assumption-free validators
import { validatePersonName, validateBirthDate } from "inclusive-kit/validate";
validatePersonName("Cher") // → { valid: true }
validatePersonName("María-José O'Neill") // → { valid: true }
validatePersonName("陳") // → { valid: true } — mononyms valid
validatePersonName("John123") // → { valid: false, reason: "contains-digits" }
validatePersonName("John123", { allowDigits: true }) // → { valid: true }
validateBirthDate("1990-06-15") // → { valid: true }
validateBirthDate("1920-01-01") // → { valid: true } — no upper-age exclusion
validateBirthDate("2099-01-01") // → { valid: false, reason: "future-date" }All validators return { valid: boolean, reason?: string, suggestion?: string } — machine-readable reason codes, never prose-only.
PersonName options:
| Option | Default | Description |
|---|---|---|
| allowEmoji | false | permit emoji in names |
| allowDigits | false | permit digits in names |
| maxLength | 200 | maximum character length |
inclusive-kit/text — Inclusive language analyzer
import { analyze, listRules } from "inclusive-kit/text";
analyze("Hi guys, please fill the form.", { locale: "en" })
// → {
// findings: [{
// term: "guys",
// matched: "guys",
// index: 3,
// category: "gender",
// severity: "medium",
// suggestions: ["everyone", "folks", "team", "all"],
// note: "'Guys' defaults to male; excludes women and non-binary people."
// }]
// }
// Filter by category
analyze(text, { locale: "en", categories: ["gender", "disability"] })
// List all rules for a locale
listRules("es") // → Rule[]Categories: gender · disability · age · ethnicity · exclusion
Severities: high · medium · low · info
Rules use whole-word, case-insensitive matching. The regex surface is sanitized — no injection vector.
inclusive-kit/audit — Form auditor
The auditor composes field knowledge + the text analyzer to score a form definition (0–100) and return actionable issues.
import { auditForm } from "inclusive-kit/audit";
const result = auditForm({
fields: [
{
id: "gender",
type: "select",
label: "Gender",
options: ["Male", "Female"],
hasPreferNotToSay: false,
required: true,
},
],
locale: "en", // default: "en"
});
result.score // e.g. 25
result.issues // [{ fieldIndex, fieldId, code, severity, message, fix }]Issue codes:
| Code | Severity | What it detects |
|---|---|---|
| binary-gender | high | Only Male/Female options |
| missing-prefer-not-to-say | medium | No "prefer not to say" on sensitive fields |
| required-sensitive-field | high | Gender or pronouns marked as required |
| name-split | high | Separate first-name + last-name fields |
| label-language | varies | Non-inclusive text in field labels (runs analyze()) |
| required-honorific | medium | Title/honorific marked as required |
Locales
Currently supported: "en" (English) and "es" (Spanish). Locale packs are tree-shaken when using subpath imports (inclusive-kit/fields, inclusive-kit/text) — unused locales are not included in your bundle.
Tree-shaking
Use subpath imports to load only what you need:
// Only loads the fields module (~4 kB)
import { genderField } from "inclusive-kit/fields";
// Only loads the text analyzer + rule pack for es (~9 kB)
import { analyze } from "inclusive-kit/text";Bundle size
| Entry | Gzip |
|---|---|
| inclusive-kit (full) | ~6 kB |
| inclusive-kit/fields | ~4 kB |
| inclusive-kit/validate | < 1 kB |
| inclusive-kit/text | ~3 kB (+ rule packs) |
| inclusive-kit/audit | ~1 kB (+ text) |
TypeScript
Full types included. Minimum TypeScript version: 5.0.
Roadmap (v2)
- CLI:
npx inclusive-kit audit form.json - React bindings:
useGenderField(),useAuditForm() - More locales:
pt,fr - ESLint plugin wrapping
text.analyze - More rule categories:
socioeconomic,religion
Contributing
See CODE_OF_CONDUCT.md. PRs welcome — especially new locale rules and additional field types.
License
MIT © Eduardo Salinas
