how-to-build-a-design-system-out-of-react-components

Jaye Hackett

One of the most exciting developments in design for me in the past few years was the launch of the GOV.UK design system. Of course, the real power of a design system comes from the community of designers who maintain it, but GOV.UK does so much right that it made me want to raise the bar on my own projects.

I wanted to make something that was:

  1. easily reused in any website or app by installing it as an npm package
  2. gives you a documented, public demo site on the web, friendly to non-developers
  3. lets you conveniently test the components

Here’s how I made it.

It’s theoretically quite easy to publish something to npm. You create an account on npmjs.com, run npm login and then run npm publish. Your current project directory will get packaged up and put on the web.

But there’s a few deceptive problems that crop up:

Modules containing JSX need to be transpiled first

I’d foolishly assumed that I could simply ship my untranspiled JSX code in my npm package, and leave it up to the app that consumed the package to do the transpilation and bundling.

This doesn’t work — a few syntax errors later, I’d integrated the rollup bundler. My config is as simple as I could make it:

// rollup.config.js 

export default {

input: "src/index.js",

output: {

file: "dist/bundle.js",

format: "cjs",

globals: { "styled-components": "styled" }

},

plugins: [

peerDepsExternal(),

autoExternal(),

resolve({

extensions: [

".js",

".jsx"

]

}),

images(),

babel({

exclude: "node_modules/**"

}),

],

}

The config is:

  • transpiling JSX into ordinary JavaScript with Babel
  • resolving image files (like .svgs) into base64 strings which can be embedded in the output
  • making sure that dependencies that the module needs, especially react, react-dom and styled-components don’t end up in the bundled code, to avoid bloat.

I experimented with using parcel (because I like zero-config solutions) and webpack first, but I found both frustrating. Rollup is designed with bundling libraries and packages in mind.

You can use an .npmignore file to keep the unneeded source files out of the published module.

Crucially, you also need to remember to change the "main" value in package.json to wherever the output bundle ends up. For instance:

"main": "dist/bundle.js"

When you import { Whatever } from "my-module" , this is the file you’re importing from, so it must match.

I don’t want to manually push to npm as well as to Github

Ideally, I would use CircleCI or some other continuous deployment server to run tests, build a bundle and push it to npm.

I experimented with using the semantic-release package to handle this for me, which looks for keywords in your commit messages to decide when and how to increment your version number and publish.

I eventually decided this was more trouble than it was worth and wrote a simple npm script to make sure that my tests and build run before publishing whenever I hit npm publish:

// package.json"scripts": {    

....

"prepare": "jest && rollup -c",

...

},

Publishing lots of components in one package

There are multiple patterns for exporting a large number of components. Scoped packages are one way. The pattern I decided on was destructured imports:

import { Button } from "my-design-system"

To make this work, I structured my files this way:

src/

|-- Button/

|-- Headline/

|-- Card/

|-- index.js

Every component has at least one named export (no defaults), and index.js looks like this:

// src/index.jsexport * from "./components/Button"

export * from "./components/Headline"

export * from "./components/Card"

...

There are a few approaches for doing this, but the most popular at the moment seems to be Storybook.

I found Storybook pretty easy to install for React, and it’s big range of add-ons are promising:

Some of the Storybook add-ons

In my npm scripts, I wrote an npm run dev that starts storybook and starts rollup watching for changes, so that the package is in an importable state if I decide to develop with it locally in a different app using npm link.

// package.json"scripts": {                           

"build": "rollup -c",

"dev": "rollup -cw & start-storybook",

"storybook": "start-storybook",

"build-storybook": "build-storybook",

},

I co-located my stories like this:

Button/

|--index.jsx

|--stories.jsx

The nature of a design system means that most components can get away with being stateless: they have predictable outputs based wholly on their props.

Any stateful logic will propably be in the apps that consume the design system.

Luckily, this means we can use Jest’s snapshot testing for the bulk of our testing needs.

Storybook has a wonderfully useful add-on called Storyshots which takes the already-written stories and uses them as the test cases for snapshots. No need to duplicate!

The config is very simple:

// .storybook/storyshots.test.jsimport initStoryshots from "@storybook/addon-storyshots"  

initStoryshots()

With that set up, I can run jest based on my Storybook stories.

eslint, and especially jsx-a11y are also useful to catch possible accessibility bugs. npm test is set up to do all this:

// package.json"scripts": {

...

"pretest": "eslint src/ --ext .jsx",

"test": "jest"

....

},

All of this was relatively painless compared to the challenge of developing the design system locally, using npm link.

npm link lets you hook up a local project on your computer as if it were a “real” package from the web.

Whenever I tried to consume my local package in an example React app, I got horrendous errors warning me of invalid hook calls, multiple versions of React and eventually multiple instances of styled-components running on the page.

This was all despite me excluding these libraries from my bundled code using Rollup’s externals feature.

It turned out that a bug in a recent version (5.0.0) of styled-components was to blame. Temporarily downgrading or migrating to another CSS-in-JS package entirely fixed it.

This isn’t an ideal fix, but it underscores the occasional difficulty of getting a good local development workflow, even when the end user experience is fine.

Once this styled-components issue is solved, I’ll make a blank, reusable boilerplate kit available here.

traits-of-a-build-and-deployment-pipeline

Organizations often encourage collaboration and transparency by promoting day-to-day activities like pairing, standups, and code reviews. While these activities are very important, we also find that a solid build and deployment pipeline can make all the difference between a well-meaning team hitting or just missing the target. That’s because working software provides a tangible focal point for collaboration and transparency across skill sets.

The best build and deployment pipelines allow stakeholders and the project team to engage together early and often to focus on the product more and the mechanics of the process less. Let’s look at what makes a solid build and deployment pipeline regardless of the technology stack.

No Thought Deployment

The best pipelines don’t require our teams to think about deploying. Instead, the team just decides if code is ready to be shared via a push to GitHub (or your favorite Git hosting service). The pipeline takes care of the rest.

Heroku and Netlify do this really well. When a Heroku or Netlify app is connected to a GitHub repository, you can configure them to deploy with each commit to any branch.
In some situations, purpose-built services like Heroku or Netlify aren’t an option. Clients use tools that serve infrastructure constraints or other demands. That’s ok. The same experience can be created with tools like Jenkins, Bamboo, and Azure DevOps Services.

If you’re not able to automatically deploy to production at the moment, targeting a pre-production environment is a great first step. It allows teams to see early the effects of changes integrated with those of their teammates. Product teams can interact and provide feedback on features they had otherwise been describing using lower fidelity techniques like wireframes, designs, or descriptions. Collaboration for the win!

Automated Data and Schema Transformations

You might ask how automated deployment is possible when it comes to data transformations, schema changes, or other stateful application data changes. These can all be worked out, I assure you. Schema migrations are a common and reliable mechanism built into most modern platforms, including .Net, PHP, Ruby, Node, etc.

For example, Knex.js allows you to craft migrations to create and alter tables for popular relational databases like MySQL, PostgreSQL, and Microsoft SQL Services. When included in the git repository, the commits provide a history of changes to schema and data transformations that correspond to dependent application code changes. These can follow the same pipeline to production as any other change to your system.

Of course, you might be concerned about tight dependencies between application code and data. Or maybe you’re worried about the performance impact of data transformations on large data sets. At times, it can be helpful to execute migrations and transformations offline or in the background. In order to do this, we need to distinguish between deploying code to an environment and releasing the functionality that code enables to users.

Decoupling deployment from release enables high-frequency deployments. This allows you to make features available (released) to some user groups before they are available across your user base. By building your application in this manner and moving data transformations offline, you can deploy and enable features early for users as their data is transformed. This brings to mind data partitioning techniques aligned with feature flags for progressive feature enablement.

For example, you may deploy new functionality and its corresponding data changes to production while disabling those features via feature flags. Via a scheduled task, background worker, or queuing, data and schema changes can be executed while normal activity continues on the system. Once the changes are available, the feature flag can be enabled for a set of users, and they see the new behavior. At no point was the system unavailable for them.

Collaboration Enabled

We’re always looking for ways to tighten feedback loops. Once code is merged, it’s too late to undo. While we agree with the authors of the book Accelerate that teams should roll forward with fixes rather than revert them, we’d love to avoid the need for fixes in the first place.

To do this, we look for pipelines that allow our teams to deploy (again, without thought) potential changes to the product. In development terms, this means deploying a pull request. By integrating automatic deployments into the natural source code collaboration tools, we make high fidelity collaboration and first-class confirmation of changes a natural part of development.

Out of the box, Heroku and Netlify both support this model of deploying pull requests automatically, which is wonderful! Continuous integration tools have long had the ability to build and, should you choose, deploy branch code. On the web, this becomes a little more tricky as you need to provide a unique URL for each instance. It can be done, but we like to rely on purpose-built services like Heroku and Netlify where we can.

Precooked and Ready to Run

We want the result of a build to create a deployable artifact. The form that the artifact takes isn’t really important. We have some projects for which CircleCI simply creates and stores a tarball or zip file after successfully building. For some, a Docker image is created and made available. For you, it may be an installer, such as Apple’s DMG format, Microsoft’s MSI, or one of the popular Linux formats. The goal is the same: produce a runnable artifact that can be deployed many times without change.

By building once and storing the deployable results, our deployments are faster, more reliable, and we can have more confidence in the artifact working in each environment. Speed and reliability create tight feedback loops and drive up confidence—two things we’re always trying to achieve.

Sparkbox works with organizations using varying processes, tools, and techniques. Over time, we have honed a set of tools that work exceptionally well. Above all, our goal is to be flexible while advocating for the practices that we see bringing success to projects. A build and deployment pipeline that encourages collaboration and transparency, without getting in the way, brings an irreplaceable heartbeat to successful projects.

how-to-build-a-remote-team

More and more companies are hiring their first remote team members and leading remote companies are open and friendly about sharing their experiences with them. There are services available to help your company to start working remotely.

More and more companies are starting to realize the benefits remote work brings and are considering hiring their first remote team members.

A lot of companies are already working remotely from the office

Communication between team members is often already happening in a virtual office even if people are sitting in the physical office.

Sometimes team members might be sitting next to each other, but still communicate through text messages or on a chat channel so as not to disturb others workflow. This way they can work through the messages when they have the time.

If your company is already mostly communicating virtually, switching to remote can be quite easy. You just stop coming to the office!

This is exactly what Marketgoo did – they started building their do-it-yourself SEO tool in the office and have been gradually moving remote. First, the marketing manager and then the whole development team started working remotely. When there were no people left in the office, they did the only reasonable thing – closed the office for good!

“Co-working spaces, coffee shops (our biz dev guy is a regular at Tim Horton’s!), working from the beach, home office, etc” answered Marketgoo’s marketing manager Larissa when I asked her about where their team mostly work from now that they don’t have an office anymore.

Marketgoo CEO shares some great feedback on how he feels about going fully remote:

“4 months after closing the office and I don’t miss it at all! I am way more productive when working on the go. Before, I was tied to do big stuff only at the desk. I adapt much better now to any situation or venue. Only con is that I feel like a hermit sometimes”

Feeling like a hermit is quite common as loneliness has been reported as one of the biggest struggles that comes with remote work.

Advice from remote companies

Remote companies who are the frontrunners of the change to remote work are usually very open and friendly about sharing their experiences.

Some leading remote companies have shared their advice on RemoteHub for companies planning to start working remotely.

GitLab, who is currently #1 most distributed team on RemoteHub with more than 250 cities across 51 countries and 60 time zones, says they have learned a lot about how to collaborate effectively and strengthen their culture while growing their remote team.

One of the leading remote companies Doist puts the emphasis on building a strong set of core values and uses them as a foundation to develop their remote culture.

They also recommend on choosing tools that will help your remote team stay connected and productive.

Doist is well-known in the remote circle by sharing their experiences as a team working remotely from 25 countries and building productivity tools like Todoist and Twist that are widely used by other remote companies.

As people are working from different places and often on different schedules, it’s even more important to be responsible for your work.

“First, we make sure people can and do take ownership of their work,” says Teamweek – a tool to plan your project timeline by a distributed company working across 10 countries.

They also emphasise the importance of honest communication and open discussions by expecting team members to share their plans, successes and failures, but they also keep the culture fun by sharing memes.

Services to help you build a remote team

As remote work becomes more and more popular, it is now possible to get some professional help to build a successful remote team.

Remote-how helps to get the most out of remote work by training the teams to work remotely. They’ve built a 6-week online program where industry-leading experts teach about how to build and lead effective distributed teams. There’s also a real live conference to help you build and scale a remote team.

If you’d like to meet some remote team leaders in person, there’s Running Remote conference that helps you to build and scale a remote team. The conference is packed with speakers from leading remote companies. They started the conference in “remote work paradise”, Bali in 2018 and their next conference is taking place in Austin, TX in the spring of 2019.

Start slowly

It probably might not be a good idea to close your office next Monday to have everyone working from wherever and see what happens. But if your company is working in a field where people are doing their most of their jobs on laptops and phones and you’re interested in flexibility and benefits remote work offers, you can gradually start converting your company to remote.

For a start, try to introduce a few days a week where your team works from home and gradually move to have more and more remote days over time.

build-your-first-real-time-app-in-node

Have you ever wondered how real-time apps like chat apps and online games are built? If you’ve never built one before, read this tutorial as I’m going to show you how to build a simple one using socket.io.

What are we going to build?

It’s a simple app with one button and a label below it. The label displays “Likes: X” (where x is the current number of likes). When the user clicks on the button, the number of likes increases by one.

We’re going to make it real time by showing users on the app how the number of likes increases as other users are clicking on the button. So you don’t need to reload the page to see the latest value.

Here’s how the app would look like:

You can get the source code of this project on GitHub.

Creating a new project

In a new folder, add package.json using npm init -y, and then install these three packages:

npm install express ejs socket.io

We’ll use ejs as the templating engine, and socket.io for making our app a real-time app.

Displaying a hello world page

As mentioned above, we’ll use ejs for rendering our views. So create index.ejs and add the following:




  
  Realtime like app


  Hello World!


Now let’s create our node server and serve the above file as the homepage.

So create node.js and add this:

const app = require('express')()
const path = require('path')

app.engine('html', require('ejs').renderFile)
app.set('view engine', 'html')

app.get('/', (req, res) => {
  res.render(path.join(__dirname   '/index.ejs'), null, (err, html) => {
    res.send(html)
  })
})

app.listen(3000, () => console.log('the app is running on localhost:3000'))

So we created a new server that runs on port 3000. When the user hits http://localhost:3000/ in the browser, we’ll render index.ejs and display it.

If you run the app using node index.js (or using nodemon if you want the app to restart automatically on changes) and open http://localhost:3000/, you should see “Hello World!” displayed.

Adding style.css

This isn’t a CSS tutorial, so let’s quickly add style.css in the root directory and fill it with this:

body {
  background: hsl(0, 50%, 80%);
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
  margin: 0;
  padding: 0;
}

button {
  background: hsl(0, 50%, 90%);
  border: none;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 150px;
  height: 150px;
  cursor: pointer;
  outline: none;
  box-shadow: 0 14px 28px hsla(0, 50%, 10%, 25%), 0 10px 10px hsla(0, 50%, 10%, 22%);
  transition: all 0.3s cubic-bezier(.25,.8,.25,1);
}

button:hover {
  box-shadow: 0 1px 3px hsla(0, 50%, 10%, 12%), 0 1px 2px hsla(0, 50%, 10%, 24%);
}

button:active {
  box-shadow: none;
}

svg path {
  fill: hsl(0, 30%, 30%);
}

.main {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
}

.likes {
  margin-top: 20px;
  color: hsl(0, 60%, 20%);
  font-weight: bold;
  font-family: sans-serif;
  text-transform: uppercase;
  font-size: 20px;
}

Now let’s tell our server about it so when we request it, it responds with this file.

Add this route in index.js (below the root route):

app.get('/style.css', (req, res) => {
  res.sendFile(path.join(__dirname   '/style.css'))
})

And then let’s use it in our index.ejs by adding this at the bottom of :


Displaying the button and the label

Open index.ejs and update it like this:




  
  Realtime like app
  


  

For this to work, we have to pass likes from the server when rendering the template.

So open index.js and update the root route like this:

let likes = 0

app.get('/', (req, res) => {
  res.render(path.join(__dirname   '/index.ejs'), { likes }, (err, html) => {
    res.send(html)
  })
})

Note how we defined likes above it.

To keep this example simple, we defined likes in the memory, which means its value will go back to 0 when the server restarts. Typically in real-world apps you’ll have your data stored in the database.

Incrementing likes by clicking on the button

To do so, we need to add a new route that increments likes and returns the new value. And then we’ll make a request to this endpoint from index.ejs, when the user clicks on the button.

Let’s define the route first, in index.js.

app.post('/like', (req, res) => {
  likes  
  res.json({ likes })
})

So it’s a POST endpoint at /like.

Now let’s listen for the button’s click event and send this request using the Fetch API.

Add the following above :


The app is now ready to be used but without showing the updated value in realtime. So if you open the app in multiple browser windows and try to update one, you won’t see the value updated in realtime on other browser windows until you reload them.

Making it a real-time app

Socket.io isn’t the only way to build real-time apps but it’s the most popular one. Not only that, but it’s also very good and easy to use.

We’ve already installed socket.io, so let’s initialize it.

But before I show you how, note that socket.io is composed of two parts:

  1. The server that we integrate with node http server.
  2. The client library that we use on the browser to communicate with the server part.

To initialize the server part, open index.js and update the top part like this:

const app = require('express')()
const http = require('http').createServer(app)
const path = require('path')
const io = require('socket.io')(http)

So we imported socket.io and passed it the http server object.

Now let’s use the http object to run the server instead of app.

http.listen(3000, () => console.log('the app is running on localhost:3000'))

With that, socket.io is initialized on the server!

When socket.io is initialized it exposes /socket.io/socket.io.js endpoint. This endpoint contains the JS file that we’ll use in the browser to connect with socket.io. (So it’s the socket.io’s client library.)

Go to index.ejs and include that file above the

After you add this, you should have the io object exposed globally on the browser (check that from the console).

To connect the browser to the server, just call io() and store the returned socket in a variable.

So put the following at the top of your , add this:

socket.on('likes:update', likes => {
  likesOutput.textContent = `Likes: ${likes}`
})

That's it! Now our app is completely a real-time app!

If your code is not working, compare it with the source code of this demo on GitHub to make sure you haven't forgotten anything.

If you’ve had an idea for a promising business, chances are, you’ve probably resorted to some sort of freelance site or had a friend with Illustrator draft up a couple concepts for you.

This would’ve been your first mistake. I want you to think of building a brand like going on a first date. If you’re desperate to make a good first impression (as you should be) then you’ve probably put your best outfit on your bed and swapped out your articles of clothing 10 different times to find the best combination.

Aha! You’ve found the perfect one! But it doesn’t stop there. You still have to be friendly, have good manners, LISTEN TO YOUR DATE, and tell a great story yourself!

A logo is only as good as the shirt you decided to wear.

For the purpose of this article, I’m going to walk you through how to build a lean startup brand from scratch by actually building a lean startup brand from scratch. The company I’m starting today is an all natural, vegan, organic, CBD dog treat that is made in the USA.

CBD pet products are popping up everywhere, becoming a highly competitive space, and that means branding is everything.

Let’s go ahead and get started.

1. Go Back to Your Story

When you first thought about building a brand around your venture, your first ideation session was likely focused around what you offer as a product or service. For example, if you’ve started a landscaping business, you’ve probably thought of a minimal grass logo with a green color palette. This is a really good way of blending in with every other landscaper in your area. Not exactly what we want to do here.

So what should you focus on instead of your product/service? Go back to the very beginning! Your personal story as a startup founder.

Where were you born?

How did your parents raise you and how did that impact your reason behind starting this venture?

Are you starting right out of school or have you been working at a corporate job for the past 25 years? How does that affect your reason behind starting this venture?

As you dig deeper to understand your personal life story, you will recognize the truth behind your motivation to start this business.

As much as I’d love to take a deep dive into my personal story behind starting a CBD dog treat company, it would take this article way over the word limit I’ve planned, so I’m going to leave this part up to you.

2. Set Your Brand Voice

Hopefully you’ve thought a lot about your personal story because now we need to take that story and highlight some keywords that will act as your brand voice. For my CBD dog treat company, I’ve come to the words: Loyal, Warm, and Confident.

CBD is still a pretty regulated industry, so using CBD in pet products has stirred up a bit of controversy. For these reasons, the brand needed to convey a warm homeyness in order to have consumers feel relaxed when interacting with the brand. The brand also needs to focus on doggy confidence as the end result, rather than the state of relaxation, in order to differentiate. Finally, loyalty leads our brand voice because I want the company to convey the reason that we have such an immense love for dogs in the first place: loyalty. I want our company to be loyal to our customers, I want our customers to be loyal to our company, and I want the dogs that we help to be loyal to their owners.

The easiest way to choose your brand voice is to just pull out a piece of scrap paper and write down every word that comes to mind when thinking about your story and your business. Honesty. Quality. Loyalty. Money. People. Family. Respect. Growth. Nothing is wrong here, but think about how those words are going to make your end consumers feel.

Once you have a solid list of words, go through them and pick three that best describe the vibe that you want your business to have.



3. Decide on a Company Name

The 5 biggest factors to consider when deciding on a name for your new company are how easy your name is to spell, how easy it is to remember, if it has room for expansion, if it’s available, and how it fits in with your brand voice.

Pick a name that is easy to spell. There are about a million stories of founders that chose names for their business and struggled to get traffic because their consumers didn’t remember how to spell it, let alone the effect it has on search engine rankings.

Pick a name that is easy to remember. Similarly to spelling, you don’t want to lose out on customers because they can’t remember what your name was. Make your name short and sweet, but unique.

Don’t limit your business from day one by picking a name that is limiting. Naming your business “Lug Nuts of Athens, Ohio” might be the perfect descriptor for your business now, but what happens when you realize that there is an opportunity for you to change brake pads? Or changing break pads in Cleveland, Ohio? Imagine if Jeff Bezos named his business “BooksOnline” instead of “Amazon”.

Is your name even available? The easiest way to do this is a quick google search followed by a domain name search. If you can’t get the “.com” domain for the name you have in mind, you should think about going back to the drawing board.

Based on my brand voice: Loyal, Warm, and Confident, a name that immediately came to mind was “Feel”. I thought it matched my brand voice pretty well and thought that there could be some clever marketing designed around pups that were “in their feels”.

Upon further research, there was already a CBD company called “Feals”, and I surely wasn’t going to get the domain name “feel.com” without reaching deep into my own pockets.

After going back to the drawing board, I realized I was missing out on a huge opportunity. People love puppies. Having my name involve the word “pup” would be easy to build a brand around and still evokes warm, friendly, and inviting emotions. Since we’re playing in a cannabis industry, I came up with the name “PupLeaf”. Unfortunately, the .com domain was already taken, so I tried “LeafPup”.

It was available! And I liked the sound of it better anyway.

http://www.webdesignernews.com/

Thank you. Check your inbox 🙂

Oops! Something went wrong while submitting the form. Try again.

4. Write Your Mission Statement

A mission statement is a staple for building internal culture and driving your future marketing materials. Having your brand voice in place should make the process of coming up with the perfect mission statement a lot easier.

My favorite mission statement example is “We believe in a world where people belong anywhere”. Can you guess the company behind it?

Airbnb.

Traveling can be intimidating, especially when traveling to places with radically different cultures. Airbnb wants to make us feel like we belong anywhere. It’s a powerful message that will appeal to a lot of people and the statement doubles as a backbone for their brand.

Airbnb's Brand

Everything you create for your business should tie into your mission statement and communicate your brand voice. Here are some other examples of world famous mission statements used to build powerful brands.

Amazon – “Our vision is to be Earth’s most customer-centric company; to build a place where people can come to find and discover anything they might want to buy online.”

Facebook – “To give people the power to build community and bring the world closer together.”

Google – “To organize the world’s information and make it universally accessible and useful.”

Sony – “To be a company that inspires and fulfills your curiosity.”

Notice how every mission statement is reduced down to the bare minimum required to describe the impact of the business. Your statement should follow this as well.

To create a mission statement for LeafPup, I went back to the word “confidence” from my brand voice. I wanted LeafPup to help dogs of all ages manage anxiety, discomfort, and fear in order to see more confident pups at the end of the day.

And so it became, LeafPup – “to help dogs of all ages manage anxiety, fear, and discomfort in order to see more confident pups at the end of the day”

5. Put Together a Mood Board

Here’s where you get to see your brand start coming together and it’s probably the easiest part to do. Pinterest is your best friend here if you aren’t design savvy.

All you have to do is create a Pinterest board for your brand and start searching for images using the keywords you chose for your brand voice. For LeafPup: loyal, warm, and confident images become the filter for “pins” that fit the brand.

After pinning about 50 different images to our company board, we had a pretty good idea what our brand was going to look like!

We picked a few of our favorite images and made a collage to narrow down the overall “vibe”. Here’s what it looks like.

Branding Board

6. Find Your Colors

It might be tempting to just pick your favorite color as your primary brand color, but it surely isn’t the most logical thing to do. We had you make a mood board for a reason!

Your mood board should tell you exactly what colors you are going to add to your palette! If you found a lot of images for your mood board that have a similar color blue, then it makes a lot of sense for that shade of blue to be in your color palette.

To really speed up the process of finding a color palette, we use Adobe Color. Don’t worry, it’s free! You can upload or browse through images that fit the vibe of your brand and Adobe Color will automatically create a color palette for you!

Brand's colors

For LeafPup, most of our images had an early-autumn color palette: browns, oranges, reds, and subtle greens. Rather than using the color green, I’m opting to use actual images of house plants and trees to convey our branding. Then, I’m taking a khaki color to use as a background against a dark brown type color. This will create the warm, homey vibe that I’m looking for. I pulled these colors from various images in my mood board and picked a few colors that would soften everything up. Finally, I picked a soft teal accent color to bring out the “confidence” that LeafPup is coming to stand for.

7. Design Your Logo

We realize this is where it gets kind of tricky if you don’t happen to be a graphic design wiz. More than likely you’ll have to outsource to a designer or design team, but at least now you have a solid brand direction to hand off.

You can find quality designers on popular freelance platforms like Fiverr, but it’s really important that you provide them with everything you’ve worked on up until this point. You don’t want to miscommunicate.

Your logo should incorporate your brand voice keywords and be able to blend well with the rest of your mood board. Let’s take a look at how Airbnb used their keywords to craft their logo icon!

Airbnb's Logo

Don’t get too caught up with trying to make a logo that describes what you do. You’ll have a million chances to tell consumers what your business does. At the end of the day, your logo is an identity that needs to meet 3 criteria. It has to be simple, appropriate, and unique. Somebody should be able to look at your logo for 5 seconds, turn around, and then draw a logo that could only resemble your logo on a blank piece of paper.

If your logo can pass that test, you probably have something you can move forward with as long as it’s appropriate. By that, I mean that it is appropriate for the rest of your brand. Remember, it has to fit in with the rest of your mood board.

Being a graphic designer with experience in building brands, I wanted to take the image of the puppy holding a leaf that I used in my mood board to create a minimal mascot icon for the LeafPup brand. The cuteness of the mascot would attract attention while the warm, natural color palette tell our story of loyalty and warmth.

Leafpup's Logo

With our products being CBD infused, the leaf was made to slightly resemble a cannabis leaf without screaming “cannabis company”. Most importantly, the logo is simple, memorable, and entirely unique. It passes the test.

8. Choose Your Typography

There are thousands of fonts for you to choose from, but you can’t rely on a gut feeling. Making the right decision depends on function, context, and a whole set of other factors.

Think about personality. Think back to your brand voice. If your brand voice is friendly, you might look for rounded fonts that are really easy to read. If your brand voice is confident, you might look for bold, condensed fonts. Maybe all caps? When you look through all your font options, think about the way they make you feel. Do they match your brand voice to the tee or could it be better communicated?

Think about function. What font are you using for what purpose? At the bare minimum you will want to find a font for your headings and a font for paragraphs. A lot of brands choose a 3rd font that acts as a brand element on it’s own.

Brand's Typography

In the above example, you can see how fonts are used functionally. There are 2 fonts at play here: Franklin Gothic URW Medium as the font in charge of getting your attention (main headings and buttons) and Adobe Garamond Pro Regular as the secondary fonts for body content and subheadings. You should take a similar approach when picking the fonts for your brand.

With LeafPup being an all natural company with a natural color palette, we needed a font that would function perfectly while communicating our brand voice proudly. A mix of serif and sans-serif font in neutral colors tell our consumers that we’re not going anywhere. We’re loyal. Using a larger font size for headings will communicate confidence, and using a softer font for body paragraphs will make our customers feel the warmth and homeyness we need to convey as well. Here’s what this looks like.

LeafPup's Fonts

9. Put Everything Together

Now that you have everything that meets the bare minimum to build a solid brand, it’s important that you take the time to present everything that you’ve worked on. Some call this a style guide, some call it brand guidelines, and some call it your brand book. Regardless, it’s a necessary step in building a brand.

Your style guide will be your bible in everything you do from here on out. You should look to it for advice on the best direction to go. Not just with design, but internal culture as well. If your brand voice and mission statement involves the word “peaceful”, you should prioritize making your working environment peaceful, making your customers at peace when they interact with you, and having a tone of voice that is soft and relaxing.

Leafpup's Mission Statement

Leafpup's Moodboard

Leafpup's Primary Logo

Leafpup's Color Palette

In the above example, everything we talked about in this guide is strategically laid out to clearly communicate all brand elements. When you look at LeafPup’s style guide, you know exactly who they are, what they stand for, and the design elements that help them stand out.

An easy way to make a style guide is to make a Powerpoint or Google Slide deck. Each slide explains and depicts the different elements of your brand.

10. Be Consistent

Your brand doesn’t stop developing here. It never ends. Fortunately, you’ve set yourself up for success by creating your style guide. The next time you need a flyer designed for an event your hosting, you can send your style guide to your designer and they will have everything they need to make sure your brand stays cohesive throughout every design project.

Everything that involves your business should fit perfectly into your style guide as an example of your design elements. Your company t-shirts, business cards, website, packaging, investor slide deck, and everything else you can think of should follow suit with your style guide.

Of course, I can’t help but to promote my real startup here. I started Pence Branding because something felt wrong about hiring a big branding agency (that charges hundreds of thousands of dollars) to create a beautiful brand around your startup idea only to send you on your way to hold up those brand standards yourself when you need a small flyer designed in the future.

At Pence Branding, we go through this process of designing your brand style guide and then roll into an unlimited graphic design/web design subscription with 48 hour turnaround times to ensure your brand elements are always used to the tee. It’s like having your very own in-house design team.

For LeafPup, the first design project that we tackled was packaging. Since CBD has turned into such a competitive market, conveying LeafPup’s brand identity through well-designed packaging was vital for standing out in the industry. Rather than simply hopping on the CBD train, we needed to create a brand that focused on educating consumers while having an empowering message to connect with and support.

After we finalized our packaging, we were able to move forward with our next project: the LeafPup e-commerce site. As mentioned earlier in this article, although the CBD industry is expected to reach $40 billion within the next 5 years, it is still heavily regulated.

Leafpup's Package

Currently the largest retailers and advertising platforms, like Amazon, Facebook, and Google don’t even support CBD sales. This means one thing: LeafPup’s direct-to-consumer platform (the e-commerce site) has to function beautifully while still communicating all of LeafPup’s creatively designed brand elements.

Here’s the e-commerce site we were able to design within 24 hours of finishing the LeafPup brand style guide.

Leafpup's Website

Leafpup's Products

You can see the full site prototype hereundefined.

Focusing your attention on building a style guide will make all future design projects a breeze. The next time you need to design a business card, website, or flyer, you will have your logo, color palette, fonts, and usage examples on hand for you to simply plug-in and go to market.

After all, time is of the essence.

Conclusion

We hope you enjoyed reading about our process of building a lean startup brand from scratch. All-in-all, the process took us 72 hours from idea to e-commerce platform. For those of you who are wondering, we are actually planning on launching the company 2 months from today (after funding is secured for our initial inventory purchase).

A marketing campaign is a project. There is a start and end date, specific deliverables, and measurable results. Building a brand isn’t a project and you can’t treat it like one. Building a brand can be more similarly related to growing as a person. You might spend your first 5 years figuring out who you are and adapting your brand elements as you go. Your brand will mature over time, develop more traits, quit bad habits, and might even end up being the opposite of what it was when it first started out.

You have to let the life your business has gone through impact your brand like the life you’ve personally gone through has impacted your current values and personality.

Of course, if you never develop your initial brand identity, there will be nothing to change. Start by looking into your personal story, set your brand voice, put together a mood board, come up with a simple name, write your mission statement, find your colors, design your logo, pick your fonts, and then put everything together into a style guide (a slide deck will work great!). After you get that far, be consistent, but let your brand go through the necessary changes to stay relevant, mature, and last a lifetime.

The best brands mature at the same time as their customers. While design might matter to their customers now, maybe comfort will matter 10 years from now. Let your brand adapt. Let your brand have its own personality and experiences. At the end of the day, your customers and employees will end up developing the bulk of your brand anyways. Your job is to communicate the values that your customers/employees develop through beautiful design.

✉️ Subscribe to receive weekly startup related articles!

We’re always publishing new articles about startups. Sign up for our newsletter to keep updated on the latest additions. You can unsubscribe whenever you want!

build-your-own-react

function createElement(type, props, ...children) {

children: children.map(child =>

typeof child === "object"

: createTextElement(child)

function createTextElement(text) {

function createDom(fiber) {

fiber.type == "TEXT_ELEMENT"

? document.createTextNode("")

: document.createElement(fiber.type)

updateDom(dom, {}, fiber.props)

const isEvent = key => key.startsWith("on")

const isProperty = key =>

key !== "children" && !isEvent(key)

const isNew = (prev, next) => key =>

const isGone = (prev, next) => key => !(key in next)

function updateDom(dom, prevProps, nextProps) {

isNew(prevProps, nextProps)(key)

.filter(isGone(prevProps, nextProps))

.filter(isNew(prevProps, nextProps))

dom[name] = nextProps[name]

.filter(isNew(prevProps, nextProps))

deletions.forEach(commitWork)

commitWork(wipRoot.child)

function commitWork(fiber) {

const domParent = fiber.parent.dom

fiber.effectTag === "PLACEMENT" &&

domParent.appendChild(fiber.dom)

fiber.effectTag === "UPDATE" &&

} else if (fiber.effectTag === "DELETION") {

domParent.removeChild(fiber.dom)

commitWork(fiber.sibling)

function render(element, container) {

let nextUnitOfWork = null

function workLoop(deadline) {

while (nextUnitOfWork && !shouldYield) {

nextUnitOfWork = performUnitOfWork(

shouldYield = deadline.timeRemaining() < 1

if (!nextUnitOfWork && wipRoot) {

requestIdleCallback(workLoop)

requestIdleCallback(workLoop)

function performUnitOfWork(fiber) {

fiber.dom = createDom(fiber)

const elements = fiber.props.children

reconcileChildren(fiber, elements)

nextFiber = nextFiber.parent

function reconcileChildren(wipFiber, elements) {

wipFiber.alternate && wipFiber.alternate.child

index < elements.length ||

const element = elements[index]

element.type == oldFiber.type

if (element && !sameType) {

if (oldFiber && !sameType) {

oldFiber.effectTag = "DELETION"

oldFiber = oldFiber.sibling

wipFiber.child = newFiber

prevSibling.sibling = newFiber

return <h1>Hi {props.name}h1>

const element = <App name="foo" />

const container = document.getElementById("root")

Didact.render(element, container)

how-to-build-accessible-products-at-a-startup

Sneha Dasgupta

Cover photo with types of web accessibility

Cover photo with types of web accessibility

At a startup, accessibility can feel daunting because resources are limited, but new technology and smaller scope can be a unique benefit. Making the investment earlier on will save a lot of time and money in the long run.

Although this article is based on my experience as the only UX person working on an earlier stage product with a small team, many of the steps and resources can be used by larger organizations with more mature products.


Accessibility is the practice of making your websites usable by as many people as possible.

Why does accessibility matter?

  1. It’s good for business. The more users that can use the software, the bigger the market. Additionally, if your company is going after any government contracts or putting a consumer facing app into an app store, accessibility will likely be a requirement.
  2. It’s good for users. Globally, 2.2 billion people are blind, have low vision, or colorblindness, and 466 million people are deaf or have hearing loss. 40% of websites are completely inaccessible to users who are blind. Accessible products avoid alienating these groups and provide a better user experience for everyone.

Stakeholders will probably ask why it’s important to make the investment. Making the case for accessibility to get team buy-in is critical to success.


Design with accessibility in mind

Starting with accessible designs sets the tone for the rest of the product.

  • Pick colors with high contrast ratios. For users with low vision and colorblindness, high color contrast ratios can make content clearer. Read more about color contrast accessibility.
  • Use readable, scalable fonts. Users should be able to increase the font size by zooming in and out to more easily read the text. Generally, the body text should be at least 16px.
  • Don’t depend on visuals or audio alone to convey a message. Provide alternate messaging for blind, low vision, deaf, or hard of hearing users. For example, if a design uses color coding to categorize, consider pairing it with text, a pattern, an icon, etc.

A view of categorization without colorblindness, protanopia, deuteranopia, and tritanopia.

A view of categorization without colorblindness, protanopia, deuteranopia, and tritanopia.

Different types of colorblindness impact the way users see content. Pairing color with a secondary identifier can help users understand the message. Using text also allows a screenreader to pick up the information.

Check your work with tools like Stark

Designers aren’t required to know if a font color has a high enough contrast ratio. Plugins like Stark can be used while designing to check contrast ratio and font size, as well as simulate colorblindness.

Stark’s contrast checker gives a level of compliance for contrast ratios at different font sizes.

Stark’s contrast checker gives a level of compliance for contrast ratios at different font sizes.

Pick two colors to see if the contrast ratio is high enough for low vision users.

Use an existing design system

If you’re at a startup, it’s unlikely you’ll have the resources to build your own design system, let alone one that’s accessible. Leveraging an established design system, like Angular Material or React, helps ensure that every time a component is used, it passes accessibility compliance.

Auditing can be so overwhelming that there are companies that audit products for companies. At a startup, that luxury is unlikely, but luckily there are resources to streamline the process.

Start with an understandable checklist

Web Content Accessibility Guidelines (WCAG), created by World Wide Web Consortium (W3C), is a global standard for web accessibility.

“Web Content Accessibility Guidelines 2.0 explain how to make web content accessible to people with disabilities. Conformance to these guidelines will help make the Web more accessible to users with disabilities and will benefit all users.”

Reading through the WCAG requirements can be tedious. WebAIM, an accessibility non-profit, put together a checklist with recommendations on how to adhere to each guideline.

Use the WebAIM Checklist.

Go page by page with the WAVE Evaluation Tool

WebAIM also created a chrome extension that can be turned on for any page. It lists potential accessibility issues and gives suggestions on how to fix them.

The WAVE Evaluation Tool can be used on any page.

Install the WAVE Evaluation Tool Chrome extension.

Fill out an audit

Use the WebAIM checklist and WAVE Evaluation tool to fill out an audit. The Voluntary Product Accessibility Template (VPAT) is the most common audit form in the US. The audit provides the status of compliance for the product and helps the team understand how much work is needed.

Here’s a blank VPAT template I started with.

The final step is the most collaborative. It requires clear communication to make sure everyone’s on the same page.

Review the audit with the team to size the work

Discuss the findings to begin sizing how much work will be necessary. Use the checklist’s recommendations to meet unmet guidelines. This will help the team agree on how and when the work should be done.

Write requirements to chip away at remaining work

Make an epic to “Create an accessible product” to have a bucket for all accessibility work. Take the page-by-page audit and write requirements for each issue. When the work is defined, the goal looks a lot more achievable.

Screenshot of JIRA with an accessiblity epic.

Screenshot of JIRA with an accessiblity epic.

Code with accessibility in mind

Make a plan to maintain an accessible product. Developers need to code with accessibility in mind, just like designers design with accessibility in mind. Use a checklist, just like any other QA checklist, to assure each new feature passes accessibility standards.

Here’s the developer accessibility checklist I put together for my team.

Finally, don’t be afraid to re-open stories

Like any other functional requirement, accessibility should be treated as an expectation for each new feature. Enforce that expectation.

Screenshot of JIRA changing a story status to Reopen Issue

Screenshot of JIRA changing a story status to Reopen Issue


Although accessibility is a subsection of inclusive design, I find it’s a great place to start a larger discussion. The standardization and examples around accessibility help teams understand why inclusive design matters.

Priorities change and accessibility is often pushed to the end of the backlog, but tirelessly advocating for accessibility and inclusive design creates the best user experiences for all users.

Don’t let the way your product is built be the reason someone isn’t using it.

Resource list

how-to-build-a-todo-list-app-with-react-hooks-and-typescript

The best way to learn something is by doing. This tutorial will help you learn how to build your own todo list app with React hooks and TypeScript. Try this easy tutorial, build your own todo list app, and get better in JavaScript, React and TypeScript.

You can find the code on my GitHub.

Briefing

The goal for this tutorial is to build your own todo list app. About the app in general. This todo list app will have very simple interface and it will focus on the most important features, i.e. create, check off and delete todos. About code. You will use React and React hooks, mostly useState hook.

There will be one occasion where you will also use useRef hook. Since this todo list app will utilize React hooks for managing state there is no need to use class components. So, you will build this app only with functional components. When it comes to styling your todo list app, you will use external CSS stylesheets.

One last things. First every todo item will have a unique id. These ids will be generated when the todo item is created. You will use this id to mark the todo as complete or to remove it. To make this easier, while following good practices and avoiding using indexes, you will use shortid package.

Project setup

As the first thing let’s create the basic app for your todo list app. We can do this very fast with the help of create-react-app. You can use this package with npm init react-app react-hooks-todo-list-app-ts --typescript, npx create-react-app react-hooks-todo-list-app-ts --typescript or yarn create react-app react-hooks-todo-list-app-ts --typescript. If you don’t want to use TypeScript, omit the --typescript flag at the end of the command.

These commands will create starting template for your todo list app, with workflow setup and almost all necessary dependencies. There is one dependency you will need to install manually, the shortid and types for this package. So, use npm i shortid and npm i -D @types/shortid, yarn add shortid and yarn add -D @types/shortid or pnpm i shortid and pnpm i -D @types/shortid.

There are some assets, such as React logo, that came with the app template. You can remove it because you will not need it. A very simple version of your package.json should look similar to this:

{
  "name": "react-todo-list-hooks-ts",
  "version": "1.0.0",
  "description": "Simple Todo list app built with React hooks and TypeScript.",
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "main": "src/index.tsx",
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  },
  "dependencies": {
    "react": "16.11.0",
    "react-dom": "16.11.0",
    "shortid": "2.2.15"
  },
  "devDependencies": {
    "@types/react": "16.9.11",
    "@types/react-dom": "16.9.4",
    "@types/shortid": "^0.0.29",
    "react-scripts": "3.2.0",
    "typescript": "3.7.2"
  }
}

If you decide to use TypeScript, your tsconfig should look similar to this:

{
    "include": [
        "./src/*"
    ],
    "compilerOptions": {
        "lib": [
            "dom",
            "es2015"
        ],
        "jsx": "react",
        "target": "es5",
        "allowJs": true,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true
    }
}

As the last thing, below is the final structure of this todo list app project. You can use this as you work on this tutorial to orient yourself. With that, you are ready to start working on your todo list app.

react-meme-generator-ts/
├─node_modules
├─public
│ ├─favicon.ico
│ ├─index.html
│ ├─manifest.json
│ └─robots.txt
├─src
│ ├─components
│ │ ├─todo-form.tsx
│ │ ├─todo-item.tsx
│ │ └─todo-list.tsx
│ ├─styles
│ │ └─styles.css
│ ├─index.tsx
│ ├─interfaces.ts
│ └─react-app-env.d.ts
├─ package.json
└─ tsconfig.json

Interfaces

The first thing to do is create interfaces for your todo list app. You will use them to define the shape of component props and the todo object, or to type them. If you decided to use pure JavaScript, instead of TypeScript, you can skip this step. You will need to create four interfaces.

One for todo (todo object), one for todo form one for todo list and one for todo item. The todo object will have three properties, id, text, isCompleted. The TodoForm props contain array of todo objects and handleTodoCreate method. The TodoList props will contain handleTodoUpdate, handleTodoRemove, handleTodoComplete and handleTodoBlur methods and array of todo objects.

The TodoItem props will contain handleTodoUpdate, handleTodoRemove, handleTodoComplete, handleTodoBlur and a single todo object.

// Todo interface
export interface TodoInterface {
  id: string;
  text: string;
  isCompleted: boolean;
}

// Todo form interface
export interface TodoFormInterface {
  todos: TodoInterface[];
  handleTodoCreate: (todo: TodoInterface) => void;
}

// Todo list interface
export interface TodoListInterface {
  handleTodoUpdate: (event: React.ChangeEvent, id: string) => void;
  handleTodoRemove: (id: string) => void;
  handleTodoComplete: (id: string) => void;
  handleTodoBlur: (event: React.ChangeEvent) => void;
  todos: TodoInterface[]
}

// Todo item interface
export interface TodoItemInterface {
  handleTodoUpdate: (event: React.ChangeEvent, id: string) => void;
  handleTodoRemove: (id: string) => void;
  handleTodoComplete: (id: string) => void;
  handleTodoBlur: (event: React.ChangeEvent) => void;
  todo: TodoInterface;
}

Todo item component

The first component you will build will be todo item. When you add new todo on your todo list, this item component will represent it. This component will be composed of a couple of elements. First, there will be a div with span elements for checking off the todo. Unchecked item will contain empty span, styled into a transparent circle with border.

Checked off todo item will contain span with check mark HTML entity, inside a green circle. The wrapper div will have onClick handler to check/uncheck the todo. Next will be another div with input. You will use this input element to render the title, or the text, of the todo. This is the simplest way to make every todo item editable, through input elements.

You will pass the title be done through value attribute, from todo object passed through props. Aside to this, this input will have two handler methods, one for onBlur and one for onChange. The last element will be also a div, now with “x” entity/icon. You will use this element to remove the todo item.

This div will have one onClick handler. As all the previous data, and handler methods, this too will be passed thorough props.

If you use TypeScript, import the TodoItemInterface interface from interfaces.ts and to use it to type props of this component. After this, type the onChange handler on input element with React.ChangeEvent because we are attaching onChange handler to input element.

// Import dependencies
import * as React from 'react'

// Import interfaces
import { TodoItemInterface } from './../interfaces'

// TodoItem component
const TodoItem = (props: TodoItemInterface) => {
  return (
    
props.handleTodoComplete(props.todo.id)}> {props.todo.isCompleted ? ( ) : ( )}
) => props.handleTodoUpdate(event, props.todo.id)} />
props.handleTodoRemove(props.todo.id)}> ⨯
) } export default TodoItem

Todo list component

The todo list will be the second component you will create. This component will be very simple. This component will accept handler methods for the TodoItem, you’ve just created, and array of todo objects through props. The component itself will contain one div as a wrapper element.

Inside this div will be a list, one ul element. Inside this element, you will use map() to iterate over the array of todo objects, and create one li element with one TodoItem component for every todo object. You will then pass the individually todo objects to the TodoItem component, along with handler methods.

For TypeScript, remember to import TodoListInterface interface and use it to type the props of the TodoList component.

// Import dependencies
import * as React from 'react'

// Import TodoItem
import TodoItem from './todo-item'

// Import interfaces
import { TodoListInterface } from './../interfaces'

// TodoList component
const TodoList = (props: TodoListInterface) => {
  return (
    
    {props.todos.map((todo) => (
  • ))}
) } export default TodoList

Todo form component

The todo “form” will is the first component where you will use useState React hook. It is also here where you will use the useRef React hook. You will use the useState hook to store the text passed to the input element, text for the todo title before you will create new todo item.

You will use the useRef hook to store reference to this input. The way you create new todo is by pressing “Enter” key, while you type some text inside that input. So, when you press “Enter” key you will use this reference to reset the input, by setting the value to empty string. This input will also have two handler methods for onChange and onKeyPress.

These two handler methods will be handleInputChange and handleInputEnter. The first, for onChange, will update the form state when you write something into the input, some todo title/text. The second, for onKeyPress, will create new todo object and reset the input field when it detect pressing “Enter” key.

Do you remember the shortid package? It is here where you are going to use this dependency. Inside the handleInputEnter function, inside the new todo object, you will use shortid to generate unique id for every new todo. Don’t worry. This will be simple. All you need is to call generate() on shortid and your new id is ready.

Lastly, few things for TypeScript. First, import TodoInterface and TodoFormInterface interfaces. Then, use the TodoInterface interface to type the new todo object inside handleInputEnter, and TodoFormInterface interface to type the props of TodoForm. Then, type the useRef hook, using and set it to null.

After that, there are also two events. For the first one, you can type it with React.ChangeEvent because we are attaching onChange handler to input element. For the second, you can type it with React.KeyboardEvent because we are “listening” for key press.

// Import dependencies
import * as React from 'react'
import shortid from 'shortid'

// Import interfaces
import {TodoInterface, TodoFormInterface} from './../interfaces'

// Todo form component
const TodoForm = (props: TodoFormInterface) => {
  // Create ref for form input
  const inputRef = React.useRef(null)

  // Create form state
  const [formState, setFormState] = React.useState('')

  // Handle todo input change
  function handleInputChange(event: React.ChangeEvent) {
    // Update form state with the text from input
    setFormState(event.target.value)
  }

  // Handle 'Enter' in todo input
  function handleInputEnter(event: React.KeyboardEvent) {
    // Check for 'Enter' key
    if (event.key === 'Enter') {
      // Prepare new todo object
      const newTodo: TodoInterface = {
        id: shortid.generate(),
        text: formState,
        isCompleted: false
      }

      // Create new todo item
      props.handleTodoCreate(newTodo)

      // Reset the input field
      if (inputRef && inputRef.current) {
        inputRef.current.value = ''
      }
    }
  }

  return (
    
handleInputChange(event)} onKeyPress={event => handleInputEnter(event)} />
) } export default TodoForm

Main (index) component

You are almost done. There is just one component you need to build. This is the main TodoListApp component. This component will implement methods for creating, updating, removing and completing your todos. This will be done via handleTodoCreate, handleTodoUpdate, handleTodoRemove and handleTodoComplete methods.

It is also this component where you will store all existing todos, using the useState React hook. So, let’s build this component, step by step.

Imports

First, as usually, you will need to import dependencies for react. Now, you will also need to import render method from react-dom. This is because you will render the TodoListApp component, your todo list app, in the DOM.

You will also import TodoForm and TodoList components so you can later return, and render, them. When you import these components you should also import the main external CSS stylesheet, so you can later style your todo list app.

For TypeScript, you will need to import the TodoInterface interface. You will use this interface a couple of times, to type todos state and some method parameters.

// Import dependencies
import * as React from 'react'
import { render } from 'react-dom'

// Import components
import TodoForm from './components/todo-form'
import TodoList from './components/todo-list'

// Import interfaces
import { TodoInterface } from './interfaces'

// Import styles
import './styles/styles.css'

Creating todo list app state

The state fo your todo list app will be simple. It will be an array of objects. One object will represent one existing todo. In the beginning, you will initialize the todos state as an empty array.

For TypeScript, make sure to use the TodoInterface interface along with []. This will tell TypeScript you are “talking” about an array of todos objects, not just one todo object.

// TodoListApp component
// ....
const TodoListApp = () => {
  const [todos, setTodos] = React.useState([])
  // ...
}

Creating new todos

The first method for your todo list app will be method to create new todos, handleTodoCreate method. This method will accept one parameter, a todo object. The way it will work is simple. First, it will create new todo list app state, the newTodosState, by copying the current todo list app state.

Next, it will take the todo object, you pass as parameter when you call this method, and add that todo to the new todo list app state, the newTodosState, using push() method. After that, it will update the todo list app state, using setTodos() method.

About TypeScript. You will use the TodoInterface interface to type the todo parameter. You will also use this interface to type the newTodosState variable. In this case, you will again have specify you want an array of todo objects, adding [] after the TodoInterface.

  // ....
  // Creating new todo item
  function handleTodoCreate(todo: TodoInterface) {
    // Prepare new todos state
    const newTodosState: TodoInterface[] = [...todos]

    // Update new todos state
    newTodosState.push(todo)

    // Update todos state
    setTodos(newTodosState)
  }
  // ....

Updating existing todos

Next, you will need method to update existing todos, handleTodoUpdate method. This method will accept two parameters, event and id. The id will be unique id generated for every todo item/object. Similarly to handleTodoCreate, this method will also start by creating new todo list app state, newTodosState, by copying the current todo list app state.

Next, it will use find() method to iterate over the newTodosState variable and find the correct todo item to update, using the id passed as argument. When it finds the correct todo item/object, it will change the value of its text key. New value will come from the value of the input inside specific todo item.

The last step is updating the todo list app state, using newTodosState and setTodos() method.

For TypeScript, use the TodoInterface interface to type the todo parameter passed to find() method. Use it also for the newTodosState variable, along with [] after the TodoInterface. Lastly, type the id parameter as a string.

  // ....
  // Update existing todo item
  function handleTodoUpdate(event: React.ChangeEvent, id: string) {
    // Prepare new todos state
    const newTodosState: TodoInterface[] = [...todos]

    // Find correct todo item to update
    newTodosState.find((todo: TodoInterface) => todo.id === id)!.text = event.target.value

    // Update todos state
    setTodos(newTodosState)
  }
  // ....

Removing existing todos

Removing todos will be done using filter() method. First, you will create new todo list app state, newTodosState, by copying the current todo list app state. During this, you will use the filter() method to remove the todo you want to remove. This will be done by comparing id of all todos with the id of todo you want to remove.

When this is done, you will use this new, filtered, state to update the todos state with the setTodos() method.

For TypeScript, use the TodoInterface interface to type the todo parameter passed to filter() method. Then, use it also for the newTodosState variable, along with [] after the TodoInterface. Finally, type the id parameter as a string.

  // ....
  // Remove existing todo item
  function handleTodoRemove(id: string) {
    // Prepare new todos state
    const newTodosState: TodoInterface[] = todos.filter((todo: TodoInterface) => todo.id !== id)

    // Update todos state
    setTodos(newTodosState)
  }
  // ....

Completing todos

The method for completing todos will look very similar to handleTodoUpdate method. First, it will copy the current todo list app state and store it in newTodosState variable. Then, it will use find() method to find specific todo item/object in todos state.

This time, it will negate the value of isCompleted key of the specific todo item/object. After this, it will use the setTodos method to update todos state.

Now, about TypeScript. First, use the TodoInterface interface to type the todo parameter passed to find() method. Next, use this interface also for the newTodosState variable, again with [] after the TodoInterface. The last type will be for the id. This will be a string.

  // ....
  // Check existing todo item as completed
  function handleTodoComplete(id: string) {
    // Copy current todos state
    const newTodosState: TodoInterface[] = [...todos]

    // Find the correct todo item and update its 'isCompleted' key
    newTodosState.find((todo: TodoInterface) => todo.id === id)!.isCompleted = !newTodosState.find((todo: TodoInterface) => todo.id === id)!.isCompleted

    // Update todos state
    setTodos(newTodosState)
  }
  // ....

Ensuring every todo has title

The last thing. When you edit existing todo there should be some warning if you leave the text/title empty. To get this done you can watch change on input element inside every todo. Then, you can check its value is not an empty string, the length of the value is bigger than “0”.

If there is an empty string, you will add specific CSS class. When you input some text, you will remove that CSS class. This CSS class will mark the input with red border. You will define this class in your CSS stylesheet later.

As usually, the TypeScript. This will be quick. All there is to type is the event passed as parameter. Since you are attaching a onChange event handler on input element, you can use React.ChangeEvent.

  // ....
  // Check if todo item has title
  function handleTodoBlur(event: React.ChangeEvent) {
    if (event.target.value.length === 0) {
      event.target.classList.add('todo-input-error')
    } else {
      event.target.classList.remove('todo-input-error')
    }
  }
  // ....

Returning all components

Your todo list app is almost finished. Now, you now need to take all the components you’ve built so far, and imported in component, and return them. Make sure to provide all components with necessary props. After that, you can use the render() method and render the TodoListApp in the DOM.

  // ...
  return (
    
{/* Todo form component */} {/* Todo list component */}
) } // Render the App in the DOM const rootElement = document.getElementById('root') render(, rootElement)

Putting it all together

You wrote a lot code in this main component. Let’s put it all together to make it more clear.

// Import dependencies
import * as React from 'react'
import { render } from 'react-dom'

// Import components
import TodoForm from './components/todo-form'
import TodoList from './components/todo-list'

// Import interfaces
import { TodoInterface } from './interfaces'

// Import styles
import './styles/styles.css'

// TodoListApp component
const TodoListApp = () => {
  const [todos, setTodos] = React.useState([])

  // Creating new todo item
  function handleTodoCreate(todo: TodoInterface) {
    // Prepare new todos state
    const newTodosState: TodoInterface[] = [...todos]

    // Update new todos state
    newTodosState.push(todo)

    // Update todos state
    setTodos(newTodosState)
  }

  // Update existing todo item
  function handleTodoUpdate(event: React.ChangeEvent, id: string) {
    // Prepare new todos state
    const newTodosState: TodoInterface[] = [...todos]

    // Find correct todo item to update
    newTodosState.find((todo: TodoInterface) => todo.id === id)!.text = event.target.value

    // Update todos state
    setTodos(newTodosState)
  }

  // Remove existing todo item
  function handleTodoRemove(id: string) {
    // Prepare new todos state
    const newTodosState: TodoInterface[] = todos.filter((todo: TodoInterface) => todo.id !== id)

    // Update todos state
    setTodos(newTodosState)
  }

  // Check existing todo item as completed
  function handleTodoComplete(id: string) {
    // Copy current todos state
    const newTodosState: TodoInterface[] = [...todos]

    // Find the correct todo item and update its 'isCompleted' key
    newTodosState.find((todo: TodoInterface) => todo.id === id)!.isCompleted = !newTodosState.find((todo: TodoInterface) => todo.id === id)!.isCompleted

    // Update todos state
    setTodos(newTodosState)
  }

  // Check if todo item has title
  function handleTodoBlur(event: React.ChangeEvent) {
    if (event.target.value.length === 0) {
      event.target.classList.add('todo-input-error')
    } else {
      event.target.classList.remove('todo-input-error')
    }
  }

  return (
    
) } const rootElement = document.getElementById('root') render(, rootElement)

Styles

Your todo list app is ready to go. Well, almost. There is a lot of space for some styling. Here are some styles you can use to make your todo list app look better.

/* Default styles*/
html {
  box-sizing: border-box;
}

*,
*::before,
*::after {
  box-sizing: inherit;
}

#root,
body {
  min-height: 100vh;
}

body {
  margin: 0;
}

#root,
.todo-list-app {
  display: flex;
  flex-flow: column nowrap;
}

#root {
  align-items: center;
  width: 100%;
}

/* Todo list app styles  */
.todo-list-app {
  padding-top: 32px;
  width: 100%;
  max-width: 480px;
}

/* Todo form styles */
.todo-form input,
.todo-item {
  border: 1px solid #ececec;
}

.todo-form input {
  padding: 0 14px;
  width: 100%;
  height: 48px;
  transition: .25s border ease-in-out;
}

.todo-form input:focus {
  outline: 0;
  border: 1px solid #3498db;
}

/* Todo list styles */
.todo-list ul {
  padding: 0;
  margin: 0;
}

.todo-list li {
  list-style-type: none;
}

/* Todo item styles */
.todo-item {
  display: flex;
  flex-flow: row nowrap;
  align-items: center;
  padding: 8px;
}

.todo-form   .todo-list ul .todo-item {
  border-top: 0;
}

.todo-item-input-wrapper {
  flex-grow: 1;
  padding: 0 16px;
}

.todo-item input {
  width: 100%;
  border: 0;
  border-bottom: 1px solid transparent;
  transition: .25s border-bottom ease-in-out;
}

.todo-item input:focus {
  outline: 0;
  border-bottom: 1px solid #3498db;
}

.todo-item .todo-input-error {
  border-bottom: 1px solid #e74c3c;
}

.todo-item span {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 1px solid #ececec;
  transition: .25s all ease-in-out;
}

.todo-item-unchecked:hover {
  background: hsla(168, 76%, 42%, .25);
  border: 1px solid hsl(168, 76%, 42%, .25);
}

.todo-item-checked {
  color: #fff;
  background: #1abc9c;
  border: 1px solid #1abc9c;
}

.item-remove {
  display: flex;
  padding-left: 8px;
  padding-right: 8px;
  font-size: 28px;
  cursor: pointer;
  line-height: 1;
  color: #ececec;
  transition: .25s color ease-in-out;
}

.item-remove:hover {
  color: #111;
}

Conclusion: How to Build a Todo List App with React Hooks and TypeScript

Congratulations, you’ve just built your own todo list app using React hooks and TypeScript! However, you don’t have to stop here. So, go ahead. Take this todo list app and make it better. Think about what features you would like it to have. Then, don’t wait for anything. Try to implement them by yourself. Have fun!

If you liked this article, then please consider subscribing.

build-a-sound-foundation-to-scale-your-facebook-campaigns

With SMX East right around the corner, it’s a great time to start the conversation that will shape my talk in November – How to Structure Your Facebook Campaigns for Success. This can surely seem a daunting undertaking. There are so many levers to potentially pull, and so much information available on the topic that it can at times be overwhelming for even the most seasoned digital marketer. However, if you’re able to keep these two things in mind, you’ll be well on your way to establishing a sound foundation to scale your social program.

The first step is to simplify your account structure where possible. We all remember not too long ago when the typical Facebook account looked like this: 

Multiple campaigns, dozens of ad sets, with you, the advertiser, struggling to identify the little pockets of performance to scale efficiency. Today, most publishers are recommending a more simplified approach, with Facebook (and Google) taking the lead for that recommendation. At my company, we’ve tested extensively into this simplified structure and found that for most of our clients it performs with better conversion rates and lower costs. This is because when using that simplified structure, you’re reducing the likelihood that you’ll have ad sets with significant overlap (which could cause increased costs if multiple ad sets are bidding for the same user in auction). Simplifying and reducing the number of ad sets per campaign also increases the data density for each ad set, which allows the algorithm to optimize more efficiently. When shifting to this more simplified structure, you’ll essentially be paring down all potential for campaign/ad set overlap, so that you go from a structure that looks like the above, to one that more closely resembles this:

The second item is something that I’m sure you’ve heard before but bears repeating – always be testing. With the numerous levers available in-platform, it’s imperative that you know the strategies that will enable stable performance for your evergreen campaigns. I’ve found that developing a roadmap to outline your test ideas, and (most importantly) to record the results, is the most straightforward way to approach this, and can be as simple as creating a G-Sheet. Some of the things to ask yourself as you’re thinking about testing can be:

  • Do I know the bidding methodology that provides the best results for my business goals?
  • Do I know the creative that is most engaging and encourages conversion for new customers? Potential customers who have visited my site but haven’t converted? Existing customers?
  • How is customer lead quality (or AOV for e-commerce) impacted by serving impressions outside of Facebook and Instagram’s Newsfeed?
  • Do I know the value of recent website visitors compared to older website visitors? Which are the segments of users I should bid up (or down) on?

Adopting an always-on mindset for testing is even more important considering a major change coming to Facebook in early 2020 – the removal of ad set budget control and the shift to Campaign Budget Optimization (CBO). At my company, we’ve tested into this new feature to better prepare our clients for the change, with relatively positive results. For most clients, testing into CBO and enabling real-time budget distribution based on performance results in increased conversion volume, with similar or more efficient costs.

However, because every business is different, there’s no guarantee that CBO will generate more efficiency or increase conversion volume for your account. If you haven’t already, it’s time to put it as a priority on your testing roadmap – that way you’ll be able to go into the New Year confident that you’ve figured out how to make this new feature work for your account.

I hope these insights give you confidence as you’re reviewing your existing Facebook structure, or considering a structure for a brand new account. If you’d like more information or just want to chat, please check out my session at SMX East this upcoming November!


Opinions expressed in this article are those of the guest author and not necessarily Marketing Land. Staff authors are listed here.



About The Author

Zenia is an account lead for 3Q Digital, where she develops strategy and manages paid media for clients in a wide range of verticals. While she is knowledgeable in all aspects of digital marketing, her passion is in paid social marketing. She has contributed to Search Engine Land, Marketing Land, and Marin, and has spoken at Janes of Digital, SMX Advanced and SMX East.



how-to-build-a-plugin-system-on-the-web-and-also-sleep-well-at-night

At Figma, we recently tackled one of our biggest engineering challenges yet: supporting plugins. Our plugins API enables third-party developers to run code directly inside our browser-based design tool, so teams can adapt Figma to their own workflows. They can enable accessibility checkers to measure contrast, translation apps to convert language, importers to populate designs with content, and anything else their heart desires.

We knew we needed to design this plugin functionality carefully. Throughout the history of software, there have been many instances where third-party extensions negatively affected a platform. In some cases, they slowed the tool to a crawl. In other cases, the plugins broke whenever new versions of the platform were released. To the extent that we could control it, we wanted users to have a better plugin experience with Figma.

Furthermore, we wanted to make sure plugins would be safe for users to run, so we knew we wouldn’t want to simply eval(PLUGIN_CODE). That is the quintessential definition of insecure! Yet, eval is essentially what running a plugin boils down to.

To add to the challenge, Figma is built on a very unconventional stack with constraints that previous tools haven’t had. Our design editor is powered by WebGL and WebAssembly, with some of the user interface implemented in Typescript & React. Multiple people can be editing a file at the same time. We are powered by browser technologies, but also limited by them.

This blog post will walk you through our pursuit for the perfect plugin solution. Ultimately, our efforts boiled down to one question: How do you run plugins with security, stability, and performance? Here’s a brief overview of our many non-trivial constraints:

Security: Plugins only have access to the file when explicitly launched. Plugins are restricted to the current file. Plugins can’t make calls as figma.com. Plugins can’t access each other’s data unless given willingly. Plugins can’t tamper with the Figma UI and behavior to mislead the user (e.g. phishing).
Stability: Plugins should not be able to slow down Figma as to make it unusable. Plugins should not be able to break key invariants in our product, such as the property that everyone always sees the same thing when viewing the same file. It should not be necessary to manage plugin installation across devices/users in order to view a file. Changes to the Figma product or internal APIs should rarely, if ever, break existing plugins.
Ease of development: Plugins should be easy enough to develop to support a vibrant ecosystem. Most of our users are designers, and may only have moderate experience with JavaScript. Developers should be able to use existing debugging tools.
Performance: Plugins should run fast enough to support most common use cases, such as searching the document for a layer, generating charts, etc.

We considered dozens of different approaches branching into all sorts of different paths. We had weeks of discussing, prototyping and brainstorming. This blog post will focus on just three of those attempts that formed the most central path in our exploration.

For me, it has been the most satisfying exercise in first principles thinking. I had fun leveraging all the computer science fundamentals I learned in the classroom (the ones I never thought I’d ever use in the real world). If that idea excites you too, we’re hiring!

Attempt #1: The