Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion website/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ node_modules
*.log
.DS_Store
.vercel
public/sitemap.xml
public/sitemap.xml
.source
138 changes: 138 additions & 0 deletions website/content/blog/formik-3-alpha.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
---
title: Formik 3 Alpha
date: 2020-10-27
published: true
slug: formik-3-alpha
authors:
- Jared Palmer
preview: |
Today, we cut the very first release of Formik v3 alpha. The reason for this blog post is that there is a small breaking change that we unfortunately have no way of warning you about like we usually do with deprecation notices due to its nature.
---

Today, we cut the very first release of Formik v3 alpha. You can install it with:

```jsx
npm install formik@next
```

The reason for this blog post is that there is a small breaking change that we unfortunately have no way of warning you about like we usually do with deprecation notices due to its nature.

---

But, before we get into the bad news, let's first share the good news:

## New `parse`, `format`, and `formatOnBlur` props!

The new alpha release contains new `parse` , `format`, and `formatOnBlur` props for `getFieldProps`, `<Field>`, and `useField()`. These props make it a lot easier to implement [input masking](https://css-tricks.com/input-masking/)—a technique where you alter the format of the raw value of an input to make it appear in a certain way to the user (e.g. like a phone number (917) 555-1234 or a text-based date 10/2020). For you TypeScript friends here's what's new:

```tsx
interface FieldConfig<V> {
// ...omitted for brevity

/**
* Function to parse raw input value before setting it to state
*/
parse?: (rawInput: string, name: string) => V;

/**
* Function to transform value passed to input
*/
format?: (value: V, name: string) => any;

/**
* Should Formik wait until the blur event before formatting input value?
* @default false
*/
formatOnBlur?: boolean;
}

// ...elsewhere...

const [field] = useField({ name: 'phone', parse: rawInput => ... })
<Field name="phone" parse={rawInput => ... } />
<input {...formikProps.getFieldProps({ name: 'phone', parse: rawInput => ... }) />
```

And here's a full example that uses the `[format-string-by-pattern](https://www.npmjs.com/package/format-string-by-pattern)` package to create various phone number input masks. Notice on the first input that even though you type 9999999999 the input's value (and Formik's internal value) is 999-999-9999. Neat!

[https://codesandbox.io/s/github/jaredpalmer/formik/tree/next/examples/format-string-by-pattern?fontsize=14&hidenavigation=1&theme=dark&file=/index.js](https://codesandbox.io/s/github/jaredpalmer/formik/tree/next/examples/format-string-by-pattern?fontsize=14&hidenavigation=1&theme=dark&file=/index.js)

**\*Pro Tip:** I'm all about making intuitive API's and so I'm aware that `parse` and `format` are hard to remember. The trick I've been using / saying in my head is as follows: "format" → sounds like "from" → "from Formik" → from Formik to input. Again, this is an alpha, so if it's too confusing, we'll rename these.\*

## A Breaking Change

To support this new behavior, we needed to make a breaking change to the way that `onChange` and `onBlur` handlers work when returned from `formikProps.getFieldProps()`, which subsequently impacts `useField()` and `Field` as well.

In the past, these `onChange` and `onBlur` methods were identical to `formikProps.handleChange` and `formikProps.handleBlur` (returned by `useFormik()` or by the render prop `<Formik>` or `withFormik`). However, as of 3.0.0-next.0, these methods behave differently, respectively.

When returned from `getFieldProps`, `useField`, or `<Field>`'s render prop, `onChange` and `onBlur` are now already scoped to the given field and can now accept either a React Synthetic event or an arbitrary value. They no longer can be curried like `handleChange` and `handleBlur` can.

### Some Examples

Here are some more concrete examples for you of what works and what doesn't work...

**Still works, but does not support `parse`, `format`, and `formatOnBlur`**

```tsx
export const MyReactNativeForm = props => (
<Formik
initialValues={{ email: '' }}
onSubmit={values => console.log(values)}
>
{({ handleChange, handleBlur, handleSubmit, values }) => (
<View>
<TextInput
onChangeText={handleChange('email')} // curried
onBlur={handleBlur('email')} // curried
value={values.email}
/>
<Button onPress={handleSubmit} title="Submit" />
</View>
)}
</Formik>
);
```

**No longer works**

```tsx
export const MyTextField = props => {
const [field] = useField(props);
const onChange = e => {
e.persist();
if (e.target.value === 'foo') {
// Using the curried version of onChange,
// effectively equivalent to setFieldValue() no longer works
field.onChange(props.name)('bar');
} else {
field.onChange(e);
}
};
return <input {...field} onChange={onChange} />;
};
```

**But instead you can just do this...**

```tsx
export const MyTextField = props => {
const [field] = useField(props);
const onChange = e => {
e.persist();
if (e.target.value === 'foo') {
// You can now just set the value
field.onChange('bar');
} else {
// Or pass an event
field.onChange(e);
}
};
return <input {...field} onChange={onChange} />;
};
```

Normally, this small change wouldn't cause a major version bump, but because we no longer know if you are currying the `onChange` method or are actually intending to set the string argument as a value we can't fire off a warning to save you from yourself. 🤷‍♂️

## What's next?

The primary goal of Formik v3 is to improve performance, ergonomics, and a11y, but also to recover from certain bets we made around React hooks that never happened (like context selectors). Unfortunately, to get where we want to go, there will be some more breaking changes and/or new components that will need to be introduced to the Formik family. The plan is to roll these out on the `next` branch over the next few weeks, argue about naming for a bit, and then decide either to split some of the existing components into their own packages (a la `prop-types`) and/or write codemods to automate the migration path. Either way, Formik is getting faster...A lot lot faster, which is something that's long overdue.
134 changes: 134 additions & 0 deletions website/content/blog/new-docs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
---
title: New Docs
date: 2020-06-30
published: true
slug: new-docs
preview: |
After a few weeks of work, I'm excited to finally release Formik's new documentation website. Formik was one of the earliest users of Facebook's [Docusaurus](https://docusaurus.io/) documentation framework. It worked great and, due to limited styling options, it helped ensure we stayed focused on the content and not on the looks. That being said, Docusaurus v1 has its shortcomings.
authors:
- Jared Palmer
---

After a few weeks of work, I'm excited to finally release Formik's new documentation website as well as its new domain at [https://formik.org](https://formik.org).

---

![/images/blog/formik-landing-page-screenshot.png](/images/blog/formik-landing-page-screenshot.png)

Formik was one of the earliest users of Facebook's [Docusaurus](https://docusaurus.io/) documentation framework. It worked great and, due to limited styling options, it helped ensure we stayed focused on the content and not on the looks.

That being said, Docusaurus v1 has its shortcomings. First, it is truly a static site generator. It spits out pure HTML. This is great for a lot of libraries and tools, but for something like Formik, which is a React package, the inability to run modern client-side JS became frustrating. Things like in-page playgrounds or editable code-blocks were not feasible.

When it came time to give the docs a much-needed refresh, I evaluated Gatsby and Docusaurus v2, but ultimately **decided to go with [Next.js](https://nextjs.org)**. Thanks to new features like `getStaticProps`, catch-all routes, and incremental static-site generation, the Formik docs now have solid foundation upon which we can innovate going forward.

## **tl;dr**

The Formik docs are built with:

- [Next.js](https://nextjs.org/) 9.4.x + MDX
- [Notion](https://notion.so) (for powering this blog post you're reading right now)
- [Tailwind CSS](https://tailwindcss.com)
- [Algolia DocSearch](https://docsearch.algolia.com/) v3 Alpha for search

_What follows in the rest of this post is a more detailed overview of Formik's documentation stack, some of the rationale behind it, and a few cool tidbits you might find interesting._

## [Next.js](https://nextjs.org/) 9.4

I chose Next.js over alternatives such as Gatsby and Docusaurus v2 for several reasons. The biggest factor in the decision is that I believe that **documentation is part of the product**. Since some of my forthcoming SaaS dashboard and marketing sites already use Next.js, staying within the Next.js universe meant all of the codebases would work the same way, even the open source ones. This reduces cognitive overhead and makes it easier to work across applications and share components.

### **Why not Gatsby?**

[Gatsby](https://gatsbyjs.org) is a React-based static site generator with a rich plugin and theme ecosystem. Its key value proposition is a single data graph powered by [GraphQL](https://graphql.org). With respect to documentation sites, Gatsby themes—groups of plugins, layouts, and components that child themes can then inherit— are extremely useful. Given the growing number of OSS projects [we are working on](https://github.com/formik), this was seriously compelling. However, I am fairly [convinced that GraphQL is still wildly overkill for documentation and most static document-driven websites](https://jaredpalmer.com/gatsby-vs-nextjs). And yes, I am fully aware that you don't technically _need_ to use GraphQL with Gatsby, but it is definitely its happy path.

### **Why not Docusaurus v2?**

As of writing, Docusaurus v2.0 is still in alpha. The new version fixes a lot of issues with v1.0 by allowing for client-side React, plugins, and even custom themes.

The biggest issue for me with Docusaurus 2 was/is its base theme.

For many projects, Facebook's new static CSS framework for docs called [Infima](https://facebookincubator.github.io/infima/) (which Docusaurus uses and is co-developed by the same team) is fine. However, there are few things about it that really bother me.

**Mobile Navigation feels awkward**

I consistently struggle to navigate every Docusaurus v2 website on mobile. I find the floating sub-navigation to be unintuitive compared to Docusaurus v1's sub-navbar. Here's a comparison video. v1 is on the left and v2 is on the right.

<video controls="true" loop="true"><source src="/images/blog/docusaurus-v1-vs-v2-nav.mp4" type="video/mp4" /></video>

**Infima CSS isn't easy to theme**

While Infima CSS is a complete CSS framework, it has somewhat limited theming options. Keeping the new Formik docs looking visually congruent with our enterprise SaaS app's design system also seemed like it would be challenging since we would need to bend/extend Infima CSS significantly.

**Lack of Community Themes**

Another great addition to Docusaurus in v2 is custom theming and [first-class theme component overriding (a.k.a "Swizzling")](https://v2.docusaurus.io/docs/using-themes/#swizzling-theme-components). If you've never heard of it before, component swizzling works similarly to Wordpress's template hierarchy for themes and plugins, but for React components. When you run `docusaurus swizzle <theme name> [component name]` , Docusaurus copies that component from the specified theme out of `node_modules` and into a local file in `src/theme/[component name]` . You can then make all the changes you want to that file and Docusaurus will use the "Swizzled" version instead of the base one when it builds your site.

The big downside to Swizzling is the same one that forever afflicts Wordpress child themes—it can make upgrading _much_ more complicated (especially when new features are added to the base theme). This problem is so prominent in fact, that the Docusaurus docs [currently warn **_against_** Swizzling until v2 reaches the beta stage](https://v2.docusaurus.io/docs/using-themes/#swizzling-theme-components):

> We would like to discourage swizzling of components until we've minimally reached a Beta stage. The components APIs have been changing rapidly and are likely to keep changing until we reach Beta. Stick with the default appearance for now if possible to save yourself some potential pain in future.

At this point, I spent a bit of time evaluating what it would take to write our own custom Docusaurus v2 theme for Formik, but ultimately decided against it because of the above warning. My rationale was that if I was going to go down that rabbit hole, I might as well just retain full control of the entire markdown processing pipeline with Next.js–and that's exactly what I did...

### MDX FTW

With a little bit of effort, Next.js can be great for documentation—with MDX being the secret sauce. However, getting it to feature-parity with Docusaurus will take considerable effort and is not for the faint of heart. That being said, I'm super happy with how the new docs work, how easy it is contribute to them, and the way the site looks.

![/images/blog/formik-mdx-docs-screenshot.png](/images/blog/formik-mdx-docs-screenshot.png)

Worth pointing out that Formik's new docs handle MDX slightly differently than most Next.js sites likely do. Instead of using the official `@next/mdx` plugin, I shamelessly stole Brent Vatne's [custom webpack loader](https://github.com/formik/formik/blob/master/website2/src/lib/docs/md-loader.js) from the [Expo.io](http://expo.io) docs which automagically extracts front-matter and injects a wrapper Layout component export in every .mdx file.

```tsx
const fm = require('gray-matter');

// Makes mdx in next.js much better by injecting necessary exports so that
// the docs are still readable on github
// (Shamelessly stolen from Expo.io docs)
// @see https://github.com/expo/expo/blob/master/docs/common/md-loader.js
module.exports = async function (src) {
const callback = this.async();
const { content, data } = fm(src);
const layout = data.layout || 'Docs';
const code =
`import { Layout${layout} } from 'components/Layout${layout}';
export const meta = ${JSON.stringify(data)};
export default ({ children, ...props }) => (
<Layout${layout} meta={meta} {...props}>{children}</Layout${layout}>
);
` + content;

return callback(null, code);
};
```

By default, this loader injects the `LayoutDocs.tsx` layout component as a wrapper, but additional layouts can be added whenever we need them. They can be specified on a per-page basis via `layout` frontmatter key.

### Notion-powered Blog with [Static Site Generation](https://github.com/vercel/next.js/issues/9524)

Instead of using a traditional CMS or MDX, this blog you're reading right now is actually powered by [Notion](https://notion.so) and Next.js's Static Site Generation feature. We keep posts in a table in a Notion API with relevant metadata and then map Notion's undocumented API to custom React components in [./src/pages/blog/[...slug].tsx](https://github.com/formik/formik/blob/master/website2/src/pages/blog/%5B...slug%5D.tsx) . The result is amazing and a fantastic writing experience. For a more detailed example of this setup and one that you can deploy immediately, go here: [https://notion-blog.now.sh/](https://notion-blog.now.sh/)

![/images/blog/notion-cms-screenshot.png](/images/blog/notion-cms-screenshot.png)

## [**Tailwind**](https://tailwindcss.com)

I've been a fan of Atomic CSS for many many years. Tailwind is the latest and perhaps greatest of all Atomic CSS frameworks. It's flexible, it's intuitive, it looks great, and nothing beats it perf-wise (cuz it's just CSS!). Thanks to Tailwind 1.4.x, we're able to purge all extraneous class with its new `purge` feature too.

## **[Algolia DocSearch](https://docsearch.algolia.com/) v3 Alpha**

I accidentally discovered the new version of docsearch.js while working on the docs and it's even better than I could have ever imagined. It has a cool omnibar and even keeps track of recent searches and favorites.

![/images/blog/algolia-docsearch-screenshot.png](/images/blog/algolia-docsearch-screenshot.png)

Overall, I'm pretty happy with the new docs site. For the first time in a while, I'm excited to write docs again. There's still a decent amount of features still missing, but I'm very happy with the end-user experience and the developer experience that this stack provides. Next.js gives us a great foundation for building more app-like features into the docs site. The first of these will be a brand new interactive tutorial as well as a new searchable example and boilerplate directory. As always, if you're interested helping out or diving deeper, the [full source code of the new docs is available on GitHub](https://github.com/formik/formik).

So with that, go poke around, but be gentle. If you find any bugs, [file an issue.](https://github.com/formik/formik/issues/new?template=Bug_report.md) With this new Notion-powered blog, I'll be posting a lot more often, so enter your email and slap that subscribe button in the footer to join the Formik mailing list.

-J

## September 2021 Update

Since writing this post, Notion now has a public API. However, we ultimately ended up switching to MDX for blog content as well.

The problem we ran into with Notion is that docs builds would fail on PRs made by external contributors without approval. This is because using Notion as a CMS requires a secret API token which Vercel rightfully does not allow access to for PR deployments made by developers from outside of an organization. This really isn't specific to Notion, but would be the same for any headless CMS used to power a blog on an OSS project. It made browsing Formik's issues difficult on GitHub, since every PR would fail out of the box. Furthermore, it's not an awesome experience for new contributors to see a red X even though they didn't do anything wrong.

At this point, we could have either moved the blog to its own repo or site, but we decided it was just easier to drop Notion for good ol' MDX and keep everything inside the codebase.

In addition to Notion's public API, Docusaurus v2 has updated and improved its mobile navigation. It's worth checking it out along with another project called [Nextra](https://nextra.vercel.app) which is like Docusaurus, but powered by Next.js. If I were to rewrite the Formik docs again today, I would likely fork `nextra-theme-docs`.
16 changes: 16 additions & 0 deletions website/content/docs/3rd-party-bindings.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: 3rd Party Bindings
original_id: 3rd-party-bindings
description: Use Formik with popular React component libraries like Material UI, Bootstrap, AntD, Semantic UI, and more.
---

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.

A few popular frameworks have open source wrappers readily available:

- [Ant Design](https://github.com/jannikbuschke/formik-antd)
- [Fabric](https://github.com/kmees/formik-office-ui-fabric-react)
- [Material UI](https://github.com/stackworx/formik-material-ui)
- [Reactstrap](https://github.com/shoaibkhan94/reactstrap-formik)
- [Semantic UI 2.0](https://github.com/JT501/formik-semantic-ui-react)
- [Semantic UI](https://github.com/turner-industries/formik-semantic-ui)
Loading