emGee Software Solutions Custom Database Applications

Share this

Web Technologies

The Magic of React-Based Multi-Step Forms

CSS-Tricks - Fri, 02/15/2019 - 07:20

One way to deal with long, complex forms is to break them up into multiple steps. You know, answer one set of questions, move on to another, then maybe another, and so on and so forth. We often refer to these as multi-step forms (for obvious reasons), but others also take to calling it a “wizard” form.

Multi-step forms can be a great idea! By only showing a few inputs on a screen at a time, the form may feel more digestible and prevent users from feeling overwhelmed by a sea of form fields. Although I haven’t looked it up, I’m willing to say no one enjoys completing a ginormous form — that’s where multiple steps can come in handy.

The problem is that multi-step forms — while reducing perceived complexity on the front end — can feel complex and overwhelming to develop. But, I’m here to tell you that it’s not only achievable, but relatively straightforward using React as the base. So, that’s what we’re going to build together today!

Here’s the final product:

See the Pen
React Simple Wizard Form
by Nathan Sebhastian (@nathansebhastian)
on CodePen.

Let’s build it!

The easiest way to create a multi-step form is to create a container form element that contains all the steps inside of it as components. Here’s a visual showing that container (<MasterForm/>), the components inside of it (<Step1/>, <Step2/>, <Step3/>) and the way states and props are passed between them.

<MasterForm/> serves as the container while three child components inside of it act as each step of the form.

Although it seems to be more complex than a regular form, a multi-step form still uses the same principles as a React form:

  • State is used for storing data and user inputs.
  • Component is used for writing methods and the interface.
  • Props are used for passing data and function into elements.

Instead of having one form component, we will have one parent component and three child components. In the diagram above, <MasterForm/> will send data and functions to the child components via props, and in turn, the child components will trigger a handleChange() function to set values in the state of <MasterForm/>. It’s one big happy family over here!

We'll need a function to move the form from one step to another as well, and we’ll get to that a little later.

The step child (get it?) components will receive props from the <MasterForm/> parent component for value and onChange props.

  • <Step1/> component will render an email address input
  • <Step2/> will render a username input
  • <Step3/> will render a password input and a submit button

<MasterForm/> will supply both data and function into child components, and child components will pass user inputs back to the parent using its props.

Creating the step (child) components

First, we’ll create the form’s child components. We’re keeping things pretty barebones for this example by only using one input per step, but each step could really be as complex as we’d like. Since the child components look almost similar between one another, I’m just gonna show one of them here. But be sure to take a look at the demo for the full code.

class Step1 extends React.Component { render() { if (this.props.currentStep !== 1) { // Prop: The current step return null } // The markup for the Step 1 UI return( <div className="form-group"> <label htmlFor="email">Email address</label> <input className="form-control" id="email" name="email" type="text" placeholder="Enter email" value={this.props.email} // Prop: The email input data onChange={this.props.handleChange} // Prop: Puts data into state /> </div> ) } }

Now we can put this child component into the form’s render() function and pass in the necessary props. Just like in React’s form documentation, we can still use handleChange() to put the user’s submitted data into state with setState(). A handleSubmit() function will run on form submit.

Next up, the parent component

Let’s make the parent component — which we’re all aware by now, we’re calling <MasterForm/> — and initialize its state and methods.

We’re using a currentStep state that will be initialized with a default value of 1, indicating the first step (<Step1/>) of the form. We’ll update the state as the form progresses to indicate the current step.

class MasterForm extends Component { constructor(props) { super(props) // Set the initial input values this.state = { currentStep: 1, // Default is Step 1 email: '', username: '', password: '', } // Bind the submission to handleChange() this.handleChange = this.handleChange.bind(this) } // Use the submitted data to set the state handleChange(event) { const {name, value} = event.target this.setState({ [name]: value }) } // Trigger an alert on form submission handleSubmit = (event) => { event.preventDefault() const { email, username, password } = this.state alert(`Your registration detail: \n Email: ${email} \n Username: ${username} \n Password: ${password}`) } // Render UI will go here... }

OK, that’s the baseline functionality we’re looking for. Next, we want to create the shell UI for the actual form add call the child components in it, including the required state props that will be passed from <MasterForm/> via handleChange().

render() { return ( <React.Fragment> <h1>A Wizard Form!</h1> <p>Step {this.state.currentStep} </p> <form onSubmit={this.handleSubmit}> // Render the form steps and pass in the required props <Step1 currentStep={this.state.currentStep} handleChange={this.handleChange} email={this.state.email} /> <Step2 currentStep={this.state.currentStep} handleChange={this.handleChange} username={this.state.username} /> <Step3 currentStep={this.state.currentStep} handleChange={this.handleChange} password={this.state.password} /> </form> </React.Fragment> ) } One step at a time

So far, we’ve allowed users to fill the form fields, but we've provided no actual way to proceed to the next step or head back to the previous one. That calls for next and previous functions that check if the current step has a previous or next step; and if it does, push the currentStep prop up or down accordingly.

class MasterForm extends Component { constructor(props) { super(props) // Bind new functions for next and previous this._next = this._next.bind(this) this._prev = this._prev.bind(this) } // Test current step with ternary // _next and _previous functions will be called on button click _next() { let currentStep = this.state.currentStep // If the current step is 1 or 2, then add one on "next" button click currentStep = currentStep >= 2? 3: currentStep + 1 this.setState({ currentStep: currentStep }) } _prev() { let currentStep = this.state.currentStep // If the current step is 2 or 3, then subtract one on "previous" button click currentStep = currentStep <= 1? 1: currentStep - 1 this.setState({ currentStep: currentStep }) } }

We’ll use a get function that will check whether the current step is 1 or 3. This is because we have three-step form. Of course, we can change these checks as more steps are added to the form. We also want to display the next and previous buttons only if there actually are next and previous steps to navigate to, respectively.

// The "next" and "previous" button functions get previousButton(){ let currentStep = this.state.currentStep; // If the current step is not 1, then render the "previous" button if(currentStep !==1){ return ( <button className="btn btn-secondary" type="button" onClick={this._prev}> Previous </button> ) } // ...else return nothing return null; } get nextButton(){ let currentStep = this.state.currentStep; // If the current step is not 3, then render the "next" button if(currentStep <3){ return ( <button className="btn btn-primary float-right" type="button" onClick={this._next}> Next </button> ) } // ...else render nothing return null; }

All that’s left is to render those buttons:

// Render "next" and "previous" buttons render(){ return( <form onSubmit={this.handleSubmit}> {/* ... other codes */} {this.previousButton} {this.nextButton} </form> ) } Congrats, you’re a form wizard! &#x1f9d9;

That was the last step in this multi-step tutorial on multi-step forms. Whoa, how meta! While we didn’t go deep into styling, hopefully this gives you a solid overview of how to go about making complex forms less… complex!

Here’s that final demo again so you can see all the code in it’s full and glorious context:

See the Pen
React Simple Wizard Form
by Nathan Sebhastian (@nathansebhastian)
on CodePen.

React was made for this sort of thing considering it makes use of states, property changes, reusable components and such. I know that React may seem like a high barrier to entry for some folks, but I’ve written a book that makes it a much lower hurdle. I hope you check it out!

The post The Magic of React-Based Multi-Step Forms appeared first on CSS-Tricks.

Categories: Web Technologies

The #StateOfCSS 2019 Survey

CSS-Tricks - Fri, 02/15/2019 - 07:19

You know about the State of JavaScript survey, where thousands upon thousands of developers were surveyed about all-things-JS, from frameworks to testing and many other things in between? Well, Sacha Greif has launched one focused entirely on CSS.

This is super timely given a lot of the content we and other sites have been posting lately centered around learning, complexity, changing roles, and more. Sacha captures it nicely:

This is especially interesting since it comes at a time where many are talking about a “Great Divide” between the “front” of the front-end (HTML, CSS) and the “back” of the front-end (JavaScript and its many frameworks and libraries). [...] [T]he survey will be a great chance to take a snapshot of the community as it currently exists, and see how this evolves over the next couple years.

Sounds like a good goal. Let's help by putting some responses in there!

Take Survey

Direct Link to ArticlePermalink

The post The #StateOfCSS 2019 Survey appeared first on CSS-Tricks.

Categories: Web Technologies

Getting to Grips with the Airtable API

CSS-Tricks - Thu, 02/14/2019 - 07:31

The Airtable web app is pretty neat. You can use it like a spreadsheet but it’s useful for all sorts of other things too. The neatest thing about it for me is that it has an API so that you can treat it like a database.

I’ve been thinking about making weekly notes for the different teams I work with at Gusto to read about what the design systems team is working on, things we've fixed, and any bugs we've encountered during that might impact other designers and engineers across our organization. I’ve spent a couple of hours thinking about how we might use Airtable to collect a whole bunch of data and then use its API to extract that info and show it in a web app.

Here’s an example of what we’ll end up building, which is basically a React web app that’s using Airtable as a nifty sorta CMS:

To get started, we have to head on over to the command line and run the following (but first make sure npm is installed):

npx create-react-app airtable-test

This will create a new directory called airtable-test which is where we’ll be making our little React app. If we run yarn start in the command line after that’s finished installing, then we’ll see the default page for the project:

And, if we open up src/App.js in that airtable-test directory, we can see how this page is being rendered with React:

import React, { Component } from 'react'; import logo from './logo.svg'; import './App.css'; class App extends Component { render() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit src/App.js and save to reload. </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </header> </div> ); } } export default App;

Now that we have React up and running, we can go ahead and install airtable in the command line which will let us interact with the Airtable API:

npm i airtable

Once we’ve done that, we’ll need to create an Airtable account and create a project. We should wind up with something like this spreadsheet:

Now we can then head to airtable.com/api and select our project so that is serves as data we're pulling from. In this case, I selected “Design Systems Projects” which you can see right at the bottom here:

This will send us to a handy docs website that gives us an incredibly easy to read API for our specific project! Scrolling down we’ll find our API key which we’ll need to access this data as well as a ton of examples that we can use to manipulate the data we get back:

Let's head back to App.js in our airtable-test directory, delete all the code in that file, and replace it with the following:

import React, { Component } from 'react'; import Airtable from 'airtable'; const base = new Airtable({ apiKey: 'XXXXXXXXXXX' }).base('XXXXXXXXXXX');

Make sure to replace those Xs with the details that you can see in that Airtable API doc we just opened. But now that we’ve done all the setup, we can finally get around to creating our interface by calling data from our spreadsheet.

In App.js we can start to construct the App component:

class App extends Component { constructor(props) { super(props); this.state = { records: [] }; } render() { return { <div className="App">Hello</div> } } } }

All this will do for now is setup the app’s state and then render “Hello” on the page. Next up, we’ll be add each record from Airtable to that state.

First thing that’s important to note below: in componentDidMount() we’ll be selecting Updates which is just a way of telling Airtable that we want the spreadsheet called Updates. Make sure that this name is the same name as the spreadsheet. We’ll also be looping through all the records, or rows, of our table in that function too:

class App extends Component { constructor(props) { super(props); this.state = { records: [] }; } componentDidMount() { base('Updates').select({view: 'Grid view'}) .eachPage( (records, fetchNextPage) => { this.setState({ records }); console.log(records); fetchNextPage(); } ); } render() { return ( <div className="App"> <div>Hello</div> </div> ); } }

fetchNextPage() is the Airtable API’s way of giving us the next record in our spreadsheet and it’s neat that it will keep going until there are no more records. Again, we’re not doing anything with that data yet; we only want to make sure everything is working correctly at this point.

Open up the console in DevTools and we should see something like this:

Array(4) [ {…}, {…}, {…}, {…} ]

And if we dive through each of the objects in this array, then we should find all the data from the spreadsheet! Doing this bit always feels like magic to me.

Anyway, next up we can update our render() function like so:

render() { return ( <div className="App"> {this.state.records.length > 0 ? ( this.state.records.map((record, index) => <div key={index}> <h2>{record.fields['Date']}</h2> {record.fields['UI Kit']} {record.fields['Component Library']} </div> ) ) : ( <p>Loading...</p> )} </div> </div> ); }

We’re going to be looping through the state that we setup earlier and then rendering the record.fields[] for each column in our spreadsheet. We have a Date, UI Kit, and Component Library column, and once we’ve updated our App.js with the code above, we should see all the content from our spreadsheet!

It’s like magic! But why does this data look so weird? Well, it’s because I wanted to write Markdown in each cell, so now we’ll need to use a parser to convert that data into good ol’ fashioned HTML. First, we need to head back to the command line though:

npm i showdown

showdown will help us parse all that Markdown we’ve written in our Airtable spreadsheet. After installing it, we only need to import it at the top of our App.js file, like this:

import showdown from 'showdown'; const markdownConverter = new showdown.Converter();

After the componentDidMount() function, we can create another function that will create our HTML using showdown:

createHTML(markdown){ return( markdownConverter.makeHtml(markdown) ) }

It’s a little iffy, but it makes me feel like the code is a bit tidier this way. Now we can update our render() function:

render() { return ( <div className="App"> {this.state.records.length > 0 ? ( this.state.records.map((record, index) => <div key={index}> <h2>{new Date(record.fields['Date']).toISOString().split('T', 1)}</h2> <div dangerouslySetInnerHTML={{__html: this.createHTML(record.fields['UI Kit'])}} /> <div dangerouslySetInnerHTML={{__html: this.createHTML(record.fields['Component Library'])}} /> </div> ) ) : ( <p>Loading...</p> )} </div> ); }

We’re doing a couple of new things here: we’re using dangerouslySetInnerHTML in each div which, in turn, uses our createHTML function to convert the data from each column (specifically, the UI Kit and Component Library columns). We’re also converting the dates of each row into headings to make things a bit easier to read.

And with that we’re pretty much done! Here’s the final App.js:

import React, { Component } from 'react'; import Airtable from 'airtable'; import showdown from 'showdown'; const markdownConverter = new showdown.Converter(); const base = new Airtable({ apiKey: 'xxxxxxx' }).base('xxxxxxx'); class App extends Component { constructor(props) { super(props); this.state = { records: [] }; } componentDidMount() { base('Updates').select({view: 'Grid view'}) .eachPage( (records, fetchNextPage) => { this.setState({ records }); fetchNextPage(); } ); } createHTML(markdown){ return( markdownConverter.makeHtml(markdown) ) } render() { return ( <div className="App"> {this.state.records.length > 0 ? ( this.state.records.map((record, index) => <div key={index}> <h2>{new Date(record.fields['Date']).toISOString().split('T', 1)}</h2> <div dangerouslySetInnerHTML={{__html: this.createHTML(record.fields['UI Kit'])}} /> <div dangerouslySetInnerHTML={{__html: this.createHTML(record.fields['Component Library'])}} /> </div> ) ) : ( <p>Loading...</p> )} </div> ); } } export default App;

There’s still a ton of updates we could make to improve things. I took a first pass at styling, but we probably want to do things like improve the date format and maybe have some kind of indication as to which updates refer to which rows in the spreadsheet. Maybe we could even toggle showing which information to show depending on whether you’re a designer or engineer.

Anyway! I think this is a good start to getting to grips with the Airtable API and I’d love to hear about how you use it in the comments below.

The post Getting to Grips with the Airtable API appeared first on CSS-Tricks.

Categories: Web Technologies

Next.js 8 now supports serverless apps

InfoWorld JavaScript - Thu, 02/14/2019 - 07:30

Next.js, a framework for building server-rendered apps with JavaScript and the React UI library, adds serverless computing capabilities as part of its new Version 8.

Next.js 8 enables serverless deployment, in which applications are split into smaller parts, or lambdas, that let code be run on demand and scale automatically. In Next.js Version 8, each page in the pages directory becomes a serverless lambda. A low-level API is available for serverless deployment.

To read this article in full, please click here

Categories: Web Technologies

Use monday.com to manage and share projects all in one place

CSS-Tricks - Thu, 02/14/2019 - 07:29

(This is a sponsored post.)

We've talked quite a bit about project management and workflows around here at CSS-Tricks, not because it's the core of what we do as designers and developers, but because we all play a role in it as part of a team and because it impacts the quality of our work at the end of the day.

That's why having a good system in place is such a benefit both to us and to teams as a whole. Where can you find a system like that? You might want to start by looking at monday.com. Yes, it's a project management tool but it actually goes way beyond that. Where some other platforms out there stop at task lists, calendars, and milestones, monday.com does those plus team collaboration.

If you've ever felt out of the loop on a project, had a surprise change in scope, or even been curious what other folks on your team have been up to, that's where monday.com really shines. It's people-centric, giving you and others insight into activity across an entire project through news feeds, messaging, shared assets, clearly defined user roles, among any other things. It's what a healthy, transparent, and collaborative team environment looks like.

We've only scratched the surface here, but lucky for you, there's a free 14-day trial to check out everything that monday.com has to offer. Go for it!

Try it Now

Direct Link to ArticlePermalink

The post Use monday.com to manage and share projects all in one place appeared first on CSS-Tricks.

Categories: Web Technologies

Parcel bundler: Production builds and best practices

InfoWorld JavaScript - Thu, 02/14/2019 - 03:00

Over the past couple of weeks I’ve been playing around with Parcel, the zero-configuration web application bundler. I had a few issues with automagical dependency management, but for the most part Parcel has been a delight. This week we’ll look at building Parcel projects for production. I’ll cover some patterns and best practices for using Parcel in serious projects and outline some gotchas and issues to watch.

To read this article in full, please click here

(Insider Story)
Categories: Web Technologies

Pages