Accessibility: Everyone has to own a little bit

There’s a misconception that accessibility is something a single champion can own. You’ve probably seen this. One person gets passionate about making a product accessible, takes on a mountain of work, and maybe they make some progress, until they hit a wall, run out of energy, or move on. The truth is, accessibility isn’t a heroic solo quest. It’s a team effort, and treating it like anything else is setting up for failure.

Ensuring accessibility takes more than adding alt text or using semantic HTML (though those are good starts). It’s about cultivating a mindset across every part of the process with designers, engineers, product managers. Everyone needs to care about accessibility if it’s going to stick. A designer considers color contrast before they open Figma. A product manager asks what accessibility standards a feature should meet when scoping it. An engineer thinks about keyboard navigation while writing the first line of code. It’s a web woven together, not a last-minute patch.

Every team and organization I have worked with says they care about accessibility, but often it doesn’t become a real priority. It’s easy to express a desire for accessibility, but without dedicated resources and support from management, it remains just that, a desire. It requires leadership to prioritize accessibility through meaningful investment and by embedding it into team goals and processes. It’s unlikely that the business side of your organization can really make more significant sales to invest heavily. Most of the time it is just a checkbox during the marketing or sale process. It’s understandable, given the fact that resources are limited.

When accessibility works best, it’s just part of how your team does things. Not a checklist at the end, not a separate ticket in the backlog. The most successful teams bake it into their DNA. They’ve got playbooks, reusable components that are accessible out of the box, and a culture where everyone’s comfortable pointing out potential barriers. When everyone gets it right from the start, it’s cheaper, faster, and just better for everyone involved.

So if you’re that accessibility champion, the one person who’s been pushing, I’ll say this, your goal isn’t to do all the work. Your goal is to get everyone to own it a little bit. Start small. Share wins. Celebrate when someone remembers to add a focus state or labels a button properly. It’s about getting the team to play together, not putting the weight on your shoulders alone.

......................................................................

Your UI Sucks and You Are Wrong—You DO Need a Design System

How do you scale the UI for your product when the code is spread across different repos, using various technologies that aren’t compatible with each other?

In a previous role, I worked at a mid-sized company where the UI was built using Angular, React, .NET MVC, .NET Web Forms, Telerik UI, jQuery UI, KnockoutJS, and a mix of custom CSS and jQuery plugins accumulated over 15 years. Most features were tightly coupled.

I suspect many codebases that have been around for a while look something like this. I’d even go so far as to say that FAANG codebases might be no different. It’s a mess, and solving it is tough because a rewrite would be extremely expensive in an already competitive market where your major competition is lightyears ahead. Most SaaS companies aren’t engineering-driven. While they have engineering departments, it’s seen as a necessary function, not the core offering of the business.

It’s easy to imagine this scenario and realize there’s no consistent user experience across features. Implementing a new user experience requires writing the same UI code over and over, leading to inconsistencies, bugs, and rework. It’s also likely that most small to mid-size companies hire mostly full-stack developers who lack deep UI expertise. In the short term, this might seem efficient, but it eventually leads to diminishing returns, and the deeper they go with this model, the bigger the tech debt hole they dig.

How do we solve it?

A rewrite isn’t an option, and there’s likely neither the will nor investment from the board. Remember, most software companies don’t view themselves as engineering-driven; they see engineering as necessary but not their core strength. In my opinion, the solution is a Design System.

I’ve noticed through many online interactions with designers and front-end engineers that there’s a misconception about what a design system should be. There are many beautiful systems built in public, but that’s not what I’m talking about. When I say a design system, I mean the simplest version that solves your organization’s UI and user experience challenges. Of course, if you have the resources and leadership support, you can go for a more robust, open-source version.

Adopting an open-source design system

If you’re starting fresh or your tech stack isn’t as complex as the one I described earlier, adopting an existing system might be a good option. If your entire codebase is a single-page application (SPA) built on React, there won’t be many issues adopting something flexible for your team and brand.

But that’s not the case for the scenario I described. If you find yourself in that situation, you’ll know what I mean. If you have to descope UI features that would improve the user experience, then you have a problem with your tools.

Start small and build on that. Real agile.

You need a design system, and starting one isn’t the big, expensive ordeal it’s made out to be. It can be, but it doesn’t have to. Start by identifying your requirements and constraints. In the tech stack I mentioned earlier, your system needs to be compatible across different technologies. You likely don’t have a dedicated roadmap for it, so it needs to start small, prioritizing reusable UI elements that fit into the existing development process. Another constraint: you can’t rewrite legacy code.

So how do you do it?

Here’s what my team and I did to solve our issue. It wasn’t fixed overnight, but it put us on the right path:

  1. We started by creating an inventory of our UI. Brad Frost, author of Atomic Design, suggests collecting screenshots of all the UI component variations you can find.
  2. Identify the technology each component is built on.
  3. Find an approach that will give you the broadest support and early wins. In other words, what are you going to build, and with what technology?

You don’t need to start with a full component library before you can use it. Think simpler. Start by building a set of design tokens as CSS variables to be shared. This small step will normalize your brand across the product, and it’s compatible with any stack

In our case, we took a hybrid approach. Given the diversity of our UI, we decided to build our own UI components using Web Components. To ensure compatibility across our stack, we chose Stencil JS, a web component compiler built by the Ionic team. It allows you to create web components that can be integrated with any framework. We didn’t start by building every component we thought we needed. Instead, we began with a button—something simple yet essential, with all the variations we needed across the system.

With each new feature, we added additional components that were high priority.

This approach worked for us. I’m not suggesting it’s the solution for everyone.

I don’t know your challenges. We had the front-end expertise to build this kind of solution. It solved many of our UI compatibility issues across applications. You can start smaller—by writing reusable CSS, for example, and later integrating it with components. Find your path.

Your UI sucks, and you need a design system.

Let me know your thoughts. Have you worked on a similar solution? How would you approach it differently?

For more follow me on X @TheJoseFromSJ.

......................................................................

Optimizing React Apps: When and How to Use React.memo

React’s performance is generally excellent out of the box, but as our applications grow more complex, we may need to optimize to maintain smooth performance. One tool in our optimization toolkit is React.memo. However, like any tool, it’s important to understand when and how to use it effectively. Let’s dive into the nuances of React.memo and explore some common pitfalls and solutions.

React.memo Basics

React.memo is a higher-order component that we can use to optimize functional components by preventing unnecessary re-renders. It does this by performing a shallow comparison of the component’s props. If the props haven’t changed, React skips rendering the component and reuses the last rendered result.

Here’s a basic example:

const MemoizedComponent = React.memo(function MyComponent(props) {
  // Your component logic here
});

The Prop Reference Challenge

While React.memo sounds great in theory, it’s not always a silver bullet. One common issue arises from how JavaScript handles object and function references.

Consider this example:

function ParentComponent() {
  const onClick = () => console.log('Button clicked');
  const data = { a: 1, b: 2 };

  return <ChildComponent onClick={onClick} data={data} />;
}

In this case, every time ParentComponent renders, it creates new references for onClick and data. Even if we wrap ChildComponent with React.memo, it will still re-render on every parent render because React.memo sees these as new props.

When React.memo Might Not Make Sense

Given the above scenario, there are times when using React.memo might not provide the optimization we’re looking for:

  1. Unnecessary Re-renders: If the parent component always creates new prop references, the memoized child will still re-render.
  2. Wasted Comparisons: The shallow comparison performed by React.memo becomes overhead if the component will re-render anyway due to new prop references.

Let’s look at an example where React.memo doesn’t help:

const MemoizedChildComponent = React.memo(ChildComponent);

function ParentComponent() {
  const onClick = () => console.log('Button clicked');
  const data = { a: 1, b: 2 };

  return <MemoizedChildComponent onClick={onClick} data={data} />;
}

Despite using React.memo, MemoizedChildComponent will still re-render on every ParentComponent render due to new onClick and data references.

Optimization Tips

To make React.memo more effective, we can stabilize prop references using useCallback and useMemo:

import React, { useCallback, useMemo } from 'react';

const MemoizedChildComponent = React.memo(ChildComponent);

function ParentComponent() {
  const onClick = useCallback(() => console.log('Button clicked'), []);
  const data = useMemo(() => ({ a: 1, b: 2 }), []);

  return <MemoizedChildComponent onClick={onClick} data={data} />;
}

Now, onClick and data maintain stable references across renders, allowing React.memo to prevent unnecessary re-renders of MemoizedChildComponent.

When to Avoid React.memo

There are scenarios where React.memo is unnecessary or even counterproductive:

  1. Primitive Elements: Wrapping basic elements like <div> or <button> in React.memo is usually overkill.
  2. Components with Frequently Changing Props: If a component’s props change often, the overhead of comparison might outweigh the benefits of memoization.

Final Thoughts

React.memo can be a powerful optimization tool when used correctly. However, it’s not a one-size-fits-all solution. To use it effectively:

  1. Understand how prop references work in your components.
  2. Use useCallback and useMemo to stabilize prop references when necessary.
  3. Consider whether the overhead of memoization is worth it for your specific use case.
......................................................................

Stop Hiring for Frameworks, Start Hiring JavaScript Experts

The tech industry’s obsession with framework-specific job titles like “React Developer” or “Angular Engineer” is not just misguided—it’s potentially harmful to both companies and developers alike. By fixating on a particular library or framework, we’re losing sight of what truly matters: solid foundational knowledge and adaptability. The role we should be focusing on is UI Engineer or Frontend Developer, professionals who can navigate the ever-changing landscape of web technologies with ease.

At its core, frontend development is built on JavaScript, HTML, and CSS. These are the core technologies that power every modern web application, regardless of the flavor-of-the-month framework being used. A truly skilled UI Engineer doesn’t just know how to use React or Vue; they understand the underlying principles of JavaScript that make these libraries possible. This deep understanding allows them to quickly adapt to new tools, debug complex issues, and make informed architectural decisions that go beyond the surface-level implementation details of any single framework.

By hiring for JavaScript proficiency rather than framework expertise, companies set themselves up for long-term success. Technologies come and go, but the fundamentals remain. A developer who deeply understands JavaScript can pick up React, Angular, or the next big thing in a matter of weeks. Conversely, a “React developer” who lacks a strong JavaScript foundation may struggle when the winds of technological change inevitably blow. It’s time we shift our focus back to the core skills that truly define a great frontend developer: mastery of JavaScript, a keen eye for user experience, and the ability to learn and adapt in an ever-evolving field.

......................................................................

UX Design and Frontend Engineering Partnerships Through a Shared Design Systems in a Distributed System Architecture

Having worked both as a Senior Software Engineer developing web applications and as a Design leader establishing the design program from the ground up in a SaaS organization, I find myself in an intriguing position. I’ve been privileged to understand the constant tensions between two groups. On one hand, designers aim to push the limits of product development to enhance user experience, often facing obstacles with scope decisions that slash rich UI interactions they’ve spent weeks or months researching and designing. On the other hand, software engineers juggle delivery deadlines, writing clean maintainable code, and scaling applications with distributed system architectures like microservices. If time and money were limitless, everything desired could be achieved. Unfortunately, resources are finite and must be managed and focused in the most productive way for the highest return.

Design systems help bridge this constant tension.

Understanding Design Systems

A design system is defined by some as:

“ A collection of reusable components, standards, and guidelines for managing and scaling design.”

I would expand this definition to “…for managing and scaling design and application front-end development.”

It’s irrelevant how amazing and useful the design system is if the front-end developers aren’t equipped with the right tools to quickly execute the design across parts of the system. This underscores the vital necessity for teams aiming to scale a system to create a partnership between UX Design and the Front-end Engineering team.

UI Components are the code implementation of all the following parts of a design system: design guidelines, principles, patterns, accessibility guidelines, usability, and best practices. They empower software engineers to implement the design vision while reducing implementation timelines, bugs, and cost. 

As teams grow and become fragmented to focus on key features and decentralize the system’s architecture, sharing code becomes more difficult and chaotic than when the application was a monolith. This often leads to duplication of UI component code with similar functionality, more bugs, and inconsistencies in the user experience, not to mention that it violates the principle of Don’t Repeat Yourself (DRY). This scenario is magnified if the organization has multiple products, each with its own design team.

The Shared UI Component Library Of A Design System

Reusable UI components enhance the precision of implementing design. This precision ensures uniform user experience and UI across different parts of the application, creating consistency across the Product(s). It also improves development efficiency by reducing redundancy in design and development efforts, speeding up the product development lifecycle.

Maintaining consistency in the UI across distributed systems is a significant challenge, especially if teams work mostly independently or are spread across locations. Fragmented teams tend to set different standards and might build with different technology stacks, leading to discrepancies in how the UI is implemented. Without a centralized UI component library or design system, teams might end up creating similar components independently, leading to variations in appearance and behavior for components that should be consistent. It makes governing the design vision across the organization impossible.

A UI component library acts as a single source of truth for both design and development teams. It simplifies the governance of design principles across products and fragmented teams. A design system fosters a common language and understanding between the teams, enforced for Front-end Engineers through the library. UX Designers can benefit from a UI design kit that aligns with the UI components using their design software of choice, such as Figma or Sketch. A UI design kit is the equivalent of a UI component library for designers. Both reduce cost, increase consistency, and speed up time-to-market for both designers and engineers.

Implementing a Shared UI Component Library

Brad Frost popularized the concept in his book “Atomic Design,” which eventually led to the popularization of Design Systems. In his book, he outlines a clear path to start creating one for your organization. My experience, influenced by Frost, follows a simple approach:

  1. Inventory your UI for all UI components across your system. Identify variations of the same components.
  2. Start by building one component to be used in one project, then build on that foundation for the next project.

It’s that simple. Know the current state, build in increments. Every new component built by one team is a net gain for all other teams. Over time, the value of the system will become evident, but it will need your help to share and convince teams to adopt it in their projects. Most stakeholders won’t see the value until they start seeing the return because many are focused on delivering features and see this as a short-term distraction of resources. Begin small and iterate.

I won’t go into technology-specific implementations because those decisions should ideally be made by you and your teams, based on what works best for your system. Personally, I’ve found that building UI components with Native Web Components offers an excellent solution for teams working across diverse technology stacks. In the past, I’ve utilized StencilJS to construct a library that seamlessly integrates with both modern front-end frameworks and traditional web applications. Consulting with the teams can increase the likelihood of adoption. 

Communicating the Value to Stakeholders

I once had a conversation with a CTO about why it was time for the organization to take UI seriously. After sharing the reasons and challenges our teams faced in the past implementing user experiences, his response was unexpected. He said, “I am not in the business of building UI Component Libraries,” which is true. For a moment, I was at a loss for words, questioning whether I had failed to communicate the value, yet still convinced this was the right direction. He wasn’t wrong; leading the company’s technological vision and ensuring technology strategies align with its business goals is his primary mission. I believe that an investment in a design system is in the best interest for many companies because they are about scaling.

Here are a few benefits to communicate to your stakeholders if you believe the organization can benefit from a design system:

  • Increase Development Efficiency and Speed: A design system reduces redundant efforts in designing and coding similar components across different projects. Teams can rapidly prototype and iterate, leading to quicker product launches and feature updates.
  • Ensure Consistency and Improve User Experience: A design system ensures consistent application of the brand across all digital products. A unified component library can lead to more intuitive and cohesive user experiences.
  • Facilitate Team Collaboration and Communication: A design system acts as a shared language between designers, developers, and stakeholders, fostering better communication and collaboration.
  • Cost Savings in the Long Run: While there’s an upfront investment in creating a design system, it pays off by decreasing development time and effort in the long run.
  • Stay Competitive and Innovative: A design system is not just about building UI components but about positioning the company as a leader that values user experience and design innovation.

These are just a few of the benefits of a design system. But what if, after considering all these points, stakeholders still prefer to use an open-source UI Component library? This is a scenario you may very well encounter. Indeed, open-source projects offer significant advantages, including the ability to kickstart projects quickly, robust community support, and ongoing updates. This approach works well in many cases, but it’s not without its challenges and limitations.

Challenges and Limitations of Open-source Projects. 

  • While open-source libraries lay a solid groundwork, they frequently necessitate significant customization to align with your distinct brand identity and user experience standards. For instance, although you can modify Material Design colors, ultimately, it embodies Google’s brand, not yours.
  • Open-source components may not consistently meet specific business needs or objectives. An in-house design system, tailored to precisely accommodate the requirements of the business, users, and developers, can provide a more unified experience that directly supports the company’s goals.
  • Additionally, open-source projects often introduce unnecessary code, potentially impacting the application’s performance. An in-house design system permits the creation of more streamlined and optimized components, delivering exactly what’s needed without excess.
  • Relying on an open-source library means depending on external entities for updates, security patches, and new features. Constructing an in-house system affords full control, ensuring swift and secure adaptations to meet emerging needs or address security concerns.

Final Thoughts

Ultimately, whether to build a design system hinges on several factors: your organization’s growth phase, size, product complexity, commitment to UX, budget, engineering capabilities, and leadership support.

Assess your organization’s collaboration methods, pinpointing redundancies. Apply the DRY principle across both engineering and design to enhance efficiency.

Instead of aiming for a comprehensive system from the start, collaborate with stakeholders, designers, and engineers on a pilot project. Embrace incremental development to deliver value to multiple teams progressively.

There’s a common misconception that design systems must be elaborate, open-source projects showcased to the world. While commendable, not all organizations have the resources for such undertakings and from a business perspective its unnecessary for most teams.

Do all design and engineering teams need a design system? Absolutely. But does it need to be a widely publicized project? Not necessarily. It’s more about adopting a modular, iterative mindset in your work—this applies to developers, designers, product managers, and yes, even CTOs skeptical about investing in a design system that includes UI components.

Begin with modest initiatives, evolve through iteration, and gradually realize significant value.

......................................................................

From Vision to Action: Translating Business Goals into Effective UX Strategies

Aligning the user experience with business goals is crucial for gaining stakeholder support. Stakeholders aim to boost product and service sales, and achieving alignment often involves setting clear, overarching objectives and goals. Setting the right goals is the hardest but most important part of creating the right UX Strategy.

A social media company might set its goal to be “increasing time spent on user engagement.” The clarity of identifying which metrics are directly related to the company’s goals simplifies developing a UX Strategy that meets both user needs and business objectives in order to foster a unified direction for the organization. In this example, social media companies make business by selling ads to advertisers. The more a user engages with the platform, the more they are likely to spend time on it, thus more eyes on ads. That is why such a goal makes sense to them.

Compare that to the goal of “Saving 100 million lives.” While a noble goal, if I am selling a SaaS product that may eventually help those who use the product to save lives, how can I directly contribute to the goal? Furthermore, if I am a UX Designer, how do I translate that into my day-to-day work when I am designing features or conducting UX research?

Identify an Actionable Company Goal

It is common for companies to confuse the company’s mission or vision with the goal. In the second example, while a great goal, there is no clarity in what I can directly do as a Product Manager or a UX Leader to contribute to inching closer to achieving it. There are many frameworks for setting goals. Two of my favorites are Jim Collins’s Big Hairy Audacious Goal (BHAG) and North Star Goals.

In the early days of Amazon, the BHAG for the company was “Every book, ever printed, in any language, all available in less than 60 seconds.” I love this goal because it was specific and had something for everyone in the organization to check their effort against. If a project reduced the number of books, then it is not aligned with the rest of the organization. If engineering efforts increase the time to find the book, it is not helpful.

Spotify’s North Star Goal of “Time Spent Listening” is a good example of a simple and easy-to-measure and align-to goal. It is also clear how it contributes to the success of the company. Time spent listening tells us whether users enjoy the product and content and contributes to Spotify’s business model. Does your organization’s goal give you the clarity to take action or help you set clear smaller goals and metrics? If the answer is no, there may be more work to do.

For our purpose, we are going to assume that the organization has already identified a clear goal. Let’s assume we are working with a North Star Goal.

Understanding Users

The UX strategy should focus on aligning user needs with business goals. Happy users stay users. Use different research methods to identify user pain points, needs, goals, and opportunities. There are many tools like surveys, interviews, and usability testing, etc.

It is also important, especially for enterprise products, to know the difference between customers and users. For most consumer products, most of the time they are one and the same, but in enterprise SaaS products many times the buyer is not the same as the user. This situation often causes a conflict between the business goals and the user’s needs. For many customers in this scenario, they may not feel the pain users are experiencing and may not give priority to addressing them. Internal teams such as sales, and product may be focused more on the customer needs to increase sales and ignore the needs of users. It is important to understand the need of both and find a balance to serve them.

In this process, also gather feedback from other groups in the organization like product management, sales, marketing, and other customer-facing teams. The goal is not to commit to any effort, rather to gain an understanding of what everyone thinks the current pain points, needs, and opportunities are. Project prioritization will be done with Product Management; the goal is to identify the strategy.

Align UX Objectives with Business Goals

Translate your North Star Goal into specific UX objectives. For instance, if your North Star Goal is “To empower businesses to achieve seamless operational efficiency,” your UX objectives might include simplifying or automating complex processes, enabling easy integration with other tools, or providing actionable insights through analytics. Each UX objective should be a stepping stone toward achieving the North Star Goal.

It is likely that research is going to lead to identifying many areas to improve. Use the North Star Goal along with the research to prioritize features, improvements, and initiatives.

From our objectives, we can identify the metrics to measure whether the strategy is inching us closer to our North Star Goal. The metrics may be unique by organization, team, or product. Whatever your team ends up identifying, it should align with the goal. As an example, Spotify could focus on gaining a new type of audience by introducing new content. By increasing the audience size, they can increase the time spent listening. In this case, the goal may be the number of users listening to this new genre of content.

Communicate the Vision

Continuously communicate the North Star Goal and how the UX strategy supports it, both within your team and to the broader organization. This keeps everyone aligned and motivated, ensuring that day-to-day decisions reinforce the long-term vision.

The UX Strategy along with the business goals will help other teams make decisions. If the UX objectives include to improve navigation and task efficiency, engineering may need to hire different talent such as more experience Front-End Engineers to help achieve the goal. If the goal is to provide better analytics, then it may require to hire a new team with the appropriate experience or work with a vendor to deliver advance reporting capabilities.

......................................................................

Creating an authentication context with useContext in React

Creating an authentication context is a practical way to manage user authentication state across your entire React application. By using the Context API together with hooks like useContext and useState, you can easily share authentication state and logic across components.

There are several ways to pass information from parent components to child components in React. One way to do that is to use props. This works great with immediate children, but becomes more challenging when dealing with a deep component tree. A second way is to use the Context API to pass data deeply with Context. Context allows the parent to make information available to any component in the UI tree without using prop drilling.

Creating an authentication context

First we will use createContext to create our AuthContext. Create a file AuthContext.js somewhere in your project. I suggest you create a context folder at the same level of your App.js.

import React, { createContext, useContext, useState } from 'react';

const AuthContext = createContext();

export function useAuth() {
  return useContext(AuthContext);
}

Here we are initializing a new context and then we define and export useAuth(). This function defines and exports the custom hook so that we can easily access the context.

Next we need to declare an AuthProvider component that will wrap our application. We will also declare a login() and logout() methods. Our methods are simple for this demonstration. They will update the user appropriately.


export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    // Check if user is logged in when the app loads
    fetch('/api/check-auth')
      .then(response => response.json())
      .then(data => {
        setUser(data.user); // Adjust based on your API response
        setLoading(false);
      }).catch((e) => {
        // Navigate to the login page...
      });
  }, []);

  const login = (loggedInUser) => {
    setUser(loggedInUser);
  };

  const logout = () => {
    setUser(null);
  };

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {!loading && children}
    </AuthContext.Provider>
  );
}

Our AuthProvider uses the useEffect hook to check authentication from our server. This is particular useful in single page applications when users refresh the browser on any other route that is not the root route. You may have a different way of maintaining your authentication session, for now we are going to assume that the server is responsible for doing so.

We are also waiting to load any children with this line{!loading && children}, until we have the server’s response. For now we are not rendering anything. This would be a good opportunity render something that will improve the user experience rather than a blank screen or “loading” text.

Integrating AuthProvider with our application

The integration is quite simple. We are going to wrap our App component with our new context.

import React from 'react';
import ReactDOM from 'react-dom';
import { AuthProvider } from './AuthContext';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <AuthProvider>
      <App />
    </AuthProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

Now we can use our authContext with any component. Here is an example of how you can create a login component and use it to update the authentication context.

import React, { useState } from 'react';
import { useAuth } from './AuthContext';

function LoginComponent() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const { login } = useAuth();

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const result = await login(email, password);
      // Redirect the user or update the UI
    } catch (error) {
      // Handle errors (e.g., show error message)
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} />
      <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} />
      <button type="submit">Login</button>
    </form>
  );
}

You can import and use the context into any component: import { useAuth } from './AuthContext'. To get your current user all you have to do is call const { user } = useAuth() and you can now perform any business logic based on whether the user is logged in.

As a challenge create a ProtectedRoute component and use useAuth() to get the current user. If the user does not exist, navigate to the login page. Here is an example of how you would use it. See if you can implement it with react-router-dom.

<Routes>
  <ProtectedRoute>
    <Route path="/" element={
          <Dashboard />
      } />
  </ProtectedRoute>
  <Route path="/register" element={<Register />} /> 
  <Route path="/login" element={<Login />} />
</Routes>

Good luck!

......................................................................

Creating a todo application with React

The goal of this post is to teach you how to set up an app, not teach you react. You can learn React here.

If you haven’t already set up your React environment. Ensure you have create-react-app installed and then create a new project:

npx create-react-app react-todo-app
cd react-todo-app
npm start

The structure of your app

Here is an example of how you can organize your app folder structure. Whenever I start working with a new technology to build web applications I always seek to know how to best organize my code from the beginning. It saves a ton of time and headaches later.

todo-app/
|-- src/
    |-- components/
        |-- AddTodo/
            |-- AddTodo.js
            |-- AddTodo.styles.js
        |-- TodoList/
            |-- TodoList.js
            |-- TodoList.styles.js
        |-- TodoItem/
            |-- TodoItem.js
            |-- TodoItem.styles.js
    |-- context/
        |-- TodoContext.js
    |-- hooks/
        |-- useTodos.js
    |-- utils/
        |-- utilityFunctions.js
    |-- assets/
        |-- styles/
            |-- GlobalStyle.js
        |-- images/
    |-- App.js
    |-- index.js

  • App.js – The main component that holds everything together.
  • TodoList.js – Displays the list of to-do items.
  • TodoItem.js – Represents a single to-do item.
  • AddTodo.js – A form to add new to-do items.

We are going to create the last 3.

Creating the TodoList and TodoItem Components

Create a Todolist.js file, use the directory structure example to guide you on where to save it.

function TodoItem({ todo, toggleTodo }) {
  return (
    <li
      style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
      onClick={() => toggleTodo(todo.id)}
    >
      {todo.text}
    </li>
  );
}

export default TodoItem;

Here we are declaring our TodoItem component and it takes two props. The todo object itself and a handler to toggle the todo’s status from pending to completed.

In the same manner create TodoList.js and paste the following code.

import TodoItem from './TodoItem';

function TodoList({ todos, toggleTodo }) {
  return (
    <ul>
      {todos.map(todo => (
        <TodoItem key={todo.id} todo={todo} toggleTodo={toggleTodo} />
      ))}
    </ul>
  );
}

export default TodoList;

Like TodoItem, it takes two properties, a list of todos and a toggleTodo method that we are then passing down to each item. There are more advance and better ways of handling the state of the todo’s but our goal here is to get your started.

Now that our todo components are ready, lets move on to managing the state of the items.

Managing State in App.js

In App.js we are going to implement toggleTodos as well as an add method to add a todo that. We will take care of fully implementing it later.

import React, { useState } from 'react';
import TodoList from './TodoList';
import AddTodo from './AddTodo'; // We'll create this next

function App() {
  const [todos, setTodos] = useState([]);

  const toggleTodo = id => {
    setTodos(
      todos.map(todo =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    );
  };

  const addTodo = text => {
    setTodos([...todos, { id: Date.now(), text: text, completed: false }]);
  };

  return (
    <div>
      <AddTodo addTodo={addTodo} />
      <TodoList todos={todos} toggleTodo={toggleTodo} />
    </div>
  );
}

export default App;

There are several things going on here. First we use the useState hook manage our todos list state. useState adds a state variable that can be used to update and re-render our application anytime the items are updated such as marking one of the todos completed.

We also implemented toggleTodos, it takes the ID of the todo and toggles the completed property by looping through our list until it finds the todo with the ID.

We are using our TodoList component and passing it a list of todos and toggleTodos.

We also implemented addTodo which we will handle next.

Adding a new Todo item

For adding an item to our list of todos, we are going to create a new component. It you look at App.js we actually already used it. This component will render a form collecting the name of the todo item and call the addTodo method passed to it from App.js. In this way, our App component will take care of managing this simple state. Lets implement it.

import React, { useState } from 'react';

function AddTodo({ addTodo }) {
  const [value, setValue] = useState('');

  const handleSubmit = e => {
    e.preventDefault();
    if (!value) return;
    addTodo(value);
    setValue('');
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={value}
        onChange={e => setValue(e.target.value)}
        placeholder="Add a new todo"
      />
      <button type="submit">Add Todo</button>
    </form>
  );
}

export default AddTodo;

Our AddTodo component, renders a form and a button. It also validates that the input field in the form actually has a value. We use useState again to manage the state. We also attached to the onChange event of the input field to update our value state variable every time the value of the input field is updated. When the user clicks the Add Todo button, we pass value to addTodo and it will take care of adding the item to our list. We also set value to an empty string leaving the form ready for the user to add another todo.

Congratulations! You’ve just built a basic to-do app with React.

......................................................................

Efficient Web Development with Emmet in Visual Studio Code: Lorem Ipsum

Emmet is a web development plugin included by default in the Visual Studio Code editor that helps developers write HTML and CSS code more efficiently. It provides a set of abbreviations and shortcuts that allow users to generate code patterns quickly and easily, making coding faster and more productive. Emmet is a powerful tool that reduces the amount of typing and errors in your code, and it is supported by many popular code editors including Visual Studio Code, Sublime Text, and Atom. As a built-in plugin in Visual Studio Code, Emmet is an essential tool for developers who want to improve their workflow and write code faster and more efficiently.

Generating Lorem ipsum in HTML documents can be a useful tool for web developers and designers to quickly create placeholders for text. Lets see how to generate Lorem ipsum in an HTML document using Visual Studio Code Editor.

To start, open your HTML file in Visual Studio Code Editor. You can either create a new HTML file or use an existing one.

To generate Lorem ipsum text in your HTML file, you can use the Emmet abbreviation lorem followed by the desired number of words or paragraphs. For example, if you want to generate three paragraphs of Lorem ipsum text, you can use the following code:

<div>
    p*3>lorem10
</div>

In this code, we’ve created a div container and added a three p element with the lorem10 abbreviation. When you press the “Tab” key on your keyboard after typing this code, Emmet will automatically generate three paragraphs of Lorem ipsum text inside the p element with then words each.

You can change the number of the lorem command to generate a specific number of words instead. For example, if you want to generate 20 words of Lorem ipsum text, you can use the following code:

<span>Lorem20</span>

After typing this code, press the “Tab” key on your keyboard. This will generate 20 words of Lorem ipsum text inside the span element.

Generating Lorem ipsum in an HTML document using Visual Studio Code Editor is a quick and easy process with the built-in Emmet feature. By following the steps, you can easily generate placeholder text for your HTML projects without the need for external plugins.

......................................................................

UX Design Operations: What, Why, and How

UX design operations (DesignOps) is a term that describes the practice of optimizing and orchestrating the people, processes, and craft involved in creating consistent, quality designs. DesignOps aims to amplify the value and impact of design at scale by addressing common challenges such as growing and evolving design teams, finding and hiring talent, creating efficient workflows, and improving the quality and impact of design outputs.

Why is DesignOps important?

DesignOps is important because it helps designers focus on designing and researching instead of being bogged down by administrative tasks, communication overheads, or inconsistent tools and processes. DesignOps also helps designers collaborate better with each other and with other teams by establishing clear roles, responsibilities, standards, and expectations. DesignOps can also help designers demonstrate their value and influence within the organization by aligning their work with strategic goals and measuring their outcomes.

How to implement DesignOps?

There is no one-size-fits-all approach to implementing DesignOps. The structure and scope of a DesignOps practice should be derived from the specific needs and objectives of each organization. However, some common steps to start or improve a DesignOps practice are:

  • Assess the current state of design within the organization. Identify the strengths, weaknesses, opportunities, and threats (SWOT) related to design processes, tools, culture, skills, resources, etc.
  • Define the vision and mission for design within the organization. Articulate what design means for the organization’s success and how it contributes to its goals. Create a clear statement that communicates the purpose and value proposition of design.
  • Prioritize the most critical pain points or opportunities for improvement. Based on the SWOT analysis, select a few areas that have high impact or urgency for addressing with DesignOps solutions.
  • Develop a roadmap for implementing DesignOps solutions. Plan how to tackle each priority area with specific actions, timelines, resources, stakeholders, and metrics.
  • Execute the roadmap with an agile mindset. Implement DesignOps solutions iteratively and incrementally. Test assumptions, gather feedback, measure results, and adjust accordingly.

What are some examples of DesignOps solutions?

DesignOps solutions can vary depending on the context and needs of each organization, but some common examples are:

  • Creating a centralized repository of design assets, guidelines, and best practices that can be easily accessed and updated by all designers and other teams.
  • Establishing a standardized workflow for managing design projects, from ideation to delivery, that includes clear stages, roles, deliverables, tools, and handoffs.
  • Developing a training program for onboarding new designers or upskilling existing ones on relevant skills, tools, processes, and expectations.
  • Setting up a system for measuring and reporting on design outcomes, such as user satisfaction, engagement, conversion, retention, etc.
  • Organizing regular events or activities for fostering a culture of collaboration, learning, innovation, and recognition among designers and other teams.

Conclusion

DesignOps is not just a buzzword, but a valuable practice that can help organizations scale their design capabilities and deliver better user experiences. By applying user-centered and design-thinking methods to their own processes, designers can create more efficient, effective, and enjoyable ways of working together and with others.

......................................................................