├── .all-contributorsrc ├── .changeset ├── README.md └── config.json ├── .codesandbox └── ci.json ├── .eslintrc.js ├── .github ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── 1.Bug-report.md │ ├── 2.Feature-request.md │ └── config.yml └── workflows │ ├── ci.yml │ ├── release.yml │ └── stale.yml ├── .gitignore ├── .kodiak.toml ├── .nvmrc ├── .prettierrc ├── .vscode └── settings.json ├── LICENSE ├── MIGRATING-v2.md ├── README.md ├── SECURITY.md ├── app ├── .gitignore ├── README.md ├── next-env.d.ts ├── package.json ├── pages │ ├── _app.js │ ├── basic.js │ ├── index.tsx │ └── sign-in.js ├── styles │ └── globals.css └── tsconfig.json ├── docs ├── 3rd-party-bindings.md ├── api │ ├── connect.md │ ├── errormessage.md │ ├── fastfield.md │ ├── field.md │ ├── fieldarray.md │ ├── form.md │ ├── formik.md │ ├── useField.md │ ├── useFormik.md │ ├── useFormikContext.md │ ├── utils.md │ └── withFormik.md ├── examples.md ├── examples │ ├── async-submission.md │ ├── basic.md │ ├── checkboxes.md │ ├── dependent-fields-async-api-request.md │ ├── dependent-fields.md │ ├── field-arrays.md │ ├── instant-feedback.md │ ├── more-examples.md │ ├── radio-group.md │ ├── typescript.md │ └── with-material-ui.md ├── guides │ ├── arrays.md │ ├── form-submission.md │ ├── react-native.md │ ├── typescript.md │ └── validation.md ├── manifest.json ├── migrating-v2.md ├── overview.md ├── resources.md └── tutorial.md ├── e2e └── basic.test.ts ├── examples ├── AsyncValidation.js ├── CombinedValidations.js ├── CustomInputs.js ├── DebouncedAutoSave.js ├── Debug.js ├── ErrorMessage.js ├── FastField.js ├── MultistepWizard.js ├── RoutedMultistepWizard.js ├── RoutedMultistepWizard2.js ├── SchemaValidation.js ├── SyncValidation.js ├── ValidateFieldWithSchema.js ├── async-submission │ ├── README.md │ ├── index.js │ └── package.json ├── basic-typescript │ ├── README.md │ ├── index.html │ ├── index.tsx │ ├── package.json │ └── tsconfig.json ├── basic │ ├── README.md │ ├── index.js │ └── package.json ├── checkboxes │ ├── README.md │ ├── index.js │ └── package.json ├── dependent-fields-async-api-request │ ├── README.md │ ├── index.js │ ├── package.json │ └── styles.css ├── dependent-fields │ ├── README.md │ ├── index.js │ ├── package.json │ └── styles.css ├── field-arrays │ ├── README.md │ ├── index.js │ └── package.json ├── field-level-validation │ ├── README.md │ ├── index.js │ └── package.json ├── instant-feedback │ ├── README.md │ ├── index.js │ ├── package.json │ └── styles.css ├── radio-group │ ├── README.md │ ├── index.js │ └── package.json ├── with-material-ui │ ├── README.md │ ├── index.js │ └── package.json └── withFormik.js ├── package.json ├── packages ├── formik-native │ ├── .gitignore │ ├── CHANGELOG.md │ ├── CONTRIBUTING.md │ ├── README.md │ ├── package.json │ ├── src │ │ └── index.ts │ ├── test │ │ └── blah.test.ts │ └── tsconfig.build.json └── formik │ ├── .gitignore │ ├── CHANGELOG.md │ ├── MIGRATING-v2.md │ ├── README.md │ ├── package.json │ ├── src │ ├── ErrorMessage.tsx │ ├── FastField.tsx │ ├── Field.tsx │ ├── FieldArray.tsx │ ├── Form.tsx │ ├── Formik.tsx │ ├── FormikContext.tsx │ ├── connect.tsx │ ├── index.tsx │ ├── types.tsx │ ├── utils.ts │ └── withFormik.tsx │ ├── test │ ├── ErrorMessage.test.tsx │ ├── Field.test.tsx │ ├── FieldArray.test.tsx │ ├── Formik.test.tsx │ ├── setupTests.ts │ ├── testHelpers.ts │ ├── tsconfig.json │ ├── types.test.tsx │ ├── utils.test.tsx │ ├── withFormik.test.tsx │ └── yupHelpers.test.ts │ ├── tsconfig.build.json │ └── types │ ├── global.d.ts │ └── index.d.ts ├── playwright.config.ts ├── scripts ├── benchmark.tsx ├── btag.sh └── retag.sh ├── tsconfig.base.json ├── tsconfig.json ├── turbo.json ├── website ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .prettierignore ├── README.md ├── next-env.d.ts ├── next.config.js ├── package.json ├── postcss.config.js ├── public │ ├── images │ │ ├── blog │ │ │ ├── algolia-docsearch-screenshot.png │ │ │ ├── docusaurus-v1-vs-v2-nav.mp4 │ │ │ ├── formik-landing-page-screenshot.png │ │ │ ├── formik-mdx-docs-screenshot.png │ │ │ └── notion-cms-screenshot.png │ │ ├── favicon.png │ │ ├── formik-mark.svg │ │ ├── formik-og.png │ │ ├── formik-twitter.png │ │ ├── formik.png │ │ ├── formik.svg │ │ ├── forms-bg.svg │ │ ├── hero6.png │ │ ├── logo-white.png │ │ ├── logos │ │ │ ├── airbnb.svg │ │ │ ├── army.svg │ │ │ ├── artsy.png │ │ │ ├── authdog.svg │ │ │ ├── benchmark-uae.svg │ │ │ ├── booking.svg │ │ │ ├── brightwheel.svg │ │ │ ├── campusjaeger.png │ │ │ ├── capsule.svg │ │ │ ├── cargurus.svg │ │ │ ├── docker.svg │ │ │ ├── egghead.svg │ │ │ ├── extendi.svg │ │ │ ├── frameio.png │ │ │ ├── gitconnected-logo.png │ │ │ ├── gremlin.svg │ │ │ ├── gusto.svg │ │ │ ├── letgo-logo.png │ │ │ ├── lyft.svg │ │ │ ├── nasa.svg │ │ │ ├── nasdaq.svg │ │ │ ├── noaa.svg │ │ │ ├── nokia.svg │ │ │ ├── opentable.svg │ │ │ ├── palmer.svg │ │ │ ├── postmates.svg │ │ │ ├── priceline.png │ │ │ ├── pwc.svg │ │ │ ├── restaurant365.svg │ │ │ ├── rvshare.svg │ │ │ ├── sony.svg │ │ │ ├── state-street.png │ │ │ ├── stripe.svg │ │ │ ├── swissdev-devops-jobs.svg │ │ │ ├── techjobsbe.svg │ │ │ ├── ubidots.svg │ │ │ ├── viacom.svg │ │ │ ├── walmart.svg │ │ │ ├── wayfair.svg │ │ │ └── zauberware-logo.svg │ │ ├── oss_logo.png │ │ ├── palmer.svg │ │ └── pattern.png │ ├── robots.txt │ └── twemoji │ │ ├── 1f600.svg │ │ ├── 1f615.svg │ │ ├── 1f62d.svg │ │ └── 1f929.svg ├── scripts │ └── build-sitemap.js ├── src │ ├── blog │ │ ├── formik-3-alpha.md │ │ └── new-docs.md │ ├── components │ │ ├── ArrowRight.tsx │ │ ├── Banner.tsx │ │ ├── Container.tsx │ │ ├── DocsPageFooter.tsx │ │ ├── ExternalLink.tsx │ │ ├── Footer.tsx │ │ ├── FormiumLogo.tsx │ │ ├── Highlight2.tsx │ │ ├── LayoutDocs.tsx │ │ ├── Logo.tsx │ │ ├── MDXComponents.tsx │ │ ├── Nav.tsx │ │ ├── ReactionForm.tsx │ │ ├── Search.tsx │ │ ├── Seo.tsx │ │ ├── Sidebar.tsx │ │ ├── SidebarCategory.tsx │ │ ├── SidebarHeading.tsx │ │ ├── SidebarMobile.tsx │ │ ├── SidebarNavLink.tsx │ │ ├── SidebarPost.tsx │ │ ├── Sticky.tsx │ │ ├── TWButton.tsx │ │ ├── Toc.module.css │ │ ├── Toc.tsx │ │ ├── addRouterEvents.tsx │ │ ├── clients │ │ │ ├── Client.tsx │ │ │ ├── ClientsMarquee.tsx │ │ │ └── Filters.tsx │ │ ├── forwardRefWithAs.tsx │ │ ├── markdown.module.css │ │ ├── useBoolean.tsx │ │ ├── useClipboard.tsx │ │ ├── useIsMobile.tsx │ │ ├── useOverScroll.tsx │ │ ├── useTocHighlight.tsx │ │ └── utils │ │ │ └── throttle.ts │ ├── index.d.ts │ ├── lib │ │ ├── blog │ │ │ └── mdxUtils.ts │ │ ├── docs │ │ │ ├── config.ts │ │ │ ├── findRouteByPath.tsx │ │ │ ├── md-loader.js │ │ │ ├── page.tsx │ │ │ ├── rehype-docs.js │ │ │ ├── remark-paragraph-alerts.js │ │ │ ├── remark-plugins.js │ │ │ └── utils.ts │ │ ├── fs-utils.tsx │ │ ├── get-route-context.tsx │ │ ├── github │ │ │ ├── api.tsx │ │ │ ├── constants.tsx │ │ │ └── raw.tsx │ │ └── types.tsx │ ├── manifests │ │ ├── getManifest.ts │ │ ├── manifest-1.3.0.json │ │ ├── manifest-2.1.4.json │ │ └── manifest.json │ ├── pages │ │ ├── _app.js │ │ ├── _document.js │ │ ├── blog │ │ │ ├── [slug].tsx │ │ │ └── index.tsx │ │ ├── docs │ │ │ └── [...slug].tsx │ │ ├── index.tsx │ │ └── users.tsx │ ├── siteConfig.tsx │ ├── styles │ │ └── index.css │ └── users.ts ├── tailwind.config.js └── tsconfig.json └── yarn.lock /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/master/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@1.3.0/schema.json", 3 | "changelog": ["@changesets/changelog-github", { "repo": "formium/formik" }], 4 | "commit": false, 5 | "linked": [], 6 | "access": "public", 7 | "baseBranch": "main", 8 | "updateInternalDependencies": "patch", 9 | "ignore": [] 10 | } 11 | -------------------------------------------------------------------------------- /.codesandbox/ci.json: -------------------------------------------------------------------------------- 1 | { 2 | "buildCommand": "build:codesandbox", 3 | "node": "18", 4 | "packages": ["packages/formik", "packages/formik-native"], 5 | "sandboxes": ["n4sgkx"] 6 | } 7 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: [ 3 | 'react-app', 4 | 'prettier/@typescript-eslint', 5 | 'plugin:prettier/recommended', 6 | ], 7 | settings: { 8 | react: { 9 | version: 'detect', 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Learn how to add code owners here: 2 | # https://help.github.com/en/articles/about-code-owners 3 | 4 | * @jaredpalmer @quantizor 5 | /docs/ @jaredpalmer @quantizor 6 | /examples/ @jaredpalmer @quantizor -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [jaredpalmer] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: formik 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1.Bug-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report for Formik / examples 4 | title: '' 5 | labels: 'Type: Bug' 6 | assignees: '' 7 | --- 8 | 9 | ## Bug report 10 | 11 | ### Current Behavior 12 | 13 | 14 | 15 | ### Expected behavior 16 | 17 | 18 | 19 | ### Reproducible example 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ### Suggested solution(s) 28 | 29 | 30 | 31 | ### Additional context 32 | 33 | 34 | 35 | ### Your environment 36 | 37 | 38 | 39 | | Software | Version(s) | 40 | | ---------------- | ---------- | 41 | | Formik | 42 | | React | 43 | | TypeScript | 44 | | Browser | 45 | | npm/Yarn | 46 | | Operating System | 47 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2.Feature-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Request a new feature for Formik 4 | title: '' 5 | labels: 'Type: Feature Request' 6 | assignees: '' 7 | --- 8 | 9 | ## Feature request 10 | 11 | ### Current Behavior 12 | 13 | 14 | 15 | ### Desired Behavior 16 | 17 | 18 | 19 | ### Suggested Solution 20 | 21 | 22 | 23 | 24 | 25 | ### Who does this impact? Who is this for? 26 | 27 | 28 | 29 | ### Describe alternatives you've considered 30 | 31 | 32 | 33 | ### Additional context 34 | 35 | 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask a question 4 | url: https://github.com/formium/formik/discussions 5 | about: Ask questions and discuss with other community members 6 | - name: Join the Discord server 7 | url: https://discord.gg/pJSg287 8 | about: Chat with other community members in real-time 9 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - next 7 | jobs: 8 | release: 9 | runs-on: ubuntu-latest 10 | if: github.repository == 'jaredpalmer/formik' 11 | steps: 12 | - uses: actions/checkout@v4 13 | with: 14 | fetch-depth: 0 15 | 16 | - uses: actions/setup-node@v4 17 | with: 18 | cache: yarn 19 | node-version-file: .nvmrc 20 | 21 | - name: Install Dependencies 22 | run: yarn install 23 | 24 | - name: Create Release Pull Request or Publish to npm 25 | uses: changesets/action@1.4.8 26 | with: 27 | publish: yarn release 28 | env: 29 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 31 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: "Close stale issues/prs" 2 | on: 3 | schedule: 4 | - cron: "1 0 * * *" 5 | 6 | jobs: 7 | stale: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/stale@v9 11 | with: 12 | repo-token: ${{ secrets.GITHUB_TOKEN }} 13 | days-before-stale: 30 14 | days-before-close: 60 15 | stale-issue-label: "stale" 16 | stale-pr-label: "stale" 17 | stale-pr-message: "This pull request is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 60 days" 18 | stale-issue-message: "This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 60 days" 19 | any-of-labels: "Resolution: Duplicate,Resolution: Invalid,Resolution: Support Redirect,Resolution: Unsolved,Resolution: User Land,Resolution: Wontfix,Resolution: Workaround,Status: Author Feedback,Status: Needs More Information" 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | compiled 3 | *.log 4 | coverage 5 | .DS_Store 6 | next.d.ts 7 | legacy.d.ts 8 | .idea 9 | *.orig 10 | output.txt 11 | 12 | node_modules 13 | package-lock.json 14 | yarn.lock 15 | !/docs/yarn.lock 16 | !/yarn.lock 17 | 18 | website/translated_docs 19 | website/build 20 | !website/yarn.lock 21 | website/node_modules 22 | website/i18n 23 | !website2/yarn.lock 24 | .env 25 | .vercel 26 | /test-results/ 27 | /playwright-report/ 28 | /playwright/.cache/ -------------------------------------------------------------------------------- /.kodiak.toml: -------------------------------------------------------------------------------- 1 | # .kodiak.toml 2 | version = 1 3 | 4 | [merge] 5 | automerge_label = "automerge" 6 | require_automerge_label = false 7 | method = "squash" 8 | delete_branch_on_merge = true 9 | optimistic_updates = true 10 | prioritize_ready_to_merge = true 11 | notify_on_conflict = false 12 | 13 | [merge.message] 14 | title = "pull_request_title" 15 | body = "pull_request_body" 16 | include_pr_number = true 17 | body_type = "markdown" 18 | strip_html_comments = true -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v18 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "trailingComma": "es5", 4 | "semi": true, 5 | "singleQuote": true, 6 | "arrowParens": "avoid" 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "node_modules/typescript/lib", 3 | "editor.formatOnSave": false, 4 | "editor.codeActionsOnSave": { 5 | "source.fixAll.eslint": "explicit" 6 | }, 7 | } 8 | -------------------------------------------------------------------------------- /MIGRATING-v2.md: -------------------------------------------------------------------------------- 1 | ./packages/formik/MIGRATING-v2.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ./packages/formik/README.md -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | ------------------ | 7 | | 2.x.x | :white_check_mark: | 8 | | 1.5.x | :white_check_mark: | 9 | | <= 1.4 | :x: | 10 | 11 | ## Reporting a Vulnerability 12 | 13 | Send a Twitter DM to [@jaredpalmer](http://twitter.com/@jaredpalmer) or an email to security@jaredpalmer.com 14 | 15 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | -------------------------------------------------------------------------------- /app/README.md: -------------------------------------------------------------------------------- 1 | # Formik Integration Test App 2 | 3 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 4 | -------------------------------------------------------------------------------- /app/next-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | 4 | // NOTE: This file should not be edited 5 | // see https://nextjs.org/docs/basic-features/typescript for more information. 6 | -------------------------------------------------------------------------------- /app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start" 9 | }, 10 | "dependencies": { 11 | "formik": "latest", 12 | "next": "^12.0.0", 13 | "react": "^17.0.1", 14 | "react-dom": "^17.0.1", 15 | "yup": "^0.29.3" 16 | }, 17 | "devDependencies": { 18 | "typescript": "^4.0.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/pages/_app.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import '../styles/globals.css'; 3 | 4 | function MyApp({ Component, pageProps }) { 5 | return ; 6 | } 7 | 8 | export default MyApp; 9 | -------------------------------------------------------------------------------- /app/pages/basic.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Formik, Field, Form, ErrorMessage } from 'formik'; 3 | import * as Yup from 'yup'; 4 | 5 | const Basic = () => { 6 | const renderCount = React.useRef(0); 7 | return ( 8 |
9 |

Sign Up

10 | { 30 | await new Promise(r => setTimeout(r, 500)); 31 | alert(JSON.stringify(values, null, 2)); 32 | }} 33 | > 34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | 47 | 48 | 49 | 53 | 54 |
Checkbox Group
55 |
56 | 60 | 64 | 68 |
69 |
Picked
70 |
71 | 75 | 79 |
80 | 81 |
{renderCount.current++}
82 | 83 |
84 |
85 | ); 86 | }; 87 | 88 | export default Basic; 89 | -------------------------------------------------------------------------------- /app/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Link from 'next/link'; 3 | 4 | function Home() { 5 | return ( 6 |
7 |

Formik Examples and Fixtures

8 |
    9 |
  • 10 | Basic 11 |
  • 12 |
  • 13 | Async Submission 14 |
  • 15 |
16 | 38 |
39 | ); 40 | } 41 | 42 | export default Home; 43 | -------------------------------------------------------------------------------- /app/pages/sign-in.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react'; 2 | import { ErrorMessage, Field, Form, FormikProvider, useFormik } from 'formik'; 3 | import * as Yup from 'yup'; 4 | import { useRouter } from 'next/router'; 5 | 6 | const SignIn = () => { 7 | const router = useRouter(); 8 | const [errorLog, setErrorLog] = useState([]); 9 | 10 | const formik = useFormik({ 11 | validateOnMount: router.query.validateOnMount === 'true', 12 | validateOnBlur: router.query.validateOnBlur !== 'false', 13 | validateOnChange: router.query.validateOnChange !== 'false', 14 | initialValues: { username: '', password: '' }, 15 | validationSchema: Yup.object().shape({ 16 | username: Yup.string().required('Required'), 17 | password: Yup.string().required('Required'), 18 | }), 19 | onSubmit: async values => { 20 | await new Promise(r => setTimeout(r, 500)); 21 | alert(JSON.stringify(values, null, 2)); 22 | }, 23 | }); 24 | 25 | useEffect(() => { 26 | if (formik.errors.username && formik.touched.username) { 27 | setErrorLog(logs => [ 28 | ...logs, 29 | { 30 | name: 'username', 31 | value: formik.values.username, 32 | error: formik.errors.username, 33 | }, 34 | ]); 35 | } 36 | 37 | if (formik.errors.password && formik.touched.password) { 38 | setErrorLog(logs => [ 39 | ...logs, 40 | { 41 | name: 'password', 42 | value: formik.values.password, 43 | error: formik.errors.password, 44 | }, 45 | ]); 46 | } 47 | }, [ 48 | formik.values.username, 49 | formik.errors.username, 50 | formik.touched.username, 51 | formik.values.password, 52 | formik.errors.password, 53 | formik.touched.password, 54 | ]); 55 | 56 | return ( 57 |
58 |

Sign In

59 | 60 | 61 |
62 |
63 | 64 | 65 |
66 | 67 |
68 | 69 | 70 |
71 | 72 | 75 | 76 | 84 | 85 |
{JSON.stringify(errorLog, null, 2)}
86 |
87 |
88 |
89 | ); 90 | }; 91 | 92 | export default SignIn; 93 | -------------------------------------------------------------------------------- /app/styles/globals.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | padding: 0; 4 | margin: 0; 5 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, 6 | Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; 7 | } 8 | 9 | a { 10 | color: inherit; 11 | text-decoration: none; 12 | } 13 | 14 | * { 15 | box-sizing: border-box; 16 | } 17 | -------------------------------------------------------------------------------- /app/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "target": "es5", 5 | "lib": [ 6 | "dom", 7 | "dom.iterable", 8 | "esnext" 9 | ], 10 | "jsx": "preserve", 11 | "allowJs": true, 12 | "skipLibCheck": true, 13 | "forceConsistentCasingInFileNames": true, 14 | "noEmit": true, 15 | "moduleResolution": "node", 16 | "resolveJsonModule": true, 17 | "isolatedModules": true, 18 | "incremental": true 19 | }, 20 | "include": [ 21 | "next-env.d.ts", 22 | "**/*.ts", 23 | "**/*.tsx" 24 | ], 25 | "exclude": [ 26 | "node_modules" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /docs/3rd-party-bindings.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 3rd Party Bindings 3 | original_id: 3rd-party-bindings 4 | description: Use Formik with popular React component libraries like Material UI, Bootstrap, AntD, Semantic UI, and more. 5 | --- 6 | 7 | If you would like to use Formik with a UI framework, you'll probably want to create a wrapper component that binds Formik's props and callbacks. 8 | 9 | A few popular frameworks have open source wrappers readily available: 10 | 11 | - [Ant Design](https://github.com/jannikbuschke/formik-antd) 12 | - [Fabric](https://github.com/kmees/formik-office-ui-fabric-react) 13 | - [Material UI](https://github.com/stackworx/formik-material-ui) 14 | - [Reactstrap](https://github.com/shoaibkhan94/reactstrap-formik) 15 | - [Semantic UI 2.0](https://github.com/JT501/formik-semantic-ui-react) 16 | - [Semantic UI](https://github.com/turner-industries/formik-semantic-ui) 17 | -------------------------------------------------------------------------------- /docs/api/connect.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: connect 3 | title: connect() 4 | --- 5 | 6 | `connect()` is a higher-order component (HoC) that allows you to hook anything into Formik's context. It is used internally to construct `` and `
`, but you can use it to build out new components as your needs change. 7 | 8 | ## Type signature 9 | 10 | ```tsx 11 | connect(Comp: React.ComponentType }>) => React.ComponentType 12 | ``` 13 | 14 | ## Example 15 | 16 | ```jsx 17 | import React from 'react'; 18 | import { connect, getIn } from 'formik'; 19 | 20 | // This component renders an error message if a field has 21 | // an error and it's already been touched. 22 | const ErrorMessage = props => { 23 | // All FormikProps available on props.formik! 24 | const error = getIn(props.formik.errors, props.name); 25 | const touch = getIn(props.formik.touched, props.name); 26 | return touch && error ? error : null; 27 | }; 28 | 29 | export default connect(ErrorMessage); 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/api/form.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: form 3 | title: 4 | --- 5 | 6 | Form is a small wrapper around an HTML `` element that automatically hooks into Formik's `handleSubmit` and `handleReset`. All other props are passed directly through to the DOM node. 7 | 8 | ```jsx 9 | // so... 10 | 11 | 12 | // is identical to this... 13 | 14 | ``` 15 | -------------------------------------------------------------------------------- /docs/api/useFormik.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useFormik 3 | title: useFormik() 4 | --- 5 | 6 | `useFormik()` is a custom React hook that will return all Formik state and helpers directly. Despite its name, it is not meant for the majority of use cases. Internally, Formik uses `useFormik` to create the `` component (which renders a [React Context](https://reactjs.org/docs/context.html) Provider). If you are trying to access Formik state via context, use [useFormikContext](useFormikContext.md). Only use this hook if you are NOT using `` or `withFormik`. 7 | 8 | \*\* Be aware that ``, ``, ``, `connect()`, and `` will NOT work with `useFormik()` as they all require React Context. 9 | 10 | ## Use cases for `useFormik()` 11 | 12 | - You are Jared 13 | - You are modifying the returned value and creating a modified version of `` for your own consumption 14 | - You want to avoid using React Context (possibly for perf reasons) 15 | 16 | ## Example 17 | 18 | ```jsx 19 | import React from 'react'; 20 | import { useFormik } from 'formik'; 21 | 22 | const SignupForm = () => { 23 | const formik = useFormik({ 24 | initialValues: { 25 | firstName: '', 26 | lastName: '', 27 | email: '', 28 | }, 29 | onSubmit: values => { 30 | alert(JSON.stringify(values, null, 2)); 31 | }, 32 | }); 33 | return ( 34 | 35 | 36 | 43 | 44 | 51 | 52 | 59 | 60 | 61 | ); 62 | }; 63 | ``` 64 | 65 | --- 66 | 67 | # Reference 68 | 69 | ## `useFormik(config: FormikConfig): FormikProps` 70 | 71 | A custom React Hook that returns Formik states and helpers. It is used internally to create the `` component, but is exported for advanced use cases or for those people that do not want to use React Context. 72 | -------------------------------------------------------------------------------- /docs/api/useFormikContext.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: useFormikContext 3 | title: useFormikContext() 4 | --- 5 | 6 | `useFormikContext()` is a custom React hook that will return all Formik state and helpers via [React Context](https://reactjs.org/docs/context.html). 7 | 8 | ## Example 9 | 10 | Here's an example of a form that works similarly to Stripe's 2-factor verification form. As soon as you type a 6 digit number, the form will automatically submit (i.e. no enter keypress is needed). 11 | 12 | ```js 13 | import React from 'react'; 14 | import { useFormikContext, Formik, Form, Field } from 'formik'; 15 | 16 | const AutoSubmitToken = () => { 17 | // Grab values and submitForm from context 18 | const { values, submitForm } = useFormikContext(); 19 | React.useEffect(() => { 20 | // Submit the form imperatively as an effect as soon as form values.token are 6 digits long 21 | if (values.token.length === 6) { 22 | submitForm(); 23 | } 24 | }, [values, submitForm]); 25 | return null; 26 | }; 27 | 28 | const TwoFactorVerificationForm = () => ( 29 |
30 |

2-step Verification

31 |

Please enter the 6 digit code sent to your device

32 | { 35 | const errors = {}; 36 | if (values.token.length < 5) { 37 | errors.token = 'Invalid code. Too short.'; 38 | } 39 | return errors; 40 | }} 41 | onSubmit={(values, actions) => { 42 | setTimeout(() => { 43 | alert(JSON.stringify(values, null, 2)); 44 | actions.setSubmitting(false); 45 | }, 1000); 46 | }} 47 | > 48 |
49 | 50 | 51 | 52 |
53 |
54 | ); 55 | ``` 56 | 57 | --- 58 | 59 | # Reference 60 | 61 | ## `useFormikContext(): FormikProps` 62 | 63 | A custom React Hook that returns Formik states and helpers via React Context. Thus, this hook will only work if there is a parent Formik React Context from which it can pull from. If called without a parent context (i.e. a descendent of a `` component or `withFormik` higher-order component), you will get a warning in your console. 64 | -------------------------------------------------------------------------------- /docs/api/utils.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: utils 3 | title: Utils 4 | --- 5 | 6 | # Reference 7 | 8 | ## Exported Functions 9 | 10 | #### `getActiveElement(doc?: Document): Element | null` 11 | 12 | #### `getIn(obj: any, key: string | string[], def?: any, p?: number): any` 13 | 14 | #### `setIn(obj: any, path: string, value: any): any` 15 | 16 | #### `setNestedObjectValues(object: any, value: any, visited?: any, response?: any): T` 17 | 18 | #### `isEmptyArray: (value?: any) => boolean` 19 | 20 | #### `isFunction: (obj: any) => obj is Function` 21 | 22 | #### `isObject: (obj: any) => obj is Object` 23 | 24 | #### `isInteger: (obj: any) => boolean` 25 | 26 | #### `isString: (obj: any) => obj is string` 27 | 28 | #### `isNaN: (obj: any) => boolean` 29 | 30 | #### `isEmptyChildren: (children: any) => boolean` 31 | 32 | #### `isPromise: (value: any) => value is PromiseLike` 33 | 34 | #### `isInputEvent: (value: any) => value is React.SyntheticEvent` 35 | -------------------------------------------------------------------------------- /docs/examples.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: examples 3 | title: Examples 4 | description: Runnable examples of using Formik in React and React Native to create forms 5 | --- 6 | 7 | ## Dependent Fields 8 | 9 | Programmatically set the value of one field based on the current values of other fields. 10 | 11 | https://codesandbox.io/s/formik-v2x-dependent-fields-r0n0v 12 | 13 | ## Dependent Fields based on Async API Request 14 | 15 | In this example, one field's value is set by making an async API based on the current values of two other fields. 16 | 17 | https://codesandbox.io/s/formik-v2x-dependent-field-with-async-api-request-4yjrv 18 | -------------------------------------------------------------------------------- /docs/examples/async-submission.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Async Submission Example 3 | description: This example demonstrates how to use async/await to submit a Formik form. 4 | --- 5 | 6 | This example demonstrates how to use `async`/`await` to submit a Formik form. 7 | 8 |
9 | 16 |
17 | -------------------------------------------------------------------------------- /docs/examples/basic.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basic Example 3 | description: This example demonstrates how to use Formik in its most basic way. 4 | --- 5 | 6 | This example demonstrates how to use Formik in its most basic way. 7 | 8 |
9 | 16 |
17 | -------------------------------------------------------------------------------- /docs/examples/checkboxes.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Checkboxes Example 3 | description: This example demonstrates how to use Formik with a checkbox group. Given that the fields all share the same `name`, Formik will automagically bind them to a single array. 4 | --- 5 | 6 | This example demonstrates how to use Formik with a checkbox group. Given that the fields all share the same `name`, Formik will automagically bind them to a single array. 7 | 8 |
9 | 16 |
17 | -------------------------------------------------------------------------------- /docs/examples/dependent-fields-async-api-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dependent fields with an Async API Request Example 3 | description: This is an example of a complex dependent field in Formik v2. In this example, one field's value is set by making an asynchronous API request based on the current values of other fields. 4 | --- 5 | 6 | This is an example of a complex dependent field in Formik. In this example, one field's value is set by making an asynchronous API request based on the current values of other fields. 7 | 8 |
9 | 16 |
17 | -------------------------------------------------------------------------------- /docs/examples/dependent-fields.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dependent Fields Example 3 | description: This is an example of how to set the value of one field based on the current values of other fields in Formik. 4 | --- 5 | 6 | This is an example of how to set the value of one field based on the current values of other fields in Formik. 7 | 8 |
9 | 16 |
17 | -------------------------------------------------------------------------------- /docs/examples/field-arrays.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Field Arrays Example 3 | --- 4 | 5 | This example demonstrates how to work with array fields in Formik. 6 | 7 |
8 | 15 |
16 | -------------------------------------------------------------------------------- /docs/examples/instant-feedback.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Accessible Instant Feedback Example 3 | --- 4 | 5 | Instant feedback during typing can be extremely helpful in certain situations. For example, checking the validity (or availability) of a username shouldn't require the user to resubmit the form (multiple times). Providing instant feedback while users are typing can allow them to experiment more easily until they find valid input value (like a suitable username). Note: This isn't always optimal, use your judgement. 6 | 7 |
8 | 15 |
16 | -------------------------------------------------------------------------------- /docs/examples/more-examples.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: More Examples 3 | --- 4 | 5 | You can find additional examples in [`examples` folder of the Formik GitHub repository](https://github.com/formik/formik/tree/main/examples/). 6 | -------------------------------------------------------------------------------- /docs/examples/radio-group.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Radio Group Example 3 | description: This example demonstrates how to create a radio group with Formik. 4 | --- 5 | 6 | This example demonstrates how to create a radio group with Formik. 7 | 8 |
9 | 16 |
17 | -------------------------------------------------------------------------------- /docs/examples/typescript.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Basic TypeScript 3 | description: This example demonstrates how to use Formik in its most basic way with TypeScript. 4 | --- 5 | 6 | This example demonstrates how to use Formik in its most basic way with TypeScript. 7 | 8 |
9 | 16 |
17 | -------------------------------------------------------------------------------- /docs/examples/with-material-ui.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: with-material-ui 3 | title: Material UI 4 | --- 5 | 6 | Formik can be easily used/integrated with [Material UI](https://material-ui.com/), with just passing a few formik props to the respective Material UI Component props. Refer to the example below to get started. 7 | 8 |
9 | 16 |
17 | -------------------------------------------------------------------------------- /docs/guides/arrays.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: arrays 3 | title: Arrays and Nested Objects 4 | --- 5 | 6 | Formik has support for nested objects and arrays out of the box. These subjects are somewhat related because they both leverage the same syntax. 7 | 8 | ## Nested Objects 9 | 10 | The `name` props in Formik can use lodash-like dot paths to reference nested Formik values. This means that you do not need to flatten out your form's values anymore. 11 | 12 | ```jsx 13 | import React from 'react'; 14 | import { Formik, Form, Field } from 'formik'; 15 | 16 | export const NestedExample = () => ( 17 |
18 |

Social Profiles

19 | { 27 | // same shape as initial values 28 | console.log(values); 29 | }} 30 | > 31 |
32 | 33 | 34 | 35 | 36 |
37 |
38 | ); 39 | ``` 40 | 41 | ## Arrays 42 | 43 | Formik also has support for arrays and arrays of objects out of the box. Using lodash-like bracket syntax for `name` string you can quickly build fields for items in a list. 44 | 45 | ```jsx 46 | import React from 'react'; 47 | import { Formik, Form, Field } from 'formik'; 48 | 49 | export const BasicArrayExample = () => ( 50 |
51 |

Friends

52 | { 57 | // same shape as initial values 58 | console.log(values); 59 | }} 60 | > 61 |
62 | 63 | 64 | 65 | 66 |
67 |
68 | ); 69 | ``` 70 | 71 | For more information around manipulating (add/remove/etc) items in lists, see the API reference section on the `` component. 72 | 73 | ## Avoid nesting 74 | 75 | If you want to avoid this default behavior Formik also has support for it to have fields with dots. 76 | 77 | ```jsx 78 | import React from 'react'; 79 | import { Formik, Form, Field } from 'formik'; 80 | 81 | export const NestedExample = () => ( 82 |
83 |

Social Profiles

84 | { 89 | // same shape as initial values 90 | console.log(values); 91 | }} 92 | > 93 |
94 | 95 | 96 | 97 |
98 |
99 | ); 100 | ``` 101 | -------------------------------------------------------------------------------- /docs/guides/form-submission.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: form-submission 3 | title: Form Submission 4 | --- 5 | 6 | ## Submission Phases 7 | 8 | To submit a form in Formik, you need to somehow fire off the provided `handleSubmit(e)` or `submitForm` prop. When you call either of these methods, Formik will execute the following _(pseudo code)_ each time: 9 | 10 | ### Pre-submit 11 | 12 | - Touch all fields. `initialValues` are required and should always be specified. See [#445](https://github.com/jaredpalmer/formik/issues/445#issuecomment-366952762) 13 | - Set `isSubmitting` to `true` 14 | - Increment `submitCount` + 1 15 | 16 | ### Validation 17 | 18 | - Set `isValidating` to `true` 19 | - Run all field-level validations, `validate`, and `validationSchema` asynchronously and deeply merge results 20 | - Are there any errors? 21 | - Yes: Abort submission. Set `isValidating` to `false`, set `errors`, set `isSubmitting` to `false` 22 | - No: Set `isValidating` to `false`, proceed to "Submission" 23 | 24 | ### Submission 25 | 26 | - Proceed with running the submission handler (i.e. `onSubmit` or `handleSubmit`) 27 | - Did the submit handler return a promise? 28 | - Yes: Wait until it is resolved or rejected, then set `setSubmitting` to `false` 29 | - No: _Call `setSubmitting(false)`_ to finish the cycle 30 | 31 | ## Frequently Asked Questions 32 | 33 |
34 | How do I determine if my submission handler is executing? 35 | 36 | If `isValidating` is `false` and `isSubmitting` is `true`. 37 | 38 |
39 | 40 |
41 | Why does Formik touch all fields before submit? 42 | 43 | It is common practice to only show an input's errors in the UI if it has been visited (a.k.a "touched"). Before submitting a form, Formik touches all fields so that all errors that may have been hidden will now be visible. 44 | 45 |
46 | 47 |
48 | How do I protect against double submits? 49 | 50 | Disable whatever is triggering submission if `isSubmitting` is `true`. 51 | 52 |
53 | 54 |
55 | How do I know when my form is validating before submit? 56 | 57 | If `isValidating` is `true` and `isSubmitting` is `true`. 58 | 59 |
60 | 61 |
62 | Why does `isSubmitting` remain true after submission? 63 | 64 | If the submission handler returns a promise, make sure it is correctly resolved or rejected when called. 65 | 66 | If the submission handler does not return a promise, make sure `setSubmitting(false)` is called at the end of the handler. 67 | 68 |
69 | -------------------------------------------------------------------------------- /docs/guides/react-native.md: -------------------------------------------------------------------------------- 1 | --- 2 | id: react-native 3 | title: React Native 4 | --- 5 | 6 | **Formik is 100% compatible with React Native and React Native Web.** However, 7 | because of differences between ReactDOM's and React Native's handling of forms 8 | and text input, there are some differences to be aware of. This section will walk 9 | you through them and what we consider to be best practices. 10 | 11 | ### The gist 12 | 13 | Before going any further, here's a super minimal gist of how to use Formik with 14 | React Native that demonstrates the key differences: 15 | 16 | ```jsx 17 | // Formik x React Native example 18 | import React from 'react'; 19 | import { Button, TextInput, View } from 'react-native'; 20 | import { Formik } from 'formik'; 21 | 22 | export const MyReactNativeForm = props => ( 23 | console.log(values)} 26 | > 27 | {({ handleChange, handleBlur, handleSubmit, values }) => ( 28 | 29 | 34 | 45 | 46 | 47 | )} 48 | /> 49 | 50 | ); 51 | 52 | export default Username; 53 | -------------------------------------------------------------------------------- /examples/CombinedValidations.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Formik, Field, Form, ErrorMessage } from 'formik'; 3 | import * as Yup from 'yup'; 4 | import { Debug } from './Debug'; 5 | 6 | const Schema = Yup.object().shape({ 7 | email: Yup.string().required('This field is required'), 8 | }); 9 | 10 | // Async Validation 11 | const sleep = ms => new Promise(resolve => setTimeout(resolve, ms)); 12 | 13 | const validate = values => 14 | sleep(300).then(() => { 15 | return { 16 | zip: 'This field is required', 17 | }; 18 | }); 19 | 20 | const isRequired = message => value => (!!value ? undefined : message); 21 | 22 | const FieldLevelValidation = () => ( 23 |
24 |

Pick a username

25 | { 34 | sleep(500).then(() => { 35 | alert(JSON.stringify(values, null, 2)); 36 | }); 37 | }} 38 | render={({ 39 | errors, 40 | touched, 41 | setFieldValue, 42 | setFieldTouched, 43 | validateField, 44 | validateForm, 45 | }) => ( 46 |
47 | 48 |
49 | 55 | 56 |
57 |
58 |
59 | 65 | 66 |
67 |
68 |
69 | 75 | 76 |
77 |
78 | 79 | 80 | 81 | )} 82 | /> 83 |
84 | ); 85 | 86 | export default FieldLevelValidation; 87 | -------------------------------------------------------------------------------- /examples/CustomInputs.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Formik, Field, Form, ErrorMessage } from 'formik'; 3 | import * as Yup from 'yup'; 4 | import { Debug } from './Debug'; 5 | 6 | // By combining a vanilla