Newer posts are loading.
You are at the newest post.
Click here to check if anything new just came in.

October 11 2019


The W3C At Twenty-Five

The W3C At Twenty-Five

The W3C At Twenty-Five

Rachel Andrew

Last week, the World Wide Web Consortium (W3C) celebrated its 25th anniversary and invited folks to share why the open web platform matters to them via the hashtag #WebStories. As I’m both a member of the CSS Working Group at W3C and the representative for Fronteers, I think it’s a good time to explain a bit more about the role of the W3C in the work that we all do.

What Exactly Is The W3C?

On the W3C website, the About page describes the W3C as:

"... an international community where Member organizations, a full-time staff, and the public work together to develop Web standards. Led by Web inventor and Director Tim Berners-Lee and CEO Jeffrey Jaffe, W3C’s mission is to lead the Web to its full potential."

There are links on that page to details of the mission and vision of the W3C, however, the key motivation of the organization is to ensure that the web is for everybody — and on everything.

Access to the web should not be limited by who you are, where you are, or the device you are using.

Who Are The Member Organizations?

A W3C Member is an organization who pays a membership fee to be part of the W3C. At the time of writing, there are 449 members, and you can see the full list here. If you read through this list, you will find that the majority of members are very large companies. Some are names that we as web developers readily recognize: browser vendors such as Google and Mozilla, large internet companies such as Airbnb and Facebook. However, there are members from many different industries. The web touches pretty much every area of life and business, and there are companies doing interesting things in the space that we might not think of as web companies. For example, people working in traditional publishing (a lot of books are formatted using web technologies) and the automotive industry.

What all the members have in common is that the web impacts the work that they do, and they are keen to have a say in the direction things move, and even to play a part in creating and specifying web technologies.

I represent Fronteers (the Dutch organization of web developers) in the W3C. This year, Fronteers took the unusual* step of becoming a W3C Member Organization.

* “Unusual” because they are a voluntary organization representing web developers, rather than a big company representing the interests of a big company.

The Advisory Committee (AC)

Member organizations take part in the business of the W3C by having a vote on various matters. This is organized by the organization’s AC representative whose job it is to ferry information from the W3C to the organization, and also bring the point of view of the organization to relevant topics being discussed at the W3C.

I’m the rep for Fronteers and so I attend two AC meetings a year — and get a lot of emails! On voting matters, I have to find out from Fronteers how they want to vote and then cast the Fronteers vote. In the last year, one important voting matter was the election of Advisory Board (AB) members; Fronteers held an internal vote, and I took the results back to make the official vote at the W3C.

W3C Groups

Most web developers are probably more aware of the W3C working groups than the rest of the organization, as it is through these groups that most of the work we care about goes on. Any member organization can opt people from their organization onto a working group. In addition, the groups may invite certain people (known as Invited Experts) to participate in that group. I was an Invited Expert on the CSS Working Group, and now am part of the group as the representative for Fronteers. In practical terms, my interaction with the CSS Working Group remains the same, however, I now have a role to play in the W3C as a whole as the W3C rep for Fronteers.

There are a large number of working groups, covering a whole range of technologies. These groups typically work on some kind of deliverable, such as the specifications produced by the CSS Working Group. There are also a number of Interest Groups, which allow for the exchange of ideas around particular topics which may also fall partly into the remit of some of the working groups.

The above groups require a significant time commitment and either a W3C membership or Invited Expert status, however, there are a number of Community and Business Groups that are open to any interested person and do not impose a particular time commitment. The Web Platform Incubator Community Group is one such group and has a Discourse forum for the discussion of new web features, and also various proposals on GitHub. Many of these features ultimately become CSS or other language specifications and therefore part of the platform.

Getting Involved And Following Along

In addition to joining a community group, it is worth noting that anyone can become involved in the work of the W3C, i.e. you don’t need to be an Invited Expert, part of a member organization, or have any special qualifications. For example, if you want to know what is happening at the CSS Working Group, you can take a look at our Issues on GitHub. Anyone can comment on these issues to offer new use cases for a feature and can even raise an issue for a feature they feel should be part of a CSS specification.

As with most W3C groups, the CSS WG uses IRC to minute meetings; any discussion on an issue will be posted back to the issue afterward so anyone who is interested can follow along.

A GitHub message auto-generated to link IRC minutes to the issue An example of a message that was auto-generated regarding an issue that had been discussed in a meeting.

If you are keen to know what the wider W3C is doing, then the strategic highlights document is a good place to look. The latest document was produced in September, and exposes some of the key work recently achieved by W3C groups. Scrolling through that document demonstrates the wide range of activities that the W3C is involved with. It is so important for the web community to engage with standards, as we’ve already seen examples in the past of what happens when vendors control the direction of the web.

This history is explained beautifully by Amy Dickens in her post, “Web Standards: The What, The Why, And The How”:

"Without the Web Standards community, browser makers would be the ones making decisions on what should and shouldn’t be features of the world wide web. This could lead to the web becoming a monopolized commodity, where only the largest players would have a say in what the future holds."

My #WebStory

Why does all of this matter to me? One of the reasons I care so much about the web platform remaining open and accessible to new people who want to publish on and build things for the web is because of the route I took to get here.

As mentioned earlier, the W3C is celebrating their anniversary by inviting people to share stories of how they became involved in the web.* In that spirit (and perhaps to encourage Smashing readers to share their stories), here is mine.

* So many folks have already shared their journey on the W3C Blog of how they were first amazed by the web and continue to be in awe of its potential. Join in and share your story!

I had never intended to work with computers. I intended to become a dancer and singer, and I left school at 16 to go to dance college. My father is a programmer, however, so we were fairly unusual at the time as we had a computer in the house by 1985 when I was 10.

As a child, I liked typing in the code of “choose your own adventure” games, which appeared in books and magazines. I liked spotting the strings of text which would then show up in the game I would later play (usually, once my dad had fixed it up) on our Amstrad CPC464. I liked to visit the computer lab at Newcastle University, see the huge computers, and talk to the women who worked on them. Perhaps most importantly (and despite my arty interests), I never grew up thinking I couldn’t use computers. I just wasn’t especially interested.

A book with lines of code intending to be typed out to make a text game The books I copied games out of as a child.

At school, I learned to type on an electronic typewriter, and the only computer in evidence was in the art room that was used for basic drawing applications. As we did have computers at home, I had used them for schoolwork, despite some teachers not being happy about printed essays.

I ultimately left dance and went backstage, working in the West-End of London. Moving lights, automated sets, and show control systems were about to make huge changes to an industry that had seen little change in years. We were seeing the beginnings of that change when I was in the West End; I remember laughing with the crew as we heard news about some show with a “fancy computer system” which had lots of problems that our traditional production didn’t have. None of us could have imagined the changes that were coming.

Then I became pregnant with my daughter and had to leave the theatre. I was good at crewing and loved the theatre, but it was heavy and sometimes dangerous work with unsociable hours — not really a job for someone with a baby. I didn’t know what I would do, but I could type so I thought that perhaps I could type up essays for people. I was upsold to a computer — having gone into PC World looking for a wordprocessor. It was a Packard Bell 486 with a built-in 640×480 screen — a terrible machine that would allow me to either get the sound card working or the modem, but not both at once. I chose the modem and this is where my web story really begins. Even getting this modem working and getting the computer onto the Internet was something of a challenge and, once I did, I went looking for information about… babies.

I didn’t know anything about babies. All my friends were men who worked backstage in theatre. I had no support network, no family around me to help, and so I logged onto ParentsPlace and found people who didn’t mind my questions and were happy to help. At the time, there obviously was no Facebook. This meant that if you wanted to share photos and stories, you built a website. So among the forums about childbirth and toddler tantrums, there were people teaching each other HTML and sharing sets of graphics along with the code to place them. It was like typing out those “choose your own adventure” books again. I was amazed that I didn’t need anyone to fix my code — it just worked!

A screenshot of the 1997 ParentsPlace website Pulled out from the Internet Archive, this was a website named ‘ParentsPlace’ that existed around the time I was pregnant with my daughter. link

Before long, people would pay me to build them a website, and I felt that I should repay at least in some way for all of the questions I had asked. So, I started to answer questions in the forums. That was how it seemed to work. People would learn and move one step up the ladder, the new people would come in with the same questions and the people a step ahead would answer — all the while asking their own questions of those further along. I loved this. I could never have afforded lessons, but I had time. I could help others, and in return, people helped me. I discovered through this that I was quite good at explaining technical things in a straightforward way — an ability I have always accredited to the fact that I struggled to learn these new things myself. It was never easy. I was willing to spend the time, however, and found it interesting.

With my daughter on my knee, I started to teach myself Perl because I didn’t like any of the off-the-shelf guestbooks and wanted to write my own. I installed Linux on a second-hand Compaq, and learned the basics of systems administration, how to compile Apache, wrapped my head round file permissions, and so by the time my daughter was three years old, I got a job heading up a technical team in a property “dot com” company.

I became interested in web standards essentially because it made no sense to me that we would have to build the same website twice — in order that it would work in both browsers. At the time, Dreamweaver was the tool of choice for many web developers, as it made dealing with the mess of nested tables we had to battle with much easier. So, influenced by the work of The Web Standards Project, I (along with my then-boyfriend, now-husband Drew McLellan) began sharing tips and Dreamweaver extensions with the Dreamweaver Usenet group, while all along explaining why web standards were important and showing how to make Dreamweaver support standards.

A screenshot of my bio on the WaSP site retrieved from the Internet Archive My bio on the WaSP site in 2002 — there wasn’t much to say! ( link)

Ultimately, we both ended up on the Macromedia Beta, helping to make Dreamweaver itself more standards-compliant. We were also invited to join the Web Standards Project — specifically to be part of the Dreamweaver Task Force. I couldn’t believe that Jeffrey Zeldman emailed me, asking me to join WaSP! These were the people I looked up to and had learned so much from. The fact that they wanted me to be part of the organization was amazing and gave me so much confidence to continue with the work I was already doing.

That involvement became the bedrock of my career; I realized that my ability to explain technical things could help other web developers learn these new technologies and understand the need for standards. I also discovered that being able to explain things clearly was useful in raising bug reports, and writing up use cases for new software features (in browsers or tools such as Dreamweaver). Two decades after discovering web standards, I am still doing this work. It continues to interest me, and I think it is more important than ever.

The open nature of the web, the relative simplicity of the technologies, and the helpful, sharing attitude of the community is why I am here at all. One of the biggest reasons why I have stayed after all these years is because of Web standards and the continued fight for the open web. That’s why I think that the W3C and the standards process is vitally important, and why I think it so important that web developers get involved in the process, too.

I want to help ensure that the voice of the web developer working on small projects is heard, and that the direction of the web isn’t dictated by a few giant companies. The web is where we have made our careers, and often even our social lives; it is the way that we communicate with each other. I want it to stay a place where I want to be. I want it to remain open enough that the next person without a technical background can pitch up and start publishing and creating, and find it a place they want to establish a career, too.

What’s Your Web Story?

Whether you have been working on the web for over 20 years or only one, please share your stories on the W3C blog, on your own site, or perhaps write up something in the comments section here below. I’d love to hear your journey!

Smashing Editorial(il)

October 10 2019


A Guide To New And Experimental CSS DevTools In Firefox

A Guide To New And Experimental CSS DevTools In Firefox

A Guide To New And Experimental CSS DevTools In Firefox

Victoria Wang

Over the last few years, our team at Firefox has been working on new CSS tools that address both cutting-edge techniques and age-old frustrations. We’re the Layout Tools team, a subset of Firefox Developer Tools, and our quest is to improve the modern web design workflow.

The web has seen an incredible evolution in the last decade: new HTML/CSS features, browser improvements, and design techniques. Our team is devoted to building tools that match that innovation so that designers and developers can harness more of the efficiency and creativity that’s now possible.

In this guide, we’ll share an overview of our seven new tools, with stories from the design process and practical steps for trying out each tool.

Editorial Design Patterns

By naming lines when setting up our CSS Grid layouts, we can tap into some interesting and useful features of Grid — features that become even more powerful when we introduce subgrids. Read related article →

1. Grid Inspector

It all started three years ago when our CSS layout expert and dev advocate, Jen Simmons, worked with members of Firefox DevTools to build a tool that would aid users in examining CSS Grid layouts.

As one of the most powerful new features of the modern web, CSS Grid had quickly gained decent browser adoption, but it still had low website adoption. There’s a steep learning curve, and you still need fallbacks for certain browsers. Thus, part of our goal was to help popularize Grid by giving developers a more hands-on way to learn it.

An example of the Grid Inspector displaying an outline of the grid layout Grid Inspector (Large preview)

The core of the tool is a grid outline, overlaid on the page, which helps devs visualize how the grid is positioning their elements, and how the layout changes when they tweak their styles. We added numbered labels to identify each grid line, the ability to view up to three grids at once, and color customization for the overlays. Recently, we also added support for subgrid, a brand new CSS specification implemented in Firefox and hopefully in more browsers soon.

Grid Inspector was an inspiration for all the tools that followed. It was even an inspiration for a new team: Layout Tools! Formed in late 2017, we’re spread across four time zones and collaborate with many others in Mozilla, like our rendering engine developers and the good folks at MDN.

Try Out The Grid Inspector

  1. In Firefox, visit our Grid example site.
  2. Open the Inspector with Cmd + Shift + C.
  3. Turn on Grid overlay via one of three ways:
  • Layout Panel:
    In the Grid section, check the checkbox next to .content.grid-content;
  • Markup View:
    Toggle the “grid” badge next to <div class="content grid-content">;
  • Rules View:
    Click the button next to display:grid; inside #page-intro .grid-content;
  • Experiment with the Grid Inspector:
    • Change the purple overlay color to red;
    • Toggle “Line numbers” or “Extend lines infinitely”;
    • Turn on more grid overlays;
    • See what happens when you disable grid-gap: 15px in Rules.

    Since Grid, we’ve been seeking to expand on the possibilities of what a browser CSS tool can be.

    2. Shape Path Editor

    The next project we worked on was the Shape Path Editor: our first visual editing tool.

    CSS Shapes allows you to define shapes for text to flow around: a circle, a triangle, or a many-sided polygon. It can be used with the clip-path property which allows you to trim elements to any of those same shapes. These two techniques together open the possibility for some very unique graphic design-inspired layouts.

    However, creating these sometimes complex shapes can be difficult. Typing all of the coordinates manually and using the right CSS units is error-prone and far removed from the creative mindset that Shapes allows. Therefore, we made a tool that allows you to edit your code by directly clicking and dragging shapes on the page.

    This type of feature—visual editing—was new for us and browser tools in general. It’s an example of how we can go beyond inspecting and debugging and into the realm of design.

    Try Out The Shape Path Editor

    1. In Firefox, visit this page on the An Event Apart website.
    2. Open the Inspector with Cmd + Shift + C and select the first circular image.
    3. In Rules, click on the icon next to the shape-outside property.
    4. On the page, click on the points of the shape and see what happens when you drag to make the shape huge or tiny. Change it to a size that looks good to you.

    Visual editing is an example of how we can go beyond inspecting and debugging and into the realm of design.

    3. Fonts Editor

    For years, we’ve had a Fonts panel in Firefox that shows an informative list of all the fonts used in a website. In continuing our theme of designing in the browser, we decided to turn this into a Font Editor for fine-tuning a font’s properties.

    An example of the Fonts Editor index of fonts and variable fonts editing Fonts Editor (Large preview)

    A driving force behind this project was our goal to support Variable Fonts at the same time that the Firefox rendering engine team was adding support for it. Variable Fonts gives font designers a way to offer fine-grained variations along axes, like weight, within one font file. It also supports custom axes, which give both font creators and web designers an amazing amount of flexibility. Our tool automatically detects these custom axes and gives you a way to adjust and visualize them. This would otherwise require specialized websites like Axis-Praxis.

    Additionally, we added a feature that provides the ability to hover over a font name to highlight where that particular font is being used on the page. This is helpful because the way browsers select the font used to render a piece of text can be complex and depend on one’s computer. Some characters may be unexpectedly swapped out for a different font due to font subsetting.

    Try Out The Fonts Editor

    1. In Firefox, visit this variable fonts demo site.
    2. Open the Inspector with Cmd + Shift + C and select the word “variable” in the title (the element’s selector is .title__variable-web__variable).
    3. In the third pane of the Inspector, navigate to the Fonts panel:
    • Hover over the font name Output Sans Regular to see what gets highlighted;
    • Try out the weight and slant sliders;
    • Take a look at the preset font variations in the Instances dropdown menu.

    4. Flexbox Inspector

    Our Grid, Shapes, and Variable Fonts tools can together power some very advanced graphic design on the web, but they’re still somewhat cutting-edge based on browser support. (They’re almost there, but still require fallbacks.) We didn’t want to work only on new features—we were drawn to the problems that most web developers face on a daily basis.

    So we started work on the Flexbox Inspector. Design-wise, this has been our most ambitious project, and it sprouted some new user research strategies for our team.

    Like Grid, CSS Flexbox has a fairly steep learning curve when you first get started. It takes time to really understand it, and many of us resort to trial and error to achieve the layouts we want. At the beginning of the project, our team wasn’t even sure if we understood Flexbox ourselves, and we didn’t know what the main challenges were. So we leveled up our understanding, and we ran a survey to discover what people needed the most when it came to Flexbox.

    The results had a big effect on our plans, making the case for complicated visualizations like grow/shrink and min/max. We continued working with the community throughout the project by incorporating feedback into evolving visual prototypes and Nightly builds.

    The tool includes two major parts: a highlighter that works much like the Grid Inspector’s, and a detailed Flexbox tool inside the Inspector. The core of the tool is a flex item diagram with sizing info.

    An example of the flex item diagram and sizing table Flex item diagram and sizing (Large preview)

    With help from Gecko layout engineers, we were able to show the step-by-step size decisions of the rendering engine to give users a full picture of why and how a flex item ended up with a certain size.

    Note: Learn the full story of our design process in “Designing the Flexbox Inspector”.

    Try Out The Flexbox Inspector

    1. In Firefox, visit Mozilla’s Bugzilla.
    2. Open the Inspector with Cmd + Shift + C and select the element div.inner (just inside the header bar).
    3. Turn on the Flexbox overlay via one of three ways:
    • Layout Panel:
      In the Flex Container section, turn on the switch;
    • Markup View:
      Toggle the “flex” badge next to <div class="inner">;
    • Rules View:
      Click the button next to display:flex.
  • Use the Flex Container panel to navigate to a Flex Item called nav#header-nav.
    • Note the sizes shown in the diagram and size chart;
    • Increase and decrease your browser’s width and see how the diagram changes.

    Interlude: Doubling Down on Research

    As a small team with no formal user research support, we’ve often resorted to design-by-dogfooding: basing our opinions on our own experiences in using the tools. But after our success with the Flexbox survey, we knew we wanted to be better at collecting data to guide us. We ran a new survey to help inform our next steps.

    We crowdsourced a list of the 20 biggest challenges faced by web devs and asked our community to rank them using a max-diff format.

    When we found that the big winner of the challenges was CSS Layout Debugging, we ran a follow-up survey on specific CSS bugs to discover the biggest pain points. We supplemented these surveys with user interviews and user testing.

    We also asked folks to rank their frustrations with browser developer tools. The clear top issue was moving CSS changes back to the editor. This became our next project.

    5. Changes Panel

    The difficulty in transferring one’s work from a browser developer tool to the editor is one of those age-old issues that we all just got used to. We were excited to make a simple and immediately usable solution.

    An example of the diff view provided by the Changes Panel Changes Panel (Large preview)

    Edge and Chrome DevTools came out with variants of this tool first. Ours is focused on assisting a wide range of CSS workflows: Launch DevTools, change any styles you want, and then export your changes by either copying the full set of changes (for collaboration) or just one changed rule (for pasting into code).

    This improves the robustness of the entire workflow, including our other layout tools. And this is just a start: We know accidental refreshing and navigation from the page is a big source of data loss, so a way to bring persistence to the tool will be an important next step.

    Try Out The Changes Panel

    1. In Firefox, navigate to any website.
    2. Open the Inspector with Cmd + Shift + C and select an element.
    3. Make some changes to the CSS:
    • Modify styles in the Rules pane;
    • Adjust fonts in the Fonts pane.
  • In the right pane of the Inspector, navigate to the Changes tab and do the following:
    • Click Copy All Changes, then paste it in a text editor to view the output;
    • Hover over the selector name and click Copy Rule, then paste it to view the output.

    6. Inactive CSS

    Our Inactive CSS feature solves one of the top issues from our layout debugging survey on specific CSS bugs:

    “Why is this CSS property not doing anything?”

    Design-wise, this feature is very simple—it grays out CSS that doesn’t affect the page, and shows a tooltip to explain why the property doesn’t have an effect. But we know this can boost efficiency and cut down on frustration. We were bolstered by research from Sarah Lim and her colleagues who built a similar tool. In their studies, they found that novice developers were 50% faster at building with CSS when they used a tool that allowed them to ignore irrelevant code.

    An example of an inactive CSS tooltip warning Inactive CSS tooltip (Large preview)

    In a way, this is our favorite kind of feature: A low-hanging UX fruit that barely registers as a feature, but improves the whole workflow without really needing to be discovered or learned.

    Inactive CSS launches in Firefox 70 but can be used now in prerelease versions of Firefox, including Developer Edition, Beta, and Nightly.

    Try Out Inactive CSS

    1. Download Firefox Developer Edition;
    2. Open Firefox and navigate to;
    3. Open the Inspector with Cmd + Shift + C and select the center content area, called central-featured;
    4. Note the grayed out vertical-align declaration;
    5. Hover over the info icon, and click “Learn more” if you’re interested.

    7. Accessibility Panel

    Along the way we’ve had accessibility features developed by a separate team that’s mostly one person — Yura Zenevich, this year with his intern Maliha Islam.

    Together they’ve turned the new Accessibility panel in Firefox into a powerful inspection and auditing tool. Besides displaying the accessibility tree and properties, you can now run different types of checks on a page. So far the checks include color contrast, text labels, and keyboard focus styling.

    An example of the Accessibility Panel’s auditing feature Auditing in the Accessibility Panel (Large preview)

    Now in Nightly, you can try the new color blindness simulator which harnesses our upcoming WebRender tech.

    Try Out The Accessibility Panel

    1. Download Firefox Developer Edition;
    2. Navigate to;
    3. In the developer tools, navigate to the Accessibility tab, and click the “Turn on Accessibility Features” button;
    4. Click the drop-down menu next to “Check for issues” and select “All Issues”;
    5. Take a look at the various contrast, keyboard, and text label issues, and click the “Learn more” links if you’re interested.

    Next Up

    We’re currently hard at work on a browser compatibility tool that uses information from MDN to show browser-specific issues for a selected element. You can follow along on GitHub to learn more.

    The Future

    We’re committed to supporting the modern web, and that means continuously changing and growing.

    New specifications get implemented by browser vendors all the time. Guidelines and best practices around progressive enhancement, responsiveness, and accessibility evolve constantly. Us tool makers need to keep evolving too.

    And what of the long-lived, ever-present problems in creating the web? What everyday user interfaces need to be rethought? These are some of the questions that keep us going!

    What about a better way to navigate the DOM tree of a page? That part of DevTools has gone essentially unchanged since the Firebug days.

    We’ve been experimenting with features like back and forward buttons that would ease navigation between recently visited elements.

    A more dramatic change we’re discussing is adding a compact DOM view that uses a syntax similar to HTML templating engines. The focus would be on the most common use case—navigating to CSS—rather than viewing/editing the source.

    A mockup of the simplified HTML Outline View HTML Outline View (Large preview)

    We’ve also been thinking about a better element selector. We know how it can be more productive to work inside the page, with less jumping back and forth into DevTools. We could make the element selector more powerful and more persistent. Perhaps it could select whitespace on a page and tell you what causes that space, or it could shed light on the relationships between different elements.

    A mockup of element overlay with collapsed margin Visual Element Selector (Large preview)

    These are just two of the many ideas we hope to explore further with the help of the community.

    We Need Your Input!

    We want to keep making awesome tools that make your life easier as a developer or designer.

    Here’s an easy way to help: Download Firefox Developer Edition and try using it for some of your work next week.

    Then, tell us what you think by taking our 1-page survey.

    We’re always interested in hearing ideas for improvements, particularly any low-hanging fruit that could save us all from some regular frustration. We do our work in the open, so you can follow along and chime in. We’ll keep you updated at @FirefoxDevTools.

    Thanks to Patrick Brosset for his contributions to this article.

    Smashing Editorial(dm, il)

    October 09 2019


    How To Use Breadcrumbs On A PWA

    How To Use Breadcrumbs On A PWA

    How To Use Breadcrumbs On A PWA

    Suzanne Scacca

    I’ve seen a lot of questions about whether or not breadcrumbs are necessary for PWAs. It makes sense why the question is raised. After all, PWAs have an app shell and sticky menu, so shouldn’t it be easy for users to move around it without a secondary navigation?

    It’s not as simple as that.

    Because PWAs often straddle the line between website and native app, navigation isn’t always minimized — especially if you’re building large e-commerce stores or blogs. Plus, don’t forget that breadcrumbs aren’t just for navigation. They’re often used to show progress.

    So, today, we’re going to look at how to design breadcrumbs for PWAs and some interesting use cases where they come in handy.

    Will PWAs Replace Native Mobile Apps?

    When it comes to the mobile user experience, are mobile websites all that bad? You hear so much about the benefits of building a dedicated native app, but that can become an incredibly costly gamble if users don’t take to it. Read related article →

    One of the reasons we build PWAs instead of websites is because they offer a better mobile experience. But that doesn’t mean you can strictly rely on your visitors to use the navigation to get around. In some cases, they’re going to need a bit of hand-holding.

    Breadcrumbs are a great way to step in and say:

    Did you go too far? Let us help you backtrack a step or two.

    Yankee Candle shows us one way this can be done:

    Yankee Candle breadcrumbs navigation Yankee Candle displays a breadcrumbs navigation as visitors move deeper through its candle inventory and categories. (Source: Yankee Candle) (Large preview)

    Or your breadcrumbs might be saying:

    Not sure how much further you have to go (or how much more you can take)? Here are your remaining steps.

    The checkout process can certainly get tiresome on mobile when it’s broken into multiple steps. That’s why breadcrumbs progress bars like the one Cort uses are so helpful.

    Cort breadcrumbs for progress Customers looking to rent furniture from Cort are taking through a multi-step checkout process with breadcrumb dots indicating progress. (Source: Cort) (Large preview)

    These aren’t the only ways you can use breadcrumbs to improve the visitor experience with a PWA. Here are some other use cases you can take advantage of:

    1. Enhance e-Commerce Search

    If you’re building a large e-commerce PWA with multiple hierarchies or categories of products, breadcrumbs are 100% necessary.

    There’s just no room on mobile to display that sort of deep navigation without driving your shoppers mad.

    Breadcrumbs also make it easier for shoppers to see the steps they’ve taken, so they can determine how far back they need to skip.

    For example, let’s say someone were shopping for a new moisturizer on the Lancôme PWA:

    Lancôme PWA breadcrumbs trail The Lancôme PWA uses breadcrumbs to help shoppers backtrack more easily. (Source: Lancôme) (Large preview)

    But let’s say they were looking for something they could wear during the day and hadn’t paid enough attention to the name of the product before clicking on it. Breadcrumbs, then, allow them to go to the exact spot they need to be (i.e. “Moisturizers”) to find the right category (“Day Creams”).

    This type of breadcrumbs navigation becomes especially important the deeper the navigation goes.

    Just be careful.

    Although Yankee Candle has an example of what to do above, if you pry deeper into its inventory, you’ll find that it’s breadcrumbing is somewhat compromised:

    Yankee Candle offscreen breadcrumbs As visitors go deeper into Yankee Candle’s store, the breadcrumbs go offscreen. (Source: Yankee Candle) (Large preview)

    You might not be able to tell from the screenshot above, but the breadcrumbs go offscreen. And if you can’t tell that, then the visitors of the PWA aren’t going to be able to tell that either.

    The extra breadcrumbs do exist. They just require visitors to scroll to the right to find them:

    Yankee Candle breadcrumb scroll Yankee Candle adds a scroll to its breadcrumb trail. (Source: Yankee Candle) (Large preview)

    Realistically, this could cause problems for visitors who are familiar with scrolling, but not with having to scroll individual elements like a breadcrumbs navigation.

    One thing that Yankee Candle has done well in this example is that it’s preserved the size of its breadcrumbs so that they remain readable and clickable. That’s something that doesn’t always happen if you add a wrap function to the navigation.

    I’ll show you why the matter of size might come up when you’re designing this element.

    This is the Bed Bath & Beyond website:

    Bed Bath & Beyond’s oversized breadcrumbs Bed Bath & Beyond’s breadcrumbs take up about a quarter of the mobile web page. (Source: Bed Bath & Beyond) (Large preview)

    This is certainly a neat way to design your breadcrumbs, especially since the last crumb enables users to dig even deeper to categories like:

    • Casual Dinnerware,
    • Fine China,
    • Charger Plates.

    Once the visitor selects one of the products, they’re shown a standard plain-text breadcrumbs along the top of the page. That said, this in-between “Dining | Dinnerware | Dinnerware Sets” breadcrumbs trail takes up nearly a quarter of the page. It doesn’t totally compromise the shopping experience, but it might cause undue irritation since visitors have to do a lot of scrolling to see each of the available dinnerware sets now.

    Your best bet? Visitors know to look for breadcrumbs in e-commerce, whether it’s on desktop, mobile or PWA. So, don’t try and get creative with it. Place them where they belong (i.e. just under the header) and use uniform typography. If your breadcrumbs have a tendency to run on the long side, you can wrap them or, better yet, reduce how many are displayed at once.

    In the Yankee Candle example above, this is what visitors see when they scroll the full width of the breadcrumb:

    Home / Seasonal Candles / Fall Candles / Fall Jar Candles / Sweet Maple Chai Large Fall Jar Candles

    This is what it could be instead:

    Seasonal Candles / Fall Candles / Fall Jar Candles

    There’s really no need to include the “Home” attribute as everyone knows the logo points there. And there’s no need to spell out the name of the product since it’s right below the breadcrumb. When you do this for your PWA, just remember to trim it back so that only the essentials appear.

    2. Improve the Browsability of Blogs

    When someone reads a blog from the comfort of their desktop or laptop, they usually have the convenience of a sidebar that shows them other recent or relevant articles. On mobile, though, that’s impossible. Instead, they have to:

    • Scroll to the bottom of the post and see if related links are available there,
    • Use the blog’s search function (if there is one),
    • Or go to a relevant category or date using breadcrumbs.

    Scrolling isn’t ideal, especially if your readers don’t always get through the full post. Search would be fine, but it requires them to have a very clear idea of what they’re looking for. Breadcrumbs, on the other hand, provides some context about what they’re reading as well as guidance for what else they can find.

    The Cooking Light blog handles this well:

    Cooking Light content The Cooking Light blog uses a simplified breadcrumbs to help users find related content. (Source: Cooking Light) (Large preview)

    Let’s say a visitor lands on the Cooking Light home page and sees this article about measuring how much pumpkin comes in a can. They click on it and find it a worthwhile read.

    Now, someone who clicks on an article like this is likely to be a novice cook, so they’d most definitely be interested in picking up other beginner tips and insights. That’s why Cooking Light’s breadcrumb is so useful. This could’ve ended up being something like this:

    Home > Cooking > Thanksgiving > Pies > Pumpkin Pie

    Instead, the article was properly and simply categorized so that the kinds of readers it attracts can find other useful and relevant content.

    While you might be tempted to categorize blog posts a different way, it can over-complicate the breadcrumbs. Case in point, this is how the Transportation Security Administration (TSA) does theirs:

    TSA blog breadcrumbs The TSA designs its blog breadcrumbs using dates (years and months). (Source: TSA) (Large preview)

    In the example above, you can see that the breadcrumbs are nothing more than a breakdown of the publication date. Unless you have visitors constantly searching for time-sensitive information instead of valuable guides, this type of breadcrumb isn’t going to work very well.

    Another thing I want to mention is that the inclusion of the title in the breadcrumbs is unnecessary. It’s nothing more than a duplication of the blog post title that appears directly below it. What’s more, the length of the title forces the breadcrumbs to wrap and take up more space than it needs to.

    Simpler is always better, especially if the goal of the breadcrumbs is to help visitors read more of your blog content. You can use my tip from #1 about shortening your breadcrumbs to fix this issue.

    3. Make It Easier to Get Help

    One of the cool things about building products for the web is that it allows us to sell exponentially more than we could if we had to constantly stock a physical inventory. But that doesn’t release us from the responsibility of supporting our products. When you build a piece of software, you better be there to help customers with it.

    That said, a lot of the problems SaaS users run into are commonplace and can easily be answered with a support portal. That way, you empower users to look up answers to their own problems and avoid clogging up your support queue. It’s a win-win for both sides.

    Now, support portals are a lot like blogs in that they can be tough to get around if you don’t have the convenience of a sidebar or search bar to show you the way. Even if those elements are present, it’s still nice to have additional context as you go deeper and deeper into the support archives.

    For instance, this is FreshWorks’ Freshsales CRM support portal:

    Freshsales support portal breadcrumbs The Freshsales support portal always keeps breadcrumbs at the top of the page for reference. (Source: FreshWorks) (Large preview)

    There is a ton of documentation in this support portal. It would be silly not to have a breadcrumbs navigation available at the top of the page. And like the blog breadcrumbs examples, this one helps users in two ways.

    It’s useful for backtracking, for one. It’s also helpful for users that are trying to learn a lot more about the same subject. By providing this level of support, your users will learn how to master your product more easily and be more likely to renew their subscriptions at the end of the term.

    Another software that uses breadcrumbs in its support section is Calendly:

    Calendly support breadcrumbs Calendly includes too many attributes in its support breadcrumbs navigation. (Source: Calendly) (Large preview)

    Notice how the name of the page and category of support topics is present just below the search bar. Now, look at the attributes included in the breadcrumbs:

    Help Center > Calendly > Getting Started > Getting Started

    None of these belong here except “Help Center”. Anyone who’s landed on this page knows that the support topic pertains to the product (Calendly). And they’re also going to see the page title is “Getting Started”, so the duplication of it here is of no help.

    Really, the breadcrumbs shouldn’t even come into play until they dig deeper in the navigation. Even then, I don’t know if it’s necessary since the title is always present at the top of the page.

    When building out your own SaaS support portal, really think about what belongs in the breadcrumbs and what doesn’t. If it’s a simple enough self-support system, you might not need it at all.

    4. Improve Conversions with Progress Bars

    When you give your PWA visitors a multi-step process to work through — be it an e-commerce checkout, quiz, questionnaire and so on — don’t leave them wondering whether it’s worth it to finish.

    Now, that doesn’t mean you need to overwhelm them with a long form that appears all at once — that could just as well hurt your conversion rate. It’s completely fine to break longer processes into multiple steps. Just remember to use progress bar breadcrumbs to split them up.

    This is something that’ll be especially useful in hospitality as the CitizenM reservation form demonstrates:

    CitizenM progress bar breadcrumbs When booking a reservation at the CitizenM hotel, visitors see exactly how much more work is ahead of them with breadcrumbs. (Source: CitizenM) (Large preview)

    These breadcrumbs serve two purposes:

    1. Visitors can see how much work is actually involved in the process.
    2. They can use them to backtrack if they need to change a response.

    This can make what might otherwise seem like a never-ending booking process more manageable. But that doesn’t mean that breadcrumbs, as a whole, always contribute to higher conversions.

    Part of the reason the breadcrumbs example above works so well is because it’s well-labeled and simplified. When you remove the transparency and logic from breadcrumbs progress bars, though, they can end up harming your conversion rates.

    For example, Ipsy is a monthly makeup subscription service. In order to get started, visitors to the PWA must fill out this quiz:

    Ipsy quiz with breadcrumbs Ipsy requires new users to fill out a beauty quiz before they can subscribe. (Source: Ipsy) (Large preview)

    While the design of the quiz is certainly attractive, is it necessary to have built it this way, especially since there are 12 pages that require two clicks or more on each page? That comes to at least 24 clicks in total (one or more for the answer and one for the “Next” button).

    That doesn’t even include filling out the subscription form!

    That said, the breadcrumbs progress bar is there to show potential customers how much more work is to be done. However, there’s no transparency over what each of those pages involves. In fact, most of them are much longer than this first one, asking for things like favorite name brands, types of makeup they like, how frequently they wear it, etc.

    In the end, it’ll probably take five minutes or more to complete the quiz and I don’t think the progress bar does any good in demonstrating that fact.

    Bottom line: If you want to get visitors to the point of conversion more quickly, design it that way. And if it does require some work on their part, be honest about how much work there is. Don’t mask it with breadcrumbs.

    5. Make Directories Easier to Explore

    Thankfully, directories no longer live inside of massive phone books or travel guides. We now digitize those directories for quicker and more convenient consumption.

    That said, online directories are a lot like big data. Now that they’re on the web, there’s almost too much information to sift through. And while most PWAs give visitors the ability to filter and sort their results, that doesn’t necessarily help with moving around the PWA itself.

    What you need for that is breadcrumbs.

    You’ll find a nice example of this on the OpenTable PWA:

    OpenTable location breadcrumbs OpenTable displays location breadcrumbs to users as they search for and book reservations. (Source: OpenTable) (Large preview)

    There are hundreds of thousands of restaurants using OpenTable as their reservation system — and from locations all over the world.

    While it might not be totally necessary to show breadcrumbs, especially if users know exactly which city they want to dine in, it’s a nice touch. It serves as a quick reminder to users that this is the location they’re searching in. If they change their mind and want to try the next town over, all it takes is a click back to the state or province to change their response.

    TripAdvisor is another massive directory site, this one storing massive amounts of data on locations, places to stay, things to do, etc. There’s just so much going on inside this PWA that there’s no way to get by without breadcrumbs:

    TripAdvisor PWA breadcrumbs The TripAdvisor travel directory PWA uses breadcrumbs to break down the attributes of a search. (Source: TripAdvisor) (Large preview)

    In this example, you can see how deep and specific the breadcrumbs attributes get:

    Things to Do > Tickets & Tours > Water Sports > Hanauma Bay Snorkeling Service

    This is useful for visitors that may have stumbled upon a particular activity or location, but, upon inspecting the breadcrumbs, realize there’s a different way to go.

    For instance, let’s say someone gets to this page and starts wondering what other kinds of tours they can do in Hawaii. So, rather than restart their search (which they’d have to do if they landed on the page from the home page), they can use the breadcrumbs to backtrack.

    That said, this is another one of those examples of putting too much into the breadcrumbs. There’s no need to include the name of the activity or location unless there are sub-categories beneath it. It only makes the breadcrumbs run past the width of the page, which can be distracting (and annoying).

    Again, it’s a good idea to keep breadcrumbs as simple as possible when you can.

    6. Convert Anchor Tags into Breadcrumbs

    Earlier, I talked about how breadcrumbs can be used as progress bars on PWAs. What if we were to use them for a similar purpose, but this time to represent the anchor tags on a page?

    It’s really no different than what developers do when they build a navigation into the top of a single-page website. The only difference is that the anchor tags from your page will be represented by breadcrumbs as a secondary navigation.

    And if you’re publishing lengthy articles or guides on your PWA, this is something to seriously think about.

    Here’s one example from the WebMD website:

    WebMD breadcrumbs navigation for anchor tags WebMD turns its anchor tags into a sort of breadcrumbs navigation. (Source: WebMD) (Large preview)

    The WebMD PWA allows visitors to check their symptoms or look up medications they’re taking. As you might imagine, these pages can go on and on for a while.

    Rather than force visitors to scroll through them, WebMD attaches this secondary navigation to the bottom of its header. As visitors scroll past the corresponding anchor tag and section, it gets highlighted in the breadcrumbs. Users can also use the breadcrumbs to quickly move around the page without having to scroll.

    Airbnb does something similar:

    Airbnb breadcrumbs navigation Airbnb creates a breadcrumbs navigation from its anchor tags. (Source: Airbnb) (Large preview)

    Airbnb could easily just leave its visitors to scroll through the page to try to pull out the details most relevant to them. Instead, it’s chosen to display a breadcrumbs navigation (built from the page’s anchor tags).

    This makes it easy for them to see which section they’re in and then bounce around as they like to pick up the details they need to make their decision.

    I know it’s not necessarily a common use of breadcrumbs, but I expect this one to appear more and more as the web shifts over to PWAs.

    Wrapping Up

    We’ve seen a lot of examples of PWAs now to know what good and bad breadcrumbs look like. Let’s sum up the basic rules:

    • Always place the breadcrumbs as close to the top of the page as possible. If the header is present, it goes directly below. If it’s not, it should take the top spot.
    • Use unique separators. The most common ones are the Guillemet (>), slash (/) and the pipe (|).
    • Build enough padding around the separators so it’s clear where the attributes start and end.
    • Make sure clickable links in breadcrumbs are big enough to tap. At minimum, they should be 1 cm x 1 cm.
    • Be careful with color. You don’t want breadcrumbs to distract from the content of the page. That said, they should at least change color or become underlined upon hover.
    • Simplify the attribute labels as much as possible.
    • Don’t include the name of the post, page, product, etc. in the breadcrumbs if it’s clearly visible on the page. “Home” probably doesn’t need to be there either.
    • If the breadcrumbs tend to run past the width of the page, wrap the text only if it doesn’t compromise clickability. It’s really best to display only the last few attributes/links.

    There’s a lot you can do with breadcrumbs on PWAs and, if handled well, can help you increase your conversion rate. Just be careful with them. If they’re included without just cause or they present more work to your visitors, it’s best to just do without them.

    Smashing Editorial(ra, yk, il)

    October 08 2019


    Developing A Custom Plugin For October CMS

    Developing A Custom Plugin For October CMS

    Developing A Custom Plugin For October CMS

    Andriy Haydash

    Last year, I did some research about new CMS systems in PHP in order to find a good alternative to WordPress. Ideally, it had to be an open-source solution with a clean and modern codebase.

    One of them caught my interest: October CMS. I tried it and almost instantly liked it. The code structure was really nice and it was easy to write custom plugins.

    This article aims to give you an overview of what to expect from the platform and give you a taste of it before you decide to commit to using it.

    Why Choose October As Your CMS Platform?

    There are a few main reasons why I have personally decided to use it for my projects.

    Powered By Laravel

    October is built on top of the most powerful PHP framework for creating modern web apps: Laravel. I can say with great confidence that it’s the best. It is very easy to use and understand, and has all the features that a modern framework needs, from routing, object-relational mapping (ORM), authorization, caching, and many others that provide a nice and clear MVC structure. As it is powered by Laravel, October has inherited all those features from its big brother.

    Clean Code And Documentation

    Unlike many other CMS solutions, October has a very clean and well-documented codebase. It’s written in using an objectoriented paradigm. Instead of plain old PHP, October uses Twig as its templating engine, which simplifies things for developers. Technical documentation is also well written, and helps you quickly find answers to most of your questions.

    Great Community

    Even though October’s community is not yet that big, it’s very helpful and responsive. There is a public Slack channel you can join, where you’ll find developers happy to assist you in fixing your issue.

    Big Marketplace

    Like WordPress and other CMSes, October has a marketplace for themes and plugins. Even though there aren’t that many good themes to choose from, there are over 700 plugins right now, so it’s very likely you’ll be able to add functionality by simply searching for and installing one of them. A great feature of plugins is that they can be easily synchronized between all your projects if you just add your project ID in the admin dashboard.

    PlugIns And Components

    Plugins are a foundation of adding new functionality to October. A plugin can consist of multiple files and directories that are responsible for registering custom components, models, updating database structure, or adding translations.

    A plugin is usually created in the plugins/ directory of the project. Since many plugins are submitted to the marketplace for others to use, each plugin should have a custom namespace, which usually starts with the name of the company or developer that created the plug-in. So, for instance, if your name is Acme and you’ve created an awesome plugin called Blog, your plugin will live under the namespace of Acme\Blog.

    Let me show you how a plugin directory structure might look like:

    Sample plugin directory structure Sample plugin directory structure (Large preview)

    As you can see, there is also a file called plugin.php that is responsible for registering a plugin and all of its components in October CMS.

    Another important thing to mention is that not all directories listed above are necessary for a plugin to run. Your plugin could have the following structure and still work perfectly well:

    Simple plugin directory structure Simple plugin directory structure (Large preview)

    Most often, one plugin is built to add only one piece of functionality. For example, the ‘Translate’ plugin is designed to help you translate content on your website into different languages, and provide the multi-language support for the users.

    October CMS has a great marketplace where you can find for your needs.

    October marketplace October marketplace (Large preview)

    Unlike WordPress and other popular CMSes, October plugins can also have components. According to October’s documentation, components are “configurable building elements that can be attached to any page, partial or layout.” Examples might include: a contact form, navigation, a list of FAQs and their answers; basically anything that it makes sense to bundle together as one building block that can be reused on multiple pages.

    Components are created as a part of a plugin and they exist in the components/ subdirectory:

    Component directory structure Component directory structure (Large preview)

    Each component has a PHP file like componentName.php that defines the component, as well as an optional subdirectory for component partials. A component partials folder must have the same name in lowercase as the component itself.

    To demonstrate how a component functions, let’s assume that our component is responsible for showing blog posts.

    namespace Acme\Blog\Components;
    class BlogPosts extends \Cms\Classes\ComponentBase
        public function componentDetails()
            return [
                'name' => 'Blog Posts',
                'description' => 'Displays a collection of blog posts.'
        // This array becomes available on the page as {{ component.posts }}
        public function posts()
            return ['First Post', 'Second Post', 'Third Post'];

    As we can see, the component has two main functions. The first one, componentDetails(), provides information about the component to the administrator who will add and use components on their web pages.

    The second function, posts(), returns dummy posts that can then be used inside a component partial (blogposts/default.htm file) like this:

    url = "/blog"
    {% for post in blogPosts.posts %}
        {{ post }}
    {% endfor %}

    For October CMS to know our component exists, we must register it using our main plugin file inside a function named registerComponents():

    public function registerComponents()
        return [
            'October\Demo\Components\Todo' => 'demoTodo'

    Creating A Custom Contact Form plugin

    We’re going to create a custom contact form plug-in. Here are the assumptions about how the plugin should work:

    • The form will have the following fields: First Name, Last Name, Email, Message.
    • Data will be submitted to the server using Ajax.
    • After data is submitted, the admin will receive an email with the message sent by the user.

    For the purpose of this tutorial we will use a fresh installation of October CMS:

    Default view after fresh installation Default view after fresh installation (Large preview)

    Let’s start creating our plugin by running a command in a terminal that will generate the plugin structure: php artisan create:plugin progmatiq.contactform

    Creating a new plugin from terminal Creating a new plugin from terminal (Large preview)

    The progmatiq.contactform argument contains the name of the author (progmatiq) and the name of the plugin (contactform).

    New plugin folder structure New plugin folder structure (Large preview)

    Now we need to open our plugin.php file and modify the plugin details in the following method:

    public function pluginDetails()
            return [
                'name'        => 'Contact Form',
                'description' => 'A simple contact form plug-in',
                'author'      => 'progmatiq',
                'icon'        => 'icon-leaf'

    Here are a few other methods that you should take a look at:

    • registerComponents()
      Here you can define an array of components that your plugin provides.
    • registerPermissions()
      You can register custom permissions that you can then use later in other areas of the application.
    • registerNavigation()
      You can add a custom menu item with a URL to your admin dashboard menu.

    Now let’s create our ContactForm component:

    1. Make a new folder named components/ inside your plug-in’s root directory.
    2. Create a file named contactForm.php inside the components/ folder.
    3. Creating a new component Creating a new component (Large preview)
    4. Paste the following code that will tell October what our component does. We can do it by creating a method inside our component called componentDetails().
    namespace Progmatiq\Contactform\Components;
    use Cms\Classes\ComponentBase;
    class ContactForm extends ComponentBase
        public function componentDetails()
            return [
                'name' => 'Contact Form',
                'description' => 'A simple contact form'

    Now we need to register our component inside the plug-in. To do that, we modify the registerComponents() method:

        public function registerComponents()
            return [
                'Progmatiq\Contactform\Components\ContactForm' => 'contactForm',

    This function returns an array of components that our plugin provides. The component’s full class name is a key in this method, and a value is an alias that we’ll use to reference our component inside our Twig templates.

    Once we have registered the component, we can create a new contact page and add our component (numbers in the steps refer to the screenshot):

    1. In your admin dashboard go to CMS (1) > Pages (2) and click on + Add (3).
    2. Give your page a name and a URL (4).
    3. Name your file (5) and select the default layout (6).
    Creating a contact page Creating a contact page (Large preview)

    Let’s add our new component to the page:

    1. Click on Components in the left menu (1) and then select our “Contact Form” component. Once you click on it (2), it should be added to the page.
    2. We need to place a piece of code that would give our page a headline as well as render the component using the {% component ‘contactForm’ %} Twig directive:
    <div class="container">
        <h1> Contact </h1>
        {% component 'contactForm' %}
    Adding contact form component to contact form page Adding contact form component to contact form page (Large preview)

    If you open your contact page right now, you will see the headline saying “Contact” and nothing else.

    Contact page Contact page (Large preview)

    That’s because our contact form doesn’t have any HTML to render.

    We need to create a contactform/default.htm file inside our components/ folder.

    Adding a html view to our component Adding an HTML view to our component (Large preview)

    And add the following HTML code to the file:

    <form method="POST" 
        data-request-success="this.reset(); alert('Thank you for submitting your inquiry')"
            <label for="first_name">First Name</label>
            <input type="text" name="first_name" class="form-control">
            <p data-validate-for="first_name" class="text-danger"></p> 
            <label for="last_name">Last Name</label>
            <input type="text" name="last_name" class="form-control">
            <p data-validate-for="last_name" class="text-danger"></p> 
            <label for="email">Email</label>
            <input type="text" name="email" class="form-control">
            <p data-validate-for="email" class="text-danger"></p> 
            <label for="content">Content</label>
            <textarea rows="6" cols="20" name="content" class="form-control"></textarea>
            <p data-validate-for="content"  class="text-danger"></p> 
            <button type="submit" class="btn btn-primary" data-attach-loading>Send</button>

    Most of this code is pretty straightforward. However, it is flavored with special data-* attributes that October allows us to use:

    1. <form> tag has three special attributes:
      • data-request="onSend". This attribute tells October that the onSend function from our component (that we’re going to create next) has to be called when the form is submitted using Ajax.
      • data-request-validate will enable form Ajax validation using errors that will be sent from the server if the form is invalid.
      • data-request-success="this.reset(); alert('Thank you for submitting your inquiry')" clears the form and then triggers the alert message if the request was successful and no validation or server-side errors were present.
    2. Every input has a following block that is responsible for displaying validation errors returned by the server for that given input:
    3. <p data-validate-for="content"  class="text-danger"></p>
    4. The submit button has the data-attach-loading attribute, which will add a spinner and disable the button while the request is being processed by the server. This is done in order to prevent the user submitting a form again until the previous request is complete.

    And here is how our page looks now:

    Contact page view Contact page view (Large preview)

    Let’s go back to our contactForm.php component and create the onSend() as well as validate() helper method that will be responsible for handling form submission:

    public function onSend()
            // Get request data
            $data = \Input::only([
            // Validate request
            // Send email
            $receiver = '';
            \Mail::send('', $data, function ($message) use ($receiver) {
        protected function validate(array $data) 
            // Validate request
            $rules = [
                'first_name' => 'required|min:3|max:255',
                'last_name' => 'required|min:3|max:255',
                'email' => 'required|email',
                'content' => 'required',
            $validator = \Validator::make($data, $rules);
            if ($validator->fails()) {
                throw new ValidationException($validator);

    The first thing we’re doing is getting data from the request and validating it using the validate() helper method. (All the available validation rules you can use can be found in the documentation.) If validation fails, the validate() method will throw the ValidationException an exception and code execution will stop, and the server will respond with status code 406 and with validation messages.

    If validation succeeds, then we will send an email to our admin.

    Note: For simplicity, I’ve assumed that the email we want to send the submission to is Make sure to use your own email!

    Here is the full code of your contactForm.php plug-in:

    namespace Progmatiq\Contactform\Components;
    use Cms\Classes\ComponentBase;
    use October\Rain\Exception\ValidationException;
    class ContactForm extends ComponentBase
        public function componentDetails()
            return [
                'name' => 'Contact Form',
                'description' => 'A simple contact form'
        public function onSend()
            // Get request data
            $data = \Input::only([
            // Validate request
            // Send email
            $receiver = '';
            \Mail::send('', $data, function ($message) use ($receiver) {
        protected function validate(array $data) 
            // Validate request
            $rules = [
                'first_name' => 'required|min:3|max:255',
                'last_name' => 'required|min:3|max:255',
                'email' => 'required|email',
                'content' => 'required',
            $validator = \Validator::make($data, $rules);
            if ($validator->fails()) {
                throw new ValidationException($validator);

    As you can see, the first argument that the Mail::send() function accepts is the name of the email template that will be rendered for the email body. We need to create it in the admin panel. Go to Settings > Mail Templates and click on the New Template button. Then fill out the form as it is shown on the screen below:

    Adding new email template Adding new email template (Large preview)

    Here is the body of the email that we’re going to be using:

    You have received a new contact inquiry
    **First Name**:
    {{ first_name }}
    **Last Name**:
    {{ last_name }}
    {{ email }}
    {{ content }}

    Now save the email template. The next thing we need to do is configure the SMTP server that will send emails.

    Go to Settings > Mail Configuration and fill out all the settings.

    Email server configuration Email server configuration (Large preview)

    Obviously, I won’t share my personal configuration. Use your own settings. 😉

    At this stage we have everything ready to start testing our contact form component.

    First, let’s check if validation works when we leave the “Content” field empty and input an invalid email:

    Contact form validation Contact form validation (Large preview)

    Validation works as expected. Let’s now input correct data and see if the email will be sent successfully to our admin.

    Here is the email that will receive:

    Contact form submission email Contact form submission email (Large preview)

    After the form is submitted successfully, the user will see an alert message informing him that the operation was successful:

    Successful submission of contact form Successful submission of contact form (Large preview)


    In this tutorial, we’ve covered what a plugin and a component are and how to use them with October CMS.

    Don’t be afraid to create a custom plugin for your project if you can’t find an existing one that fits your needs. It’s not that difficult and you have full control over it, and you can update or extend it at any time. Even creating a simple contact form plugin like we’ve done today can be useful if you want to then integrate it with other services like Mailchimp or HubSpot.

    I hope this tutorial was helpful to you. If you have any questions, don’t hesitate to ask in the comments section below.

    Smashing Editorial(dm, yk, il)

    October 07 2019


    Design Systems Are About Relationships

    Design Systems Are About Relationships

    Design Systems Are About Relationships

    Ryan DeBeasi

    Design systems can be incredibly helpful. They provide reusable elements and guidelines for building a consistent “look and feel” across products. As a result, users can take what they learned from one product and apply it to another. Similarly, teams can roll out well-tested patterns for navigation or reviews, making products more trustworthy. Effective design systems solve boring problems in a repeatable way so that developers and designers can focus on solving novel problems.

    Yet when someone uses the term “design system” in a meeting, I’m never quite sure what reaction to expect. I’ve seen curiosity and excitement about trying a new way of working, but I’ve also seen frustration and concern at the idea of a system limiting designers’ creativity. Some designers argue that design systems sap creativity, or that they are solutions in search of a problem. Design systems can fragment over time, causing teams to stop using them.

    Design systems aren’t going away, though. Just 15% of organizations lacked a design system in 2018, according to one survey. That’s down from 28% the previous year. Some teams use large, general-purpose design systems such as Google’s Material Design, while others use smaller, more bespoke systems such as REI’s Cedar and Mozilla’s Protocol.

    Design systems should empower teams, not limit them. For that to happen, we need to start thinking more holistically. A design system isn’t just code, or designs, or documentation. It’s all of these things, plus relationships between the people who make the system and the people who use it. It includes not just CSS files and Sketch documents, but also trust, communication, and shared ownership. As it turns out, there’s a whole field of study dedicated to exploring systems like these.

    Grid of icons including stars, a shopping cart, and a snowflake In REI’s Cedar Design System, icons are tailored to the company’s outdoor gear business. The snowflake icon indicates ski and snowboard services, and the ruler icon indicates a size chart. (Large preview)

    The Big Picture

    A 1960 paper titled “Socio-technical systems” explored the interactions among technology, humans, and the larger environment in which they exist. Enid Mumford explained that researchers began by investigating how to build better relationships between managers and employees, but by the 1980s, they were focused on making work more efficient and cost-effective. In 2011, Gordon Baxter and Ian Sommerville wrote that this research helped inspire user-centered design, and that there’s a lot of work left to do.

    Baxter and Sommerville argued that today, there is still a tension between “humanistic” research, which focuses on employees’ quality of life, and “managerial” research, which focuses on their productivity. They also explained that it’s important to consider both technology and human interactions: “system performance relies on the joint optimization of the technical and social subsystems.”

    I’d argue that design systems are socio-technical systems. They involve interactions between the people who create the system, the people who create products using the system, and the end users who interact with these products. They also evoke the same tension between efficiency and humanism that Baxter and Sommerville saw.

    Design systems aren’t composed just of images and code; they involve conversations among designers, developers, product managers, CEOs, and random people on GitHub. These interactions occur in various contexts — a company, an open-source community, a home — and they happen across cultures and organizational boundaries. Building a team can mean bringing together people from disciplines such as animation, sound design, data visualization, haptics, and copywriting. Creating a successful design system requires equal parts of technical expertise and soft skills.

    And yet, peruse design or engineering news aggregators and you’re likely to see a distinct focus on that “technical subsystem” — code and tools, rather than people and conversations. Which creative tool is the best at keeping track of design tokens? What JavaScript technologies should be used for building reusable components — React, web components, or something else? Which build tool is best?

    The answer to these questions is, of course, “it depends!” Who will design, build, and use the system? What are their needs? What constraints are they operating under? What tools and technologies are they comfortable with? What do they want to learn?

    To answer these sorts of questions, Baxter and Sommerville recommend two types of activities:

    • Sensitisation and awareness activities
      Learning about the varied people who will create and participate in the system, and sharing that information far and wide.
    • Constructive engagement
      Communicating across roles, building prototypes, and considering both the technical and social parts of the system.

    Digging In

    In early 2019, I was part of a team — let’s call them “team blue” — that was building a design system for a large organization. I facilitated informal chats with this team and “team green”, which was using the design system to build a web application. Every couple of weeks, we got all the developers and designers together around a table and talked about what we were building and what problems we were trying to solve. These chats were our “sensitization and awareness activities.”

    We didn’t have permission to make our design system public, so we did the next best thing: we treated it like a small open-source project within the organization. We put the code in a repository that both teams could access and asked for contributions. Team blue was responsible for reviewing and approving these contributions, but anyone on either team could contribute. Team blue was also building an application of their own, so in a sense, they were both users and custodians of the design system.

    These interactions helped the teams build better products, but just as importantly, they established trust between the teams. Team blue learned that folks were using the system thoughtfully and building clever new ideas on top of it. Team green learned that the system really was tailored to their needs, so they could work with it instead of against it. Baxter and Sommerville might call this work “constructive engagement.”

    We found that both teams were under pressure to learn new technologies and deliver a complete product quickly. In other words, they were already operating under a pretty considerable cognitive load. As a result, the two teams agreed to focus on making the system easy to use. That meant sidestepping the whole web components debate, focusing mostly on CSS, and ensuring that our documentation was clear and friendly.

    Screenshot of links to Windows, Web, iOS, and Android documentation Microsoft’s Fluent Design System targets four very different platforms. (Large preview)

    Putting It All Together

    Organizations of all sizes create reusable design elements to help teams build more consistent, elegant applications. Different organizations’ needs and dynamics are expressed in their design systems. Here are just a few examples:

    • Google’s Material Design has several implementations in different frameworks and languages. It’s used by a variety of people inside and outside of Google, so it has comprehensive documentation and a variety of toolkits for design apps.
    • Microsoft’s Fluent Design System targets four very different platforms. Like Material, it includes toolkits for UX designers and comprehensive documentation.
    • Mozilla’s Protocol is implemented in Sass and vanilla JavaScript. It has a strong focus on internationalization. Alex Gibson says that this system helps Mozilla “create on-brand web pages at a faster pace with less repetitive manual work.”
    • REI’s Cedar is built with Vue.js components and can’t be used with other JavaScript frameworks. Cedar is used primarily by REI’s internal developers and is closely tied to the company’s brand. The design system’s code is open source, but its fonts are not.
    • Salesforce’s Lightning Design System is a JavaScript-agnostic CSS framework. It can optionally be used alongside the Lightning Component Framework, which includes two JavaScript implementations: one using web components and another using Salesforce’s proprietary Aura framework.
    • Red Hat’s PatternFly was created to provide a consistent user experience across the company’s cloud platform products, so it has a relatively high information density and includes a variety of data visualization components. The PatternFly team recently switched from Angular to React after some experimentation with web components. PatternFly also includes a JavaScript-agnostic implementation using HTML and CSS. (Full disclosure: I’m a former Red Hatter.)
    • IBM’s Carbon Design System offers implementations in React, Vue, Angular, and vanilla JavaScript as well as a design toolkit for Sketch. The Carbon team is experimenting with web components. (Hat tip to Jonathan Speek for tracking down that repository.)

    Systems like these are consistent and reliable because people from different teams and roles worked together to build them. These systems solve real problems. They’re not the result of developers trying to impose their will upon designers or vice-versa.

    Josh Mateo and Brendon Manwaring explain that Spotify’s designers “see their role as core contributors and co-authors of a shared system — one that they have ownership of.” Mina Markham describes herself as “the translator between engineering and design” on the Pantsuit design system. Jina Anne digs into the team dynamics and user research behind design systems: “Spoiler alert! You’re going to need more than just designers.”

    Let’s Build Some Stuff!

    Now that we’ve gone through research and some examples, let’s talk about how to build a new design system. Start by talking to people. Figure out who will be using and contributing to your design system. These people will probably span a variety of disciplines — design, development, product management, business, and the like. Learn about people’s needs and goals, and ask them to share what they’re working on. Consider planning an informal meeting with snacks, coffee, or tea to create a welcoming atmosphere. Establish regular communication with these folks. That might mean joining a shared chat room or scheduling regular meetings. Keep the tone casual and friendly, and focus on listening.

    As you talk about what you’re working on, look for common problems and goals. You might find that teams need to display large amounts of data, so they’re investigating tools for displaying tables and generating reports. Prioritize solutions for these problems.

    Look also for repeated patterns and variations on similar themes. You might find that buttons and login forms look a bit different across teams. What’s the significance of these variations? What variations are intentional — for example, a primary button versus a secondary button — and what variations have happened by accident? Your design system can name and catalog the intentional patterns and variations, and it can eliminate the “accidental” variations.

    Screenshot of five different button styles IBM’s Carbon Design System lists all the variations of its components. (Large preview)

    The goal here is to establish a rapid feedback loop with people who are using the design system. Faster feedback and smaller iterations can help avoid going too far in the wrong direction and having to dramatically change course. P.J. Onori calls these sudden, large changes “thrash.” He says that some thrash is good — it’s a sign that you’re learning and responding to change — but that too much can be disruptive. “You shouldn’t fear thrash,” he says, “but you need to know when it’s useful and how to help mitigate its downsides. One of the best [ways] to mitigate the downsides of thrash is to start small — with everything.”

    Consider starting small by setting up a few basic elements:

    • A version control system to store your code. GitHub, GitLab, and Bitbucket are all great options here. Make sure that everyone who uses the system can access the code and propose changes. If possible, consider making the code open source to reach the widest possible audience.
    • CSS code to implement the system. Use Sass variables or CSS custom properties to store “design tokens” — common values such as widths and colors.
    • A package.json file that defines how applications can build and install the design system.
    • HTML documentation that demonstrates how to use the design system, ideally using the system’s own CSS.

    The node-sass documentation for the CSS framework Bulma describes these steps in a bit more detail. You can skip installing and importing Bulma if you’d like to start from scratch, or you can include it if you’d like to start off with some of the basics in place.

    You might have noticed that I didn’t mention anything about JavaScript here. You might want to add this element eventually, but you don’t need it to get started. It’s easy to go down a rabbit hole researching the best and newest JavaScript tools, and getting lost in this research can make it harder to get started. For example, “5 Reasons Web Components Are Perfect For Design Systems” and “Why I Don’t Use Web Components” both make valid points, but only you can decide what tools are right for your system. Starting with just CSS and HTML lets you gather real-world feedback that will help you make this decision when the time comes.

    As you release new versions of the system, update your system’s version number to indicate what has changed. Use semantic versioning to indicate what’s changed with a number like “1.4.0.” Increment the last number for bug fixes, the middle number for new features, and the first number for big, disruptive changes. Keep communicating with the folks who use the design system, invite feedback and contributions, and make small improvements as you go. This collaborative, iterative way of working can help minimize “thrash” and establish a sense of shared ownership.

    Finally, consider publishing your design system as a package on npm so that developers can use it by running the command npm install your-design-system. By default, npm packages are public, but you can also publish a private package, publish the package to a private registry, or ask developers to install the package directly from a version control system. Using a package repository will make it easier to discover and install updates, but installing directly from version control can be an easy short-term solution to help teams get started.

    If you’re interested in learning more about the engineering side of things, Katie Sylor-Miller’s Building Your Design System provides a fantastic deep dive. (Full disclosure: I’ve worked with Katie.)

    Wrapping Up

    Design systems are made up of code, designs, and documentation as well as relationships, communication, and mutual trust. In other words, they’re socio-technical systems. To build a design system, don’t start by writing code and choosing tools; start by talking to the people who will use the system. Learn about their needs and constraints, and help them solve problems. When making technical, design, or strategy decisions, consider these people’s needs over the theoretically “best” way to do things. Start small, iterate, and communicate as you go. Keep your system as simple as possible to minimize thrash, and invite feedback and contributions to establish a sense of shared ownership.

    By giving equal weight to engineering and interpersonal considerations, we can get the benefits of design systems while avoiding the pitfalls. We can work in a way that’s efficient and humane; we don’t have to choose one over the other. We can empower teams rather than limiting them. Empowered teams ultimately help us better serve our users — which, after all, is why we’re here in the first place.

    Further Reading on SmashingMag:

    Smashing Editorial(ah, il)

    October 04 2019


    Editorial Design Patterns With CSS Grid And Named Columns

    Editorial Design Patterns With CSS Grid And Named Columns

    Editorial Design Patterns With CSS Grid And Named Columns

    Rachel Andrew

    Many websites, in particular those which display long-form content, have a fairly straightforward repeating pattern of components: a full-width area for images, a central content area, and perhaps a split view of two half-width blocks. These components repeat to display an article, images and other related content — with content editors selecting the right component as they create articles for publication.

    In this article, I’m going to demonstrate an approach to this kind of editorial design, which builds on a few techniques some of which are discussed in the following articles:

    In addition to this being a nice way to name sections of your layout, this technique exposes a whole bunch of interesting things about Grid Layout which you may find useful in creating your own layout patterns. It also demonstrates more of the promise of subgrid (a part of the upcoming Level 2 of the grid specification and being implemented in Firefox).

    Naming Things In CSS Grid Layout

    When using CSS Grid Layout, you can name lines and areas. Both of these things can make working with Grid — especially complex grids — more straightforward. Defining naming conventions for things in your layout can be useful when working with your team; it is much easier to understand where anything placed with grid-area: content will end up than having something placed from column-line: 3 / 9.

    When using the grid-template-areas approach, you give the items that you want to place on the grid a name by using the grid-area property and then placing them around the grid. In the following example, the item with grid-area: content goes into the grid area defined by the grid-template-areas property:

    See the Pen [Layout With Named Area]( by Rachel Andrew.

    See the Pen Layout With Named Area by Rachel Andrew.

    This works well for components where you have one item to go into one area; however, if you want to place multiple things into the content area (one below the other), using grid-area is the wrong approach. Instead, you might define names for the column lines and place the item from the start to end line.

    See the Pen [Layout With Named Columns]( by Rachel Andrew.

    See the Pen Layout With Named Columns by Rachel Andrew.

    This isn’t as neat, however, when using the grid-area approach we have to know both the start and end line when placing an item using grid-column or grid-row — or do we?

    Take a look at this next CodePen example. My items are placed using a single name or ident by using the grid-column property, even though some of the grid areas being targeted cross a number of columns:

    See the Pen [Layout with Named Columns]( by Rachel Andrew.

    See the Pen Layout with Named Columns by Rachel Andrew.

    My aim here is to abstract away the complexity of the grid setup when actually using the grid. I can put a lot of work into creating the initial grid, but then place things without thinking too much about it as I populate my pages. I also want to make sure that we can repeat the components as often as we need to as we build up the article. What I have in mind is a content creator using a CMS, and creating blocks of content using the different patterns whilst knowing that they will be placed correctly one below the other on the overall grid.

    In order to understand how I got to this point requires an understanding of a few things about CSS Grid Layout as well as named lines and areas.

    We Can Name Lines

    As you’ve already seen in my second example above, we can name lines on the grid that can be pretty much anything we like — other than the word span. The name is an ident rather than a string which is why it is not quoted.

    However, you will see many examples where the naming conventions name-start and name-end are used that append -start onto the name of the start line and -end on the name of the end line. This is not purely convention and for the technique I am going to show you why we need to name our lines this way. So you should pick a name for the area you are describing, and then add the -start and -end suffixes — which need to match, of course!

    We name our lines inside square brackets. Lines can (and often need to) have multiple names. In this case, space separates the names. When placing the items using line-based positioning, you can pick any name for the line to do the placement.

    With our named lines in place, we could place our items using grid-column by specifying the start and end line name. This pattern is just the same as using line numbers, so the name before the slash is the start line and the name after is the end line.

    See the Pen [Example using start and end lines]( by Rachel Andrew.

    See the Pen Example using start and end lines by Rachel Andrew.

    This places the items but isn’t the neat single name per item that I used in the example. However, we now have everything in place due to the special way that Grid handles named areas and lines.

    Line Names Give Us A Named Area

    Assuming you have named your lines with -start and -end as I have, Grid will give you a named area of the main name you used. Therefore, in my case, I have areas named content, start-half, end-half, full and center. Each of these areas is a single row (as I don’t have named rows), however, it will span the column tracks from the -start to the -end line.

    Named Areas Give Us A Named Line Of The Main Name Used

    If we want to be able to place our items as if we have a column name, we also need to make use of the fact that when we create a grid area, we get a line name of the main name used; that is, the main name being the name with -start and -end removed. This line name resolves to the start or end of the area depending on whether we are targeting grid-column-start or grid-column-end.

    So, we have an area named content, because we have column lines named content-start and content-end. The area named content also gives us the ability to use grid-column-start: content which will resolve to the start line of that content area, while grid-column-end: content will resolve to the end line of the content area.

    This, therefore, means that we can place an item into the content area by using the following:

    .content {
        grid-column: content / content;

    Next, we can now tidy up this technique further due to the fact that if you use a named line for grid-column-start and omit the end line (rather than spanning one track as would be the case if you used line numbers), grid copies the name over to the end line. Therefore, grid-column: content is exactly the same as grid-column: content / content;

    This is then all we need to be able to place items using grid-column with a simple, single name. This behavior is all exactly as specified and not some kind of “hack”. It demonstrates the depth of thinking that went into the creation of the Grid Layout specification, and the amount of careful work that has gone into making it so straightforward to lay items out in our designs.

    Giving This Technique Superpowers With Subgrid

    I think this technique is a nice one that enables a very straightforward way of declaring where elements should be placed on the grid. However, if we add subgrid support to the mix, it becomes very powerful indeed.

    Currently, subgrid is being implemented in Firefox, and so these next examples require Firefox Nightly to run. You can download Nightly here.

    The subgrid value of grid-template-columns and grid-template-rows means that sizing created on a parent grid can be opted into by an item which is a child of the grid (assuming it is also using grid layout) by having display: grid applied.

    Note: You can read more about the features of subgrid in my articles here on Smashing Magazine “CSS Grid Level 2: Here Comes Subgrid” and “Digging Into The Display Property: Grids All The Way Down”.

    Line Names From The Parent Are Passed Into Subgrids

    In addition to the track sizing information being passed into the child grid, any line names set on the parent will be passed in. This means that we can use our “column names” within subgridded components, making this solution very useful in a world where subgrid exists. An item placed in content — even if nested down inside subgrids — will line up with one placed as a direct child of the main grid.

    In this next example, I have nested two elements directly inside the div with a class of full-2. I have also placed a ul inside .content. If we look at the items inside full-2, in order to place these on the parent grid, we need to make the selector full-2 a grid with display: grid then use the grid-template-columns property with a value of subgrid.

    This causes the grid on .full-2 to use the tracks defined on the parent grid, and have access to the named lines defined there. As this is a full-width item, this really will behave just like the parent grid in terms of placing our items. We can then use any of the names we defined for the different columns to place the items. In this case, I have set both child elements to grid-column: center and they display one after the other in that center area.

    .full-2 {
      grid-row: 4;
      grid-column: full;
      display: grid;
      row-gap: 10px;
      grid-template-columns: subgrid;
    .full-2 > div {
      background-color: rgb(124,222,220);
      grid-column: center;
    A set of boxes, one with other boxes nested instead The nested elements line up with the grid on the parent (Large preview)

    If we take a look at our nested ul inside .content, we will need to create a subgrid on the selector .content just as with the last example; when we do this, the ul falls into the first track of the subgrid. If we want to lay out the listen items on the subgrid, we need to do two things: cause the ul to take up the same area as its parent by placing it with grid-column: content, and then making it a grid which is a subgrid.

    Having done this the list items will lay out using auto-placement into the column tracks of the subgrid:

    .content {
      grid-row: 1;
      grid-column: content;
      display: grid;
      grid-template-columns: subgrid;
    .content ul {
      grid-column: content;
      display: grid;
      row-gap: 10px;
      grid-template-columns: subgrid;
    A set of boxes, the nested boxes falling into the tracks of the grid With auto-placement the items fall into the tracks of the parent (Large preview)

    Once you have your grid, you can use the names from the parent in exactly the same way as before.

    .content li:nth-child(1) {
      grid-column: center;
    .content li:nth-child(2) {
      grid-column: start-half;
    .content li:nth-child(3) {
      grid-column: end-half;
    .content li:nth-child(4) {
      grid-column: content;
    Screenshot of various boxes, which line up in columns The completed subgrid layout (Large preview)

    If you have Firefox Nightly, you can see the full demo in this CodePen example:

    See the Pen [Naming Column and Subgrid]( by Rachel Andrew.

    See the Pen Naming Column and Subgrid by Rachel Andrew.

    You can keep “nesting’ subgrids into your markup structure like this, and each time the line names will be passed through. This is a feature that I think will be particularly useful.

    When you create a subgrid, the line numbers correspond to the lines of the subgrid and not the parent grid. Therefore, if you do want to ensure that elements in the subgrid line up with the parent grid, then using line names or named areas (as shown in this example) will make that straightforward and logical.

    Wrapping Up

    You now know how to use this technique for your main grid, and hopefully, it won’t take too long before we start seeing support for subgrid in all browsers. It’ll enable techniques such as this one and make it incredibly powerful for us to use.

    Smashing Editorial(il)

    October 03 2019


    Inspired Design Decisions: Bea Feitler, An Unstoppable Creative Force

    Inspired Design Decisions: Bea Feitler, An Unstoppable Creative Force

    Inspired Design Decisions: Bea Feitler, An Unstoppable Creative Force

    Andrew Clarke

    Even if you didn’t study graphic design at art school, you might know a few famous names. With over a century of commercial art direction, there are plenty more names to discover. People who have done astonishing work which can encourage and inspire us to think about the web more creatively.

    Discovering people with incredible talent has been one of the most rewarding aspects of studying art direction. Learning about one designer often leads me to another, and when I find someone who’s work I admire, I want to understand not just what they made, but why they made it.

    Previously On “Inspired Design Decisions”

    1. Inspired Design Decisions: Avaunt Magazine
    2. Inspired Design Decisions: Pressing Matters
    3. Inspired Design Decisions: Ernest Journal
    4. Inspired Design Decisions: Alexey Brodovitch

    After learning about Alexey Brodovitch’s influential work on Harper’s Bazaar until the 1950s, I wanted to know the impact his legacy had on the magazine. This led me to Bea Feitler and her creative partner Ruth Ansel who directed Harper’s Bazaar throughout the 1960s.

    Feitler has been described as “the pioneering female art director you’ve never heard of.” I’ve never heard her mentioned at a design conference or seen her referenced in an article about web design.

    But, Feitler’s confident and energetic designs are only part of what makes her life and work fascinating. Even more important was how her work reflected changes in society in America during the 1960s and the choices she made to influence it.

    Only one exhibition has been staged about her work and one retrospective book published. “O Design de Bea Feitler,” written by her nephew, was published in her native Brazil in 2012. It took me months to track down a copy, but eventually, I found one. It’s the most expensive book I’ve bought.

    Feitler has as much to teach people who design for the web as she did the magazine designers who followed her. I hope that in some small way, I can help people fall in love with Bea Feitler’s work the way I did.

    Inspired By Bea Feitler

    Portrait of Bea Feitler by Bob Richardson, during the 1960s. Portrait of Bea Feitler by Bob Richardson, during the 1960s. (Large preview)

    Bea Feitler was born in Rio de Janeiro in 1938. After working on album covers, book jackets, magazines, and poster designs, she left Brazil and moved to Manhattan. In 1961 — and still only 25 years old — she became an art assistant, then one of the youngest and first female co-art directors at Harper’s Bazaar alongside Ruth Ansel.

    Just like Alexey Brodovitch — who’d stepped down from Harper’s Bazaar before her move to the United States — Feitler’s collaborations with artists and photographers helped define her work. At Harper’s Bazaar, Richard Avedon’s photograph of model Jean Shrimpton in her famous pink space helmet, then Annie Leibovitz’s naked John Lennon on the cover of Rolling Stone.

    Although Feitler never met Brodovitch, it’s fascinating to see how she respected then developed his legacy. Feitler understood that magazine pages should be deliberately and individually constructed, yet at the same time should be connected to one another to form a harmonious rhythm.

    A selection of magazine covers with art direction by Bea Feitler. From left: Harper’s Bazaar, MS., Rolling Stone, and Vanity Fair. (Large preview)

    A magazine should flow. It should have rhythm. You can’t look at one page alone, you have to visualize what comes before and after. Good editorial design is all about creating a harmonic flow. — Bea Feitler

    Feitler combined Brodovitch’s mastery of the double-page spread with her choices of bold colors which were inspired by pop artists Jasper Johns, Roy Lichtenstein, and Andy Warhol, as well as street fashion and youth culture.

    She wasn’t afraid to experiment with color or to break with conventions, twice placing lurid green text onto a neon pink background, first for a Harper’s Bazaar cover in April 1965 and later for feminist magazine Ms. in December 1972.

    Harper’s Bazaar, February 1967. Art direction by Bea Feitler. (Large preview)

    At the Harper’s Bazaar studio she shared with Ruth Ansel, a continually changing collage filled their inspiration wall; something I wish I had space for in my tiny studio. Feitler wasn’t afraid to mix media, and when she felt that one of her most iconic spreads wasn’t working, she combined one of Avedon’s most well-known photographs with a panel from a comic book she’d bought from a newsstand in the street below.

    Harper’s Bazaar, August 1966. Photography by Hiro. Art direction by Ruth Ansel and Bea Feitler. Their confident choices of color and strong shapes have inspired much of my recent work. (Large preview)

    Feitler’s designs influenced and reflected the changes in American society in the 1960s. The magazines she art directed had a fast-paced, almost cinematic quality which perfectly suited the culture of the time but is also relevant to our work online today. Feitler believed that good editorial design is about creating a harmonious flow. This is as relevant to designing engaging user experiences and customer journeys as it is magazine pages.

    Some of my favourite Feitler designs have neither color nor images, like this typographic spread from Harper’s Bazaar. (Large preview)

    Even though some people continue to recite the mantra that the web isn’t print, there’s a lot we can learn from Feitler’s work. Her designs can help us improve not only editorial design online but e-commerce websites and digital product designs too.

    Feitler said that a book was “50/50 image to text.” On the web, we need to allow for interactive features and video too. Understanding how to successfully combine these components to create a consistent, engaging experience is a fundamental skill which every digital designer should develop.

    As a mentor and teacher, Feitler shared many principles with Alexey Brodovitch. She encouraged her students to develop their own direction, and many themselves became prominent art directors. Feitler was demanding and accepted nothing less than the very highest standards of design excellence from everybody.

    Hold on to your passions and dig deep while trusting your instincts. Step outside of what is expected. Embrace accidents, and know that eventually you will discover the perfect solution to a creative dilemma and be very joyous while doing it. — Ruth Ansel

    Sadly, Bea Feitler died from cancer in 1982 aged just 44. I believe she has as much to teach those of us who design for the web as she did the magazine art directors who followed her. I hope her life and work will influence us to have courage in our convictions and make our own brave and confident choices.

    Beauty Blast Off

    Harper’s Bazaar, April 1965. Model: Jean Shrimpton. Photographer: Richard Avedon.Harper’s Bazaar’s hadn’t had a guest editor before, but for its April 1965 edition, long-time collaborator Richard Avedon edited and photographed the entire issue.

    Inside, Avedon photographed Donyale Luna — the first black woman to be featured on the cover of a mainstream fashion magazine — and Paul McCartney wearing a spacesuit borrowed from NASA. For the cover, Avedon chose an image of contemporary supermodel Jean Shrimpton wearing a space helmet which had been made by one of New York’s most famous milliners.

    Avedon later recalled that at 11 PM — after their deadline had passed — the photograph he’d shot for the cover wasn’t working. So, Feitler cut the shape of a helmet from pink Day-Glo paper and placed it over Avedon’s photograph. No focus groups, no research, no audience testing, just a gutsy and intuitive design decision.

    The result was a cover which went on to win the New York Art Director's Club medal and was placed at number fifteen in the American Society of Magazine Editor’s 2005 list of Top 40 Magazine Covers.

    5050 Image To Text

    Agneta Darin. Spread from Harper’s Bazaar, August 1966. Photography by Hiro. Art direction by Bea Feitler and Ruth Ansel Agneta Darin. Spread from Harper’s Bazaar, August 1966. Photography by Hiro. Art direction by Bea Feitler and Ruth Ansel. (Large preview) This design uses a CSS background-image gradient and the picture element This design uses a CSS background-image gradient and the picture element. (Large preview)

    To implement my first Feitler-inspired design, my aim is to use the most minimal set of structural elements; a header plus main and aside elements for content. My header contains the split image of an iconic Volkswagen Beetle and a headline which includes an inline SVG Volkswagen logo. As this headline contains no text, I use an ARIA label to describe it. This will help people who use assistive technologies:

      <h1 aria-labelledby="Volkswagen logo">

    For smaller screens, I need only foundation styles as the normal flow, handles my single column layout. First, I add a linear gradient behind the header image. Gradients are incredibly flexible, but despite their usefulness they’re surprisingly under-used:

    header {
    padding: 1rem 2vw;
    background-image: linear-gradient(
    to right,
    #444 0%,
    #444 50%,
    #fff 50%,
    #fff 100%);
    text-align: center; }

    My gradient starts on the left with a dark grey and ends on the right with white. Without color stops, the result would be a smooth gradient between those colors, but I want a hard line in the center of my header. To achieve this effect, I place two color stops at the same 50% position. To change the direction of my gradient, I needn’t adjust those percentages. I can simply change the gradient direction from to right to to left.

    Left: My gradient starts on the left. Right: I change the direction without altering my percentage color stops. Left: My gradient starts on the left. Right: I change the direction without altering my percentage color stops. (Large preview) When you use images to add drama, make sure their effect is dramatic on all screen sizes. Shrinking a landscape image to fit a portrait orientation decreases its visual weight and impact. When you use images to add drama, make sure their effect is dramatic on all screen sizes. Shrinking a landscape image to fit a portrait orientation decreases its visual weight and impact. (Large preview)

    It’s important to maintain a consistent balance of visual weight while adapting designs to several size screens. I don’t want my header image so tall it pushes my running text off the first screen, so I set a maximum height of 75vh or three quarters the height of a small screen:

    header img {
    max-height: 75vh; }

    To complete my small screen design, I establish the header as a positioning context. Then, I absolutely position the Volkswagen emblem and ensure its width will adapt to the screen by using a viewport width unit of 5vw:

    header {
    position: relative; }
    h1 {
    position: absolute;
    top: 1rem;
    left: 1rem;
    width: 5vw; }

    My portrait orientation image fits well into tall screens, but I need a wider format image for screens which are wider than they are tall. Orientation is a fabulous, but seldom used media query which tests the orientation of a viewport. This media query can be used in stylesheets as an alternative to more conventional width queries. It can also be applied to the source of a picture element. This query swaps my portrait image for a landscape alternative whenever width exceeds height, whether on a small phone or desktop size display:

    <source srcset="landscape.png"
    media="(orientation: landscape)">
    <img src="portrait.png" alt="Volkswagen Beetle">

    For my alternative landscape design, I use Grid to place the header, main, and aside elements. There are several options for placing these elements — including columns and rows, and template areas — but I’ve chosen to use grid-template-columns to define a symmetrical two-column grid on the body. I apply the linear gradient again and set its minimum height to the match the full viewport:

    @media screen and (orientation: landscape) {
    body {
    display: grid;
    grid-template-columns: [main] 1fr [aside] 1fr;
    min-height: 100vh;
    background-image: linear-gradient(
    to right,
    #444 0%,
    #444 50%,
    #fff 50%,
    #fff 100%); }

    In landscape orientation, my header fills the entire width of the screen. As I no longer need the linear gradient background image on this element, I can simply remove it:

    header {
    grid-column: 1 / -1;
    background-image: none; }

    Now, because this grid is so simple, I place my main and aside elements onto the grid using named lines:

    main {
    grid-column: main; }
    aside {
    grid-column: aside; }

    The end result is a design which adapts its layout depending on whether a browser or device screen is in landscape or portrait orientation.

    Comic Book Art

    Comic Book ArtBea Feitler regularly combined photographs with illustrations, and comic book art appears in work throughout her career.

    For Harper’s Bazaar, she placed one of Avedon’s photographs of Jean Shrimpton wearing a spacesuit onto a comic book background. Later, she commissioned legendary comic artist Marie Severin to create this cover for Ms. Magazine in 1973.

    Emphasize Scale

    The Foot and the Ferrari.' Spread from Harper’s Bazaar, March 1967. Photography by Bill Silano. Art direction by Bea Feitler and Ruth Ansel. 'The Foot and the Ferrari.' Spread from Harper’s Bazaar, March 1967. Photography by Bill Silano. Art direction by Bea Feitler and Ruth Ansel. (Large preview) This design, inspired by 'The Foot and the Ferrari.' uses a CSS background-image gradient and the object-fit property. This design, inspired by 'The Foot and the Ferrari.' uses a CSS background-image gradient and the object-fit property. (Large preview)

    The Volkswagen Beetle was a small car with a big personality. I want my next design to have a character to match. The large screen design uses an enormous picture of the Beetle’s wheel to emphasize the smallness of that little car. But, before I get to large screens, I want to make sure I maintain a similar contrast in scale on small screens.

    Three structural elements make up the markup I need to implement this design; a header for the large wheel picture, a figure which contain the smaller image of the car, and a main for my running text. As the header has no meaning for anyone who uses a screen reader, I choose to hide it by using an aria-hidden attribute:

    <header aria-hidden="true">
    <img src="header.png" alt="">
    <img src="figure.png" alt="Volkswagen Beetle">

    Foundation styles and normal flow take care of most aspects of my small screen design, but that doesn’t mean I can ignore what makes it the overall concept distinctive; the contrast between the large wheel and the small Volkswagen. To ensure my header always occupies one-third of the viewport height with identical whitespace between it and my content, I use viewport height units for both height and margin:

    header {
    margin-bottom: 33vh;
    height: 33vh; }
    This wheel is easily distorted, giving the Beetle an unintentional flat tyre. Right: Using object-fit restores the roundness of my wheel. This wheel is easily distorted, giving the Beetle an unintentional flat tyre. Right: Using object-fit restores the roundness of my wheel. (Large preview)

    One problem I often encounter when developing flexible layouts is the unintentional resizing of images. With a fixed height on my header and 100% width on its image, the giant wheel can distort. Fortunately, there’s a way to preserve its aspect ratio using the object-fit property. There are four possible options, plus none:

    1. contain
      Preserves an image’s aspect ratio while fitting inside a parent’s content box.
    2. cover
      Preserves an image’s aspect ratio but this time fills the whole box. When this happens, parts of the image outside the content box will be hidden.
    3. fill
      An image will be distorted so its width and height match its parent.
    4. scale-down
      Similar to contain, reduces the size of an image or video to fit inside its parent.
    Left–right: contain, cover, fill, and scale-down. The object-position property often goes hand in hand with object-fit. It allows precise positioning of an element within its parent’s content box. Left–right: contain, cover, fill, and scale-down. The object-position property often goes hand in hand with object-fit. It allows precise positioning of an element within its parent’s content box. (Large preview)

    I want my large wheel to fill the header completely without altering its aspect ratio. I’m also not concerned some parts of the image will be clipped, which makes cover the right choice for object-fit:

    header img {
    object-fit: cover;
    object-position: center bottom;
    width: 100%;
    height: 100%; }

    Now the wheel image is in position, I provide scale by contrasting its large size with a small image of the whole car. I restrict the Beetle’s maximum size to half the viewport width and centre it horizontally using its margins:

    figure {
    margin: 0 auto;
    max-width: 50vw; }

    This design uses a solid grey background to represent the road, so I add a background color and move the figure down by 10px, so the Beetle’s wheels sit firmly on the tarmac:

    main {
    padding: 2rem;
    background-color: #f0f0f1; }
    figure {
    transform: translateY(10px); }

    Bigger screens provide an opportunity to make a big impression, and for this design, I want the header image to occupy half the width and the full height of a large screen. I apply the same 6+4 compound grid I’ve used for many designs in this series. It has eight columns to which I add three rows. I give the middle and bottom rows a fixed height and allow the first row to occupy all remaining vertical space:

    @media screen and (min-width : 64em) {
    body {
    display: grid;
    grid-template-columns: 2fr 1fr 1fr 2fr 2fr 1fr 1fr 2fr;
    grid-template-rows: 1fr 155px 155px;
    grid-column-gap: 2vw; }

    I want the body to always fill the full viewport height, so I apply a minimum height of 100vh and use a linear gradient to create the illusion of a road:

    body {
    min-height: 100vh;
    background-image: linear-gradient(
    to top,
    #f0f0f1 0%,
    #f0f0f1 155px,
    #fff 155px,
    #fff 100%); }

    Using line numbers, I place the header on the grid, so it occupies half the columns and all the rows. The alignment of the small figure places it at the end of its grid module. Then, the main forms a single narrow column of running text:

    header {
    grid-column: 5 / -1;
    grid-row: 1 / 4;
    margin-bottom: 0;
    height: auto;
    background-color: #444; }
    figure {
    grid-column: 1 / 4;
    grid-row: 2;
    align-self: end;
    max-width: auto; }
    main {
    grid-column: 4;
    grid-row: 1 / 3;
    align-self: center;
    background-color: transparent; }
    In this alternative design, I preserve the difference in scale between both pictures across fluid screen sizes using CSS Grid. In this alternative design, I preserve the difference in scale between both pictures across fluid screen sizes using CSS Grid. (Large preview)

    Knowing how scale influences someone’s understanding of a story is essential to telling it well. Sheer size is rarely enough on its own, so to make a significant impact, largeness must be relative to the size of other elements.

    Bea Feitler understood scale and used it well. She often contrasted large foreground elements with smaller ones in the background to create designs which contained incredible depth. We can now follow in her footsteps by using scale to add impact to product and websites designs.

    Confident Color Choices

    Bea Feitler’s confident choice of colors was one of the hallmarks of her work, and it attracted me immediately. For my next Feitler-inspired design, I contrast a deep red with a vibrant yellow and reverse those colors on both sides of the design.

    Left: Spread from Harper’s Bazaar, August 1966. Photography by Hiro. Art direction by Ruth Ansel and Bea Feitler. Right: This design uses CSS Grid and Flexbox. Left: Spread from Harper’s Bazaar, August 1966. Photography by Hiro. Art direction by Ruth Ansel and Bea Feitler. Right: This design uses CSS Grid and Flexbox. (Large preview)

    While this page is big on color, it is also small on markup. I need just two structural elements; a header and main. Inside both are a figure and a division:


    Background and text colors are the starting point for implementing this design. I can leave everything else to the normal flow:

    body {
    background-color: #ba0e37;
    color: #f8d72e; }
    main {
    background-color: #f8d72e;
    color: #272732; }
    I change the layout across screen sizes while maintaining a constistent look and feel. I change the layout across screen sizes while maintaining a constistent look and feel. (Large preview)

    For medium-size screens, I want the figures and divisions inside my header and main to occupy half the height and width of any viewport, so I apply a symmetrical two-column grid and a minimum height:

    @media screen and (min-width : 48em) {
    header, main {
    display: grid;
    grid-template-columns: 1fr 1fr;
    min-height: 50vh; }

    I place the header’s figure in the second column and the division in the first. Because this is the opposite of the content order, I need to assign both to the same row to avoid one column dropping below the other:

    header figure {
    grid-column: 2;
    header div {
    grid-column: 1;
    grid-row: 1; }

    The main element’s figure and division follow the content order, so I needn’t specify a grid-row for them:

    main figure {
    grid-column: 1;
    align-self: end; }
    main div {
    grid-column: 2; }

    I want to fill screens with color from edge to edge. For larger screens, I apply asymmetrical two-column grid which extends the full height of my body:

    @media screen and (min-width : 64em) {
    body {
    display: grid;
    grid-template-columns: 1fr 1fr;
    min-height: 100vh; }

    In this large-screen design, the figure and division in my header and main stack vertically instead of horizontally. I change the display property from grid to flex and set the direction to column. But, the visual order of the main is opposite to its content order, so I change its direction from column to column-reverse:

    header, main {
    display: flex;
    flex-direction: column; }
    main {
    flex-direction: column-reverse; }

    Then, to improve the readability of my running text, I use multi-column layout and specify a column width of 18em. A browser will generate as many columns of that width as will fit inside its parent element:

    main div {
    column-width: 18em;
    column-gap: 2vw; }

    Large blocks of solid color can be tiring for the eye, so I want to break them up by adding a playful, repeating background image pattern to the body using SVG:

    body {
    background-image: url("data:image/svg+xml"); }

    Within the SVG, I specify both the fill color and set a low fill opacity for a subtle effect:


    I apply the same SVG image to the yellow background of my main, this time changing its fill color to white and increasing the fill-opacity:

    main {
    background-image: url("data:image/svg+xml"); }

    Pattern and texture play a big part in many of Bea Feitler’s iconic magazine spreads, and yet they’ve fallen out of favor on the web. Next, I’ll show you how to use CSS and SVG patterns which will add depth to your designs.

    Pattern And Texture Adds Depth

    Left: Spread from Vanity Fair. Right: This design uses a CSS blend modes, clip-path, and SVG patterns. Left: Spread from Vanity Fair. Right: This design uses a CSS blend modes, clip-path, and SVG patterns. (Large preview)

    In this next Feitler-inspired design, I want to convey the curvaceousness of the Volkswagen Beetle by using circles. I need minimal HTML to implement this shapely design, just three elements; a header, main and aside:

    <header aria-hidden="true">
    <h1 aria-labelledby="Volkswagen logo">

    I don’t want the header announced by screen readers, so I add an aria-hidden attribute with a value of true. I do want screen readers to describe my top-level heading, so I add an aria-labelledby attribute to that.

    Half-tone style dots add texture to this page, and it’s easy to implement patterns like this using multiple background gradients, and combinations of background-size and background-position:

    body {
    background-color: #ba0e37;
    color: #fff;
    radial-gradient(rgba(255,255,255,.25) 15%, transparent 16%),
    radial-gradient(rgba(255,255,255,.25) 15%, transparent 16%);
    background-size: 6vw 6w;
    background-position: 0 0, 3vw 3vw; }

    I’ll break this style into three steps:

    1. Two radial gradients, separated by a comma. Each gradient includes two color steps, the first at 15%, and the second at 16% which form the dots.
    2. By using viewport width units to size the resulting pattern, I keep the dot size proportionate to the page width.
    3. Position the first radial gradient to the top left of the viewport (0 0), and the second using viewport width units which are half the background sizes.
    Four linear and radial gradient background image patterns. Four linear and radial gradient background image patterns. (Large preview)

    Lea Verou has been busy compiling a gallery of useful patterns which she developed using linear and radial gradients. As clever as Lea’s gallery is, there’s something about convoluted gradients being used to produce image-like patterns which bother me.

    SVG patterns from Hero Patterns by Steve Schoger. SVG patterns from Hero Patterns by Steve Schoger. (Large preview)

    SVG patterns seem much more appropriate. They’re just as lightweight and are far more flexible. Add SVG to a background image using a URL, and if you’re concerned about HTTP requests, embed an SVG into a stylesheet as a data:image:

    body {
    background-image: url("data:image/svg+xml"); }

    The aside in this design includes two divisions which each contain pictures of the Beetle’s fabulous front. I clip those divisions into circles to compliment its curves:

    aside div {
    -webkit-clip-path: circle();
    clip-path: circle(); }
    (Large preview)

    By making the pictures’ backgrounds fully transparent, I can change the color of their parent divisions whenever I need to. I add slightly transparent background colors which allow hints of the dot pattern to show through:

    aside div:first-child {
    background-color: rgba(57,135,106,.9); }
    aside div:last-child {
    background-color: rgba(248,215,46,.9); }

    With so much color and texture in this design, my layout needs to be simple, so I apply a two-column asymmetrical grid where the narrowest column can never shrink below 260px:

    @media screen and (min-width : 64em) {
    body {
    display: grid;
    grid-template-columns: 4fr minmax(260px, 1fr); }

    To improve the accessibility and readability of my paragraphs of running text against the red pattern, I add a subtle drop shadow in a color which matches my background:

    p {
    filter: drop-shadow(0 0 5px #ba0e37); }
    By reducing the opacity of my header using a CSS filter, the patterned background shows through. By reducing the opacity of my header using a CSS filter, the patterned background shows through. (Large preview)

    In the past, filtering a picture to apply a blur, color change, or drop shadow, required adding destructive effects in an image editor, but today, many of those same filters are available in CSS. You can apply filters to other HTML elements too.

    Applying a CSS filter is straightforward. First, declare the filter-function and then a value in parentheses. To reduce an element’s opacity to 25% using a filter — instead of the opacity property — I use the opacity filter:

    .ihatetimvandamme {
    filter: opacity(.25); }

    Those values differ with each filter. Some filters use degrees, accept use pixels, percentages, or their equivalent decimal. For example, .25 is equal to 25%, and 1 is the equivalent of 100%.

    There are ten stock CSS filters to choose from: blur, brightness, contrast, drop-shadow, greyscale, hue-rotate, invert, opacity, saturate, and sepia. You can also use the URL function to use a custom filter from SVG.

    I want to remove all color from my header and reduce its opacity to 80%. I can combine any number of filters by separating them with a space. It’s important to remember that a browser will apply filters in the order they’re specified, so for my header, color will be removed before opacity is altered:

    header {
    filter: grayscale(1) opacity(.8); }

    When I need a smooth shift between CSS filters and values, I can add a transition between states, perhaps by increasing the opacity of my header for an :hover pseudo-class:

    header {
    filter: grayscale(1) opacity(.8);
    transition: filter 1s linear; }
    header:hover {
    filter: grayscale(1) opacity(1); }

    I can use CSS to develop a more elaborate animation between filters by first defining my keyframes, setting filter values at any percentage between 0 and 100% of the animation’s duration:

    @keyframes beetle {
    0% {
    filter: grayscale(1) opacity(.8) blur(5px); }
    50% {
    filter: grayscale(1) opacity(1) blur(0); }
    100% {
    filter: grayscale(1) opacity(.8) blur(5px); }

    I then assign this animation to my header, using the animation-name plus values for animation-duration, animation-delay, and other optional settings:

    header:hover {
    animation-name: beetle;
    animation-delay: 0s;
    animation-direction: alternate;
    animation-duration: 1s;
    animation-fill-mode: forwards;
    animation-iteration-count: 1;
    animation-timing-function: linear; }

    Una Kravets recreated Instagram filter effects using CSS filters and blend-modes for her CSSgram library. Building on Una’s work, developer Indrashish Ghosh made cssFilters, a tool for granular control over those Instagram-style effects, applying them to an uploaded image, and generating CSS values. Tools like Indrashish’s make it as easy to use CSS filters as any image editor.

    A reaction to overly ornamental designs, flat design has been the dominant aesthetic for almost a decade. As gradients, patterns, shadows, and three-dimensional skeuomorphism fell out of fashion, designers embraced solid colors, square corners, and sharp edges.

    Anti-skeuomorphism no doubt helped designers focus on feature design and usability without the distraction of what some might still see as flourishes. But, reducing both product and website designs to a bare minimum has had unfortunate repercussions. With little to differentiate their designs, products and websites have adopted a regrettable uniformity which makes it difficult to distinguish between them.

    While I’m not advocating a return to the worst excesses of skeuomorphism, I hope product and website designers will realize the value of a more vibrant approach to design; one which appreciates how design can distinguish a brand from its competition. A method which uses gradients, patterns, shadows appropriately to tell stories and provide greater affordance. This will make products and websites not only easier to use but more enjoyable too.

    Develop With SVG Filters

    Left: Spread from Harper’s Bazaar. Right: This design uses CSS Flexbox and Grid, and SVG filters. Left: Spread from Harper’s Bazaar. Right: This design uses CSS Flexbox and Grid, and SVG filters. (Large preview)

    For this final inspired design, I need just two structural elements; a header which contains six brightly colored Beetles, and a main for my text:

    <div><img src="car-red.png" alt=""></div>
    <div><img src="car-green.png" alt=""></div>
    <div><img src="car-cyan.png" alt=""></div>
    <div><img src="car-magenta.png" alt=""></div>
    <div><img src="car-yellow.png" alt=""></div>
    <div><img src="car-black.png" alt=""></div>

    Normal flow takes care of most of this design for small screens, but that doesn’t mean there’s nothing to do. I would lose the impact of those colorful cars if I were to shrink them all to fit a small screen. I also don’t want people to scroll past all six before they see my content, so my solution is to line them up horizontally in a scrolling panel.

    Flexbox is the obvious choice for arranging those images, but the default left-right order would mean showing the back of the final car, instead of the front of the first. This is easily solved by changing the flex-direction from the default row to row-reverse:

    header {
    display: flex;
    direction: row-reverse;
    max-width: 100%;
    overflow-x: scroll; }

    I want all these cars to appear at the same size, so I use the flex-grow property and a value of 1. As I want to show the front of each car to indicate there’s more to see outside the viewport, I set the flex-basis value to 80%;

    header div {
    flex-grow: 1;
    flex-grow: 0;
    flex-basis: 80%;
    /* flex: 1 0 80%; */  }

    On medium-size screens, there’s space for a more elaborate layout for my collection of cars. For this design, I arrange my Beetles on an 8x12 modular grid, where each module is a 16:9 aspect ratio rectangle. The black Beetle furthest away from the viewer occupies a single module, and the cars appear progressively larger until the red Beetle in the foreground occupies the largest spacial zone.

    Left: On small screens, I arrange my cars in a horizontally scrolling panel. Right: For medium screens, I place my Beetles on a modular grid. (Large preview)

    To implement this modular grid, I apply Grid to my header element, followed by eight repeating evenly sized columns, and twelve rows which adapt to the minimum height of their content. By aligning the items to the end, rather than the start, of each row, the result looks more realistic:

    @media screen and (min-width : 48em) {
    header {
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    grid-template-rows: repeat(12, min-content);
    grid-row-gap: 10px;
    align-items: end; }
    Left: An 8x12 modular grid for medium screens. Right: I change the layout and proportions on large screens by switching to a 16x12 grid. (Large preview)

    My next task is to place each Beetle onto the grid. I use a combination of child (>) and nth-child selectors to place each element using line numbers:

    header > :nth-child(1) {
    grid-column: 3 / -1;
    grid-row: 10 / -1; }
    header > :nth-of-type(2) {
    grid-column: 3 / 7;
    grid-row: 7 / 9; }
    header > :nth-of-type(3) {
    grid-column: 1 / 4;
    grid-row: 5 / 7; }
    header > :nth-of-type(4) {
    grid-column: 2 / 4;
    grid-row: 3; }
    header > :nth-of-type(5) {
    grid-column: 6 / 8;
    grid-row: 2; }
    header > :nth-of-type(6) {
    grid-column: 3;
    grid-row: 1; }

    A design like this cries out for typographic details. Padding on the main element adds space around my running text, so to add interest to my type, I set column widths of 24em, and a browser will automatically create the right number of columns to fit the viewport:

    p {
    column-width: 24em;
    column-gap: 2vw; }

    To add extra interest to my type, I combine a first-of-type pseudo-class selector with a first-line pseudo-element to transform that first line into uppercase letters:

    p:first-of-type::first-line {
    text-transform: uppercase; }

    To implement my design for larger screens, I double the number of columns from eight to sixteen and reposition my images to the new line numbers:

    @media screen and (min-width : 64em) {
    header {
    grid-template-columns: repeat(16, 1fr); }
    header > :nth-child(1) {
    grid-column: 8 / 15;
    grid-row: 9 / 13; }
    header > :nth-of-type(2) {
    grid-column: 6 / 11;
    grid-row: 5 / 8; }
    header > :nth-of-type(3) {
    grid-column: 1 / 5;
    grid-row: 4 / 6; }
    header > :nth-of-type(4) {
    grid-column: 4 / 6;
    grid-row: 3; }
    header > :nth-of-type(5) {
    grid-column: 11;
    grid-row: 2; }
    header > :nth-of-type(6) {
    grid-column: 5;
    grid-row: 1; }

    Compared to today’s Beetle — which weighs almost 3000lbs — the Volkswagen Type 1 was a lightweight and speedy little car for its time. I’d like to create the impression these cars are speeding past the viewer by adding motion blur. Blurring an element using a CSS filter is straightforward:

    header > div {
    filter: blur(5px); }

    This filter allows me to blur an element by any amount using several length values, including pixels which seem to me to be the most appropriate unit. But, CSS filters only allow me to blur an element using the same amount horizontally and vertically, much like an image editor’s Gaussian blur. To add realistic motion to my design, I need to swap CSS for an SVG filter.

    Left: A uniform CSS blur filter with equal horizontal and vertical values. Right: Two gaussian blur values in SVG create a more realistic motion blur. (Large preview)

    I cover just a small amount of detail about SVG filters in this issue, but SVG expert Sara Soueidan has written about them extensively. Start with Sara’s SVG Filters 101 tutorial.

    While its ten stock filters are a relatively recent addition to CSS, their history goes way back to their SVG origins. Filters in SVG offer far greater flexibility with six more filters available and incredible customization possibilities. Whereas CSS blur allows just one value for both horizontal and vertical axes (X/Y,) in SVG I can use two values; one for the X-axis, the other for Y.

    In SVG, every filter has its own identity, so to blur to an HTML element, reference its ID using the URL value in the filter property from a stylesheet:

    .blur {
    filter: url(#blur); }

    Filters have their own element in SVG, it’s the filter element. Even though a filter won’t be visible in a browser, giving SVG a height of 0 will ensure it takes up no space:

    <svg height="0">
    <filter id="blur">…</filter>

    Each SVG filter primitive has its own name which is prefixed by fe, an abbreviation of “filter effect.” Unsurprisingly, the name for a blur is feGaussianBlur. The amount of blur is applied as a stdDeviation using either one uniform value or two separate values for horizontal and vertical. To reproduce the previous uniform 5px Gaussian blur in SVG, I add one value:

    <filter id="blur">
    <feGaussianBlur in="SourceGraphic"

    I’m looking for a more realistic motion effect where the image is blurred on just the horizontal axis. I apply blur to only the X-axis, leaving the Y-axis at zero:

    <filter id="blur">
    <feGaussianBlur in="SourceGraphic"
    stdDeviation="15, 0"/>

    Now my car is speeding across the viewport, but when you look more closely. the result isn’t altogether realistic. That’s because the edges of my blurred elements are clipped by the bounding box. This is the rectangle which surrounds every element.

    Left: The bounding box clips the blurred edges. Right: Increasing the filter region shows the whole blurred image. (Large preview)

    To make the entire filter effect visible, I need to increase the size of my filter region using x, y, width, and height values. I use negative values of -10% on both horizontal and vertical axes, then increase the width and height to 120% which allows more visible space for my images’ blurred edges:

    <filter id="blur"
    x="-10%" y="-10%"
    width="120%" height="120%">

    When you watch cars speeding past, or you look out of a moving train window, objects closest to you appear to move faster than those further away. To make my design seem more realistic, I need a different set of blur values for objects in the foreground, middle ground, and background.

    Foreground elements like the closet red Beetle need the highest amount of horizontal blur. I give this filter an identity of blur-foreground:

    <filter id="blur-foreground"
    x="-10%" y="-10%"
    width="120%" height="120%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="15,0"/>

    Then, Beetles in the middle ground receive a slightly lower stdDeviation of 10:

    <filter id="blur-medium"
    x="-10%" y="-10%"
    width="120%" height="120%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="10,0"/>

    Finally, objects in the background receive the least blurring. I give this filter an identity of blur-background so I can apply it in my stylesheet:

    <filter id="blur-background"
    x="-10%" y="-10%"
    width="120%" height="120%">
    <feGaussianBlur in="SourceGraphic" stdDeviation="5,0"/>

    With all my filters specified, in my stylesheet I apply them to Beetles in the foreground, middle ground, and background:

    <img src="car-red.png" class="blur-foreground">
    <img src="car-green.png" class="blur-medium">
    <img src="car-cyan.png" class="blur-medium">
    <img src="car-magenta.png" class="blur-medium">
    <img src="car-yellow.png" class="blur-background">
    <img src="car-black.png" class="blur-background">
    .blur-foreground { filter: url(#blur-foreground); }
    .blur-medium { filter: url(#blur-medium); }
    .blur-background { filter: url(#blur-background); }

    My set of six colorful Beetles are now racing across the viewport and my final Feitler-inspired design is a winner too.

    NB: Smashing members have access to a beautifully designed PDF of Andy’s Inspired Design Decisions magazine and full code examples from this article.

    Related Reading

    1. Inspired Design Decisions: Avaunt Magazine
    2. Inspired Design Decisions: Pressing Matters
    3. Inspired Design Decisions: Ernest Journal
    4. Inspired Design Decisions: Alexey Brodovitch
    Smashing Editorial(vf, ra, yk, il)

    October 02 2019


    Text-To-Speech And Back Again With AWS (Part 2)

    Text-To-Speech And Back Again With AWS (Part 2)

    Text-To-Speech And Back Again With AWS (Part 2)

    Philip Kiely

    This is the second half of a series on transforming content between text and speech on AWS. In part one, we used Amazon Polly to narrate blog posts and embedded the content in a website using an audio tag. In this article, we will use speech-to-text to draft transcripts of podcasts and interviews for publication. Finally, we will evaluate the overall accuracy of these format-transformation technologies by running a few samples through round-trip transcriptions.

    Speech-To-Text Project

    In 2012, Patrick McKenzie (a.k.a. patio11, of Kalzumeus and Stripe) and Ramit Sethi (of I Will Teach You To Be Rich) sat down and recorded two hour-long podcasts. As I am a fan of both of their work, I probably would have listened to the podcasts, but I definitely wouldn’t have listened to them several times each. The transcripts, on the other hand, I can reread and reference at my leisure. I also freely recommend the series when talking to people about freelancing, knowing that I am giving them a resource that takes a quarter the time to read that it takes to listen to. Even though the content of the podcasts and transcripts are exactly the same, the combination is 10× as useful as the podcast alone.

    In the first transcript, McKenzie says that he paid 75 dollars and waited a couple of days to have the podcast transcribed by a professional service. His other option was to transcribe it himself. When I worked for my college’s newspaper, I frequently transcribed interviews. Over time, I got more practiced at the skill and improved from taking four minutes of transcribing per minute of audio to three minutes per minute. While I imagine that a professional with specialized equipment and a faster typing speed could drop below two minutes per minute, as an amateur transcriber McKenzie likely saved himself five or six hours of work by paying for the service.

    Seven years later, it seems like he should have another option: an automated transcription with Amazon Web Services. As we’ll see, the transcription would require significantly more editing before it would be publication-ready, but automated transcription has two killer features compared to hiring a professional: he would have gotten the transcription back in real time for about a dollar. In this article, I’ll explain how you can use Speech-to-Text on AWS to easily make your content multi-format and ideas for using Amazon Transcribe in more complex applications.

    Amazon provides a console to experiment with Transcribe. To access the console, log on to your AWS account and search “Transcribe” in the services search field. The console exposes the full power of Transcribe, and if you’re only planning on transcribing a few pieces of content per week then using the console is a solid long-term option. The transcription console gives you two options: streaming audio and uploading a file.

    Amazon Transcribe Console Real-Time Transcription Tab You can launch live transcriptions in the real-time transcription tab. (Large preview)

    The “real-time transcription” tab offers the ability to speak into the microphone and have a transcription generated in real time. Speaking deliberately, and with my computer’s onboard microphone, I was able to transcribe the sentence “Smashing Magazine publishes technical content for developers worldwide” on the first try. However, when I tried to transcribe the previous paragraph at a more conversational speed and articulation, there were numerous errors.

    “Amazon provides a consul to experiment with transcribe access. The console log onto a ws account and search transcribed in the services search field, The consul exposes the full power of transcribed. And if you only planning on transcribing a few pieces of content a week than using the consul is a solid long term option. The transcription Council gives you two options streaming audio and uploaded a file.”

    In addition to simply missing some words, Transcribe has issues with homophones and punctuation. In the first sentence, it transcribed “console” as “consul.” This homophone error can only be corrected by evaluating each transcribed word in the context of the sentence and adjusting according to the algorithm’s best guess. The first sentence also runs into the second, which throws off the grammatical structure and meaning of the entire rest of the paragraph. Beyond contextual clues, Amazon Transcribe seems to use pauses to determine punctuation. That said, I am using a built-in microphone, transcribing in real time, and to be honest I don’t have the clearest speaking voice. Let’s see if we can find improvements by mitigating each of these factors.

    I used a Blue Yeti, a midrange all-purpose recording microphone, to stream audio into the console. As you can see in the image below, improved audio quality did not significantly improve transcription quality. I hypothesize that while a poor quality audio input would further degrade the text’s accuracy, improvement past the threshold of a built-in microphone or cheap webcam does not provide the quality transcription that we are looking for.

    Results of using a good microphone Improving microphone quality does not materially improve transcription quality. (Large preview)

    Using the same microphone, I recorded the same paragraph as an .mp3 file and uploaded it for transcription. To do the same, navigate to the “Transcription Jobs” panel and click the orange button with the text “Create Job.” This will bring you to a form where you can configure the transcription job.

    Transcription job form top half A transcription job requires a title, language, input source, and file format. (Large preview)

    The job name is arbitrary, just choose something that will be meaningful to you when you review the completed jobs. You can select from about a dozen languages, with English and Spanish available in regional variants. The transcription service draws its input from S3, so you’ll need to upload your audio file to the storage service before you can run the job. You can upload the file in one of four supported formats: .mp3, .mp4, .wav, and .flac.

    Transcription job form bottom half A transcription job offers data location and audio identification options. (Large preview)

    If you want to keep the output data in a permanent location, change “Data location” to “Customer specified” and enter the name of an S3 bucket that you can write to. Finally, you can choose between two identification options. Channel identification tags input with the channel that it came from in the audio file, while “Speaker identification” attempts to recognize distinct voices in the audio. If you are transcribing a multi-person podcast or interview, Speaker identification is a useful feature, but it is not applicable to this simple test.

    Inspecting the output, unfortunately, reveals that the transcription is no more accurate than the real-time console transcription. However, running a transcription job does provide more data. In addition to the transcription text, the job outputs JSON with each word, its confidence score, and alternate words considered, if any. If you want to write your own natural language processing code to try to improve the readability of the output, this data will give you what you need to get started.

    Finally, I had a friend who hosts a local radio show narrate the same paragraph for live transcription. Despite his steady pace and clear enunciation, the resulting text was no more accurate than any of my live transcription attempts. While a professional narrator may be able to achieve even more specific pronunciation, the technology is really only useful if it is widely usable.

    Unfortunately, it seems that the transcription quality is too low to fully automate our proposed use case. Depending on your typing speed, running audio through Amazon Transcribe and then editing by hand may be faster than simple manual transcription, but it is not a turnkey solution for speech-to-text that compares to what exists for text-to-speech. For specific domains, you can define Custom Vocabularies to improve transcription accuracy, but out of the box, the service is insufficiently advanced.

    As with most of its services, AWS offers an API for using Transcribe. Unless you have a large number of files to transcribe or you need to transcribe audio in response to events, I would recommend using the console and save yourself the time of setting up programmatic access.

    To use Transcribe from the AWS CLI, you’ll need a JSON file and a terminal command.

    aws transcribe start-transcription-job \
         --region YOUR_REGION_HERE \
         --cli-input-json YOUR_FILE_PATH.json

    At YOUR_FILE_PATH.json, you’ll need a .json file with four pieces of information. As above, you can set any meaningful string as the TranscriptionJobName and any supported language as the LanguageCode. The CLI supports the same four media file formats and still reads the media file from S3.

        "TranscriptionJobName": "request ID", 
        "LanguageCode": "en-US", 
        "MediaFormat": "mp3", 
        "Media": {
            "MediaFileUri": "https://YOUR_S3_BUCKET/YOUR_MEDIA_FILE.mp3"

    This kind of access is also available through a Python SDK. Amazon recommends Transcribe for voice analytics, search and compliance, advertising, and closed-captioning media. In each of these cases, the transcribed text is an input to another system like Amazon Comprehend rather than the final output. Thus, as a developer, it is important to design your system and limit its use cases to tolerate the range of errors that Transcribe will feed into your application.

    Note: For more on using Amazon Transcribe and other services programmatically, check out Amazon’s getting started guide.

    Round Trip Accuracy

    While the live performance of Amazon Transcribe was somewhat disappointing, we can investigate the theoretical maximum accuracy of the system by transcribing something that was read by Amazon Polly. The two services should be using compatible pronunciation libraries and speech cadences, so text input into Amazon Polly should survive the round trip more or less intact. Of course, we will stick with the same test paragraph.

    Lo and behold, this is the only strategy that has made the transcription noticeably better:

    “Amazon provides a console to experiment with transcribe. To access the console, log onto your AWS account and search transcribing the service’s search field. The console exposes the full power of transcribe, and if you’re only planning on transcribing a few pieces of content per week than using the console is a solid long term option. The Transcription council gives you two options. Streaming audio and uploading a file.”

    Stubborn errors persist (“council” versus “console” comes in at 70% confidence) but overall the text is a few edits away from useable. However, most of us don’t speak like synthesized robots, so this quality is unavailable to us at the time of writing.


    While the quality of output speech and text are noticeably lesser than that of a person, these services cost so little that they are a strong alternative for many applications. Text-to-speech, at 4 dollars per million characters (16 dollars per million for the superior neural voices), can narrate articles in seconds for pennies. Speech-to-text, at .04 cents per second, can transcribe podcasts in minutes for about a dollar. Of course, prices may change over time, but historically as technologies like these improve, they tend to become less expensive and more effective.

    Because of the low cost, you can experiment with these technologies for things like improving your personal productivity. When biking or driving to work, it is impossible to type notes or an outline a project, however, speaking and automatically transcribing a stream-of-consciousness narration would get a lot of planning done. Journalists frequently transcribe long interviews, a process which AWS can automate by tagging the voices of people speaking in a recording. On the other side of the writing process, having a steady, robotic voice read your work back to you can help you identify errors and awkward phrasing.

    These technologies already have a number of use cases, but that will only expand over time as the technologies improve. While text-to-speech is reaching near-perfect accuracy in pronunciation, especially when assisted by pronunciation alphabets and tags, the synthesized voice still doesn’t sound fully natural. Speech-to-text systems are pretty good at transcribing clear speech but still struggle with punctuation, homophones, and even moderately quick speech. Once the technologies overcome these challenges, I anticipate that most applications will have a use for at least one of them.

    Smashing Editorial(dm, yk, il)

    October 01 2019


    How To Ensure Your Design System Helps To Achieve The Purpose Of Your Product

    How To Ensure Your Design System Helps To Achieve The Purpose Of Your Product

    How To Ensure Your Design System Helps To Achieve The Purpose Of Your Product

    Nick Babich

    (This is a sponsored post.) Design systems help product teams to approach design with a system in mind. But not all design systems are equally effective. Some design system help product teams create coherent experience; others produce confusing designs.

    The effectiveness of a design system can be measured by how well it works to help achieve the purpose of the product. In this article, we’ll try to find the qualities that make a design system good for your product development.

    Do You Clearly Understand Why You Need A Design System?

    All too often, product teams attempt to create a solution for a problem they don’t have. And when it comes to creating a design system, some teams attempt to create a system just because other teams are doing it.

    Product And Company Maturity

    Companies have different levels of design maturity. Some companies have a product with thousands of users, while others are just beginning to implement their product.

    Creating a design system from scratch is a time-consuming activity. Small fast-moving teams likely don’t need a design system because it would slow them down. A three-to-five–person startup that is trying to find a product-market fit would probably spend a significant amount of time creating a system. And if resources are being spent on building a design system, they aren’t being spent on building the product. Until the company establishes a clear direction with its product, investing time in creating a design system risks producing a lot of waste.

    A design system should come from the need to increase efficiency at scale. And it happens only when a team has real problems with the efficiency that prevent it from moving quickly. Let your team hit scale first and reach a point where inefficiencies such as in the technical and design departments become significant factors in design decisions.

    Interface Audit And Technology Stack

    Many companies tend to build a design system on top of the current interface, but this approach is not very good for many reasons. Imagine that your company has been building a product for a long time without a system; it’s likely that the product has some level of inconsistency in design.

    That’s why if you plan to introduce a design system, start with an audit: Explore existing interactions, and collect all of the UI elements in your product. Collect all elements that make up the interface, and file them for review. The reviews should help you to understand the reason for inconsistency and the changes you’ll need to introduce in the design process in order to avoid such problems in the future.

    Does The Design System Set A Clear Direction For Designers And Developers?

    A design system is valuable only if the people who are working on the product adopt it. Shared understanding plays a vital role in adoption of the system.

    Before starting to design a product, it’s essential to align teams around a clear set of shared goals. Build a vision, and ensure that everyone is looking in the same direction. A design system should give teams a guided way to build solutions for their product problems.

    Mapping Out User’s Needs, Goals, And Motivations

    One of the first things we need to do when starting to work on a product is to understand who our users are and what are their goals, needs, and motivations. This information should be the foundation of the design system you want to create.

    Tools like user-journey mapping and the Jobs to be Done framework will help you to understand how people interact with your product. The product team should keep this information in mind when working on the design system.

    Express The Purpose Of The Product

    The purpose is the core of the product, and it should inform design and development decisions. The purpose of a product should be expressed in one sentence. For instance, if we were designing a meditation app for quick relaxation, our goal would be to help people who use our app to relax. If we expressed this purpose in a single sentence, it would be something like, “Help people relax in no time.”

    Note that the purpose should be natural, not forced; otherwise, the team won’t believe in it.

    Establish Clear Design Principles

    Solid design principles are the foundation of any well-functioning system. They should capture the essence of what good design means for the company and provide practical recommendations for product teams on how to achieve it.

    Design principles should be created on the principles and values of the product. Design Principles of the Lightning Design System. (Large preview)

    Below are just a few guidelines for design principles.

    Design Principles Should Be Authentic And Genuine

    Many of us hear principles like “simple and useful”. But qualities like these should be a given. Knowing that your product should be simple and useful is not going to be helpful in guiding your design decisions. Imagine that a new member joins your team, and you need to share the three guiding principles that are most important when designing a product. You might say something like, “We like simple things — strive to create simple things.” This doesn’t say much to the person. It’s hard to imagine that anyone would intentionally create a complex and useless product.

    That’s why principles should offer practical guidance on how to solve a design problem within the context of the particular product. One of the design principles of Medium, a popular blogging platform, is “Direction over choice.” Thanks to this principle, instead of designing a text editor with endless visual styles, Medium’s design team decided to limit the number of visual styles. In doing so, they make the writer focus on what’s really important: the content they are producing.

    Medium text editor. (Large preview)
    Design Principles Should Be Memorable

    Ask the people in your company what your design principles are. If no one can remember them, chances are they are not working.

    Design Principles Should Provide Practical Examples

    Even the best principles can be interpreted in different ways. Nothing makes a principle clearer that being paired with a real-life example, showing how it can be applied in context.

    Tip: Sometimes you need to provide counter-examples to help people understand what not to do.

    How Effective Is The Design Language Of The Interface?

    A design language emerges as a team works on a product. The design language of the interface has a significant impact on how users interact with the product. If a product created with a design system is confusing and doesn’t help users achieve their goals, then the design system is not effective.

    How Design Patterns Are Executed And Applied

    A pattern is a reusable solution that can be applied to solve a design problem. Design patterns are shaped by the core idea of how a product works, and they form the foundation of the language that the team uses to communicate with users.

    There are two types of patterns: functional and perceptual.

    Functional Patterns

    Functional patterns are the tangible building blocks of an interface. Buttons, icons, text fields and so on all come together to form what we call a product.

    Many factors influence the choice of design patterns, and most of them come from the domain that the product belongs to and from its core functionality. Let’s take a finance product as an example. A finance product might need to prioritize multitasking and quick scanning (which require greater information density). In Bloomberg’s interface, shown below, density is achieved through tight spacing, compact controls, and good typography choices.

    Bloomberg terminal has a dense design, fitting large amounts of information on the screen. Image: Wikipedia. (Large preview)
    Perceptual Patterns

    In his book _The Timeless Way of Building_, Christopher Alexander asks why some places feel so great to be in, while others feel dull and lifeless. According to him, the way places and buildings make us feel is the result of specific patterns: perceptual patterns.

    Perceptual patterns focus on what users feel. Colors, typography, iconography, shapes, and animation come together to form the identity of a product. Without perceptual patterns, you wouldn’t sense much difference between products in the same domain.

    The aesthetics and voice and tone in a product should capture the personality and ethos we want to convey through the interface:

    • How do we want our product to be perceived?
    • Is our product serious or playful?
    • Should it be utilitarian or emotional?
    MailChimp’s Voice and Tone. Image source. (Large preview)

    It’s also important to understand that perception is influenced not only by individual elements (text, colors, typefaces, white space, etc.), but also by the relationships between those elements. In other words, it’s not enough to use colors and fonts consistently; we should also be aware of the “just right” combinations that make a product feel a certain way.

    Tip: When working on a perceptual pattern, you can use the technique of moodboarding. Collect all elements with relevant visual styles, and define their core visual brand elements. Moodboards are an excellent tool to explore different visual themes. To make one, you can use a digital tool like Pinterest or assemble printed pages on a large board.

    Measure Your Progress

    Implementing a design system is a process. And it’s crucial to ensure along the way that the system is helpful. No matter how good you are at predicting things, in many cases, it will be hard to predict how a particular change will affect the user experience. That’s why it’s important to define metrics and to track them along the way. After every release, measure how your product performs. Measure the qualitative and quantitative results, and make sure your metrics are going in the right direction.

    How Effective Are The Practices Of The Team?

    How Fast Does The Internal Design Team Work?

    Can the people working on the product ship changes more quickly?

    An effective design system allows a business to meet its goals faster and at a lower cost. A design system should reduce implementation decisions, because team members would have all elements of a product ready for use, along with information on how to use them. As the process of building products accelerates, designers will gain time, which they can invest in other areas, such as user research.

    Here are a few areas to monitor:

    • Efficiency
      Measure how fast new patterns are integrated and how fast changes to existing patterns are introduced. If designers often have to introduce a new component to solve a problem, that could be a strong sign that the design system is not flexible.
    • Consistency
      How hard is to create consistent experiences across different platforms.

    When it comes to design efficiency, investment in tools and technology is essential. A good toolbox will help to eliminate manual operations from your design process. Adobe XD offers two excellent features that can improve design efficiency: components and shared assets panel.

    Using XD, you can create a master component to define a reusable UI element, such as a button. Create instances of any component in your UI, and customize them. The components are designed to resize responsively, so you can take any instance and adjust the size of the component, and XD will automatically manage the placement and scaling of the elements within the component for you.

    You can use the Assets panel to curate a collection of reusable elements that you want to make available to other designers on your team. To enable others to use the visual styles and components you’ve defined, invite them to the document using “Share” → “Invite to Edit”. The great news is that everyone will leverage the latest assets; whenever the design is updated, team members who have been invited to the collection will be notified about the changes. Team members will be able to update at their own discretion.

    How Easily Can Developers Code The UI?

    It’s well known that developers and designers must work hand in hand. And when it comes to communication between designers and developers, design specifications play a key role. The most important aspect of the design specification is clarity: If developers don’t understand the specification, they might implement something different from the original idea. A good design specification reduces false interpretation of design decisions.

    With Adobe XD, creating an unambiguous specification is a relatively simple process. You can use “Share” → “Share for Development” to publish your design system on the web. The resource will contain information about color values, style attributes, and downloadable assets.

    Image source. (Large preview)

    How Good Are The Naming Conventions?

    Does the design system allow team members to communicate more efficiently? Language is fundamental to collaboration. Every element in a design system should have a name that is known and that makes sense to the people on your team. Proper naming conventions are especially important for products that will scale — as the number of patterns in a library increases, good naming conventions can help team members quickly find what they’re looking for.

    Here are a few tips on naming elements:

    • The distinguishing aspect of a design system’s language is its stickiness. Similar to any other language, we need to use the language if it is to survive. It needs to be a part of our daily routine.
    • Naming an element can be hard when the team hasn’t fully understood its purpose. If you have a hard time finding the right name, chances are that something isn’t quite right. Maybe an element’s purpose is unclear.
    • Name components from the user’s perspective. Speak to users and potential users of the product, and name components according to how their refer to them. This will help engineers to think from the user’s perspective and to always have users in mind.
    • Test your language with users. This ensures that the modules you’ve defined are aligned with your user’s potential behaviors and mental models.

    How Easy Is It To Maintain The System?

    A design systems is not a static tool, but rather a living organism in your company. It should grow and evolve together with your product. The time required to keep the system up to date plays a key role in its success or failure. If keeping the design system updated becomes difficult, it will quickly become outdated.

    Here are two important moments to consider:

    • Depending on the size of a company, a design system could be either static or dynamic. It’s always better to have a dynamic design system, one that will be updated in real time with the product. Also, a static design system would not fit a company that has large-scale products, because the time required to introduce changes would be significant.
    • A design system should have a roadmap and backlog. As with any other product, creating a design system is an iterative process, constantly ongoing.

    Does The Design System Extend Creative Directions?

    Creative experimentation is an integral part of the design process. Sometimes, effective design decisions are based on intuition. That’s why one of the main goals of a design system is to extend creative direction. A design system should encourage the people who work on the product to be creative and spontaneous.

    Invite Everyone To Contribute To The System

    Everyone in the company should be not only allowed but encouraged to contribute to the system. Give people enough freedom to contribute, yet make sure the system stays managed and curated.

    Tip: Follow a process of peer-to-peer reviews. This will increase awareness of the design system.

    Achieve A Balance Between A Sticky And Loose System

    Some users of design systems fixate on perfect consistency. But perfect consistency doesn’t guarantee a great product. If the process you’re following is restrictive, you risk ending up with a generic design. That’s why it’s vital to find a balance between consistency and creative expression in the design.

    When it comes to creative exploration, it’s always better to experiment on a small scale first. If some elements work well (such as a new style for a call-to-action button), then the design system should make it easy to integrate the changes into other parts of the interface.


    A well-crafted design system serves as a North Star of your product development. A design system amplifies design-driven culture — it encourages people who work on the product to look beyond the building blocks and to think of the purpose of their design. The big picture that a design system imparts will lead to a better understanding of your users and, ultimately, a better user experience.

    Recommended Reading

    This article is part of the UX design series sponsored by Adobe. Adobe XD tool is made for a fast and fluid UX design process, as it lets you go from idea to prototype faster. Design, prototype and share — all in one app. You can check out more inspiring projects created with Adobe XD on Behance, and also sign up for the Adobe experience design newsletter to stay updated and informed on the latest trends and insights for UX/UI design.

    Smashing Editorial(ms, yk, il)

    SmashingConf Freiburg 2019: Videos And Photos

    SmashingConf Freiburg 2019: Videos And Photos

    SmashingConf Freiburg 2019: Videos And Photos

    Rachel Andrew

    We returned to our home in Freiburg for the 2019 SmashingConf, and brought all the SmashingConf fun with us. We’ve wrapped up the event in this post, including links to the video of all of the presentations, so you can relive what you enjoyed — or share in something of what you missed.

    Smashing built in lego bricks ‘Smashing’ in Lego, built by our attendees. (Photo credit: Drew McLellan)

    The Presentations

    The main focus of the conference is the speakers and the presentations they bring. As with all of our 2019 events, some speakers opted to present without slides. In the tables below, I’ve linked to slides for those talks which had them, plus the video of each presentation. Enjoy two days worth of learning from the comfort of your own couch!

    Day One

    The Day One Collaborative Doc created by attendees is full of takeaways from the first day of the conference. Rémi Parmentier used our stage to launch his project “Can I Email…?”, a site which aims to do for HTML email what Can I Use does for web platform features.

    Speaker Name Talk Title Video & Slides Joe Leech Designing Powerful Users Experiences With Psychology Video, Slides Anna Migas Effortless Performance Debugging Video Uri Shaked and Benjamin Gruenbaum The Anatomy Of A Click Video, Slides Val Head Designing With Motion Video, Slides Rémi Parmentier Think Like An Email Geek Video, Slides Benjamin Hersh Every Product Has A Voice Video Two people on a sofa on stage talking Vitaly interviews Anna Migas after her talk. (Photo credit: Drew McLellan)

    Day Two

    Check out the Day Two Collaborative Doc for more resources and thoughts from our attendees and speakers.

    Our mystery speaker was Seb Lester. No-one managed to guess the theme mystery, although there was a suggestion it might be the panda that was sat on stage!

    We then enjoyed talks covering a wide range of topics from our day two speakers. Our final speaker, Heather, also announced her new book, which she will be publishing through Smashing Books! Heather also wrote up a post in which she shares her thoughts on speaking at Smashing Conf and also answers lots of questions from the audience that she didn’t have time to during the Q&A session.

    A woman presenting on stage Heather Burns Was our final speaker of the day. (Photo credit: Drew McLellan) Speaker Name Talk Title Video & Slides Robyn Larsen International Is The New Mobile First Video Philip Walton Service Workers For The Rest Of Us Video Guillaume Kurkdjian A Little Advice From An Illustrator And Animator Video Sara Soueidan Applied Accessibility: Practical Tips For Building More Accessible Front-Ends Video, Slides Heather Burns Building Privacy Conscious Products Video, Slides A man and woman on stage, the woman behind a lectern Sara Soueidan being introduced by Vitaly (Photo credit: Drew McLellan)


    Our workshops are a big part of each of our Smashing conferences. In Freiburg, workshops were held the day after the conference. This time round, we saw the following workshops:

    Name Workshop Title The Deque Team How To Translate Wireframes Into Accessible HTML and CSS Sara Soueidan Accessible UI Patterns Joe Leech Psychology For UX And Product Design Vitaly Friedman Smart Responsive UX Design Patterns

    Side Activities

    A conference isn’t just about the talks and speakers. We want to make spaces where attendees and speakers can learn from each other and share experiences in a more informal setting. We want to offer something for everyone — from the party-goers to the fitness enthusiasts, and everyone in-between! So at lunchtime, we had lunch sessions: On Day 1, we saw the “Web We Want” panel discussion from Microsoft, and on Day 2, Deque ran a session in which attendees could grab a plate of lunch and settle down in a more cozy environment to take part.

    Three women panelists ‘The Web We Want’ panel (Photo credit: Drew McLellan)

    We had a great lounge area, with the talks live-streamed where some attendees spent time watching talks and building lego or doing jigsaw puzzles.

    Overhead shot of people doing jigsaw puzzles and building lego Doing puzzles in the lounge (Photo credit: Drew McLellan)

    We enjoyed all of these things powered by excellent coffee from a barista stand, sponsored by our friends at Honeypot.

    Morning Run

    If you follow me on Twitter, you’ll know that I’m a keen runner, and it’s always nice to have some company on an early morning run. For a few conferences now, we’ve been organizing pre-conference runs — Freiburg was no exception. Runners joined me on both days for 5k along the river — we even avoided the rain.

    Jam Session

    The Jam Session this time round was hosted by Shopify. Attendees spent time socializing and hearing some lightning talks.

    The Planetarium, Cable Car and Photo Walk

    On the Sunday before the conference, some hardy souls took a trip up the Schauinsland Cable Car. It’s the longest loop cable car in Germany, and everyone had fun despite the weather being less than ideal for views from the top.

    After Day 1, everyone was invited to enjoy a show at the Freiburg Planetarium before heading over to the after-conf party. Our party this year was held at Grünhof Freiburg and sponsored by Speedcurve. Speakers and attendees were able to enjoy time together in the garden there, as the weather had improved from the previous day!

    After Day 2, many attendees enjoyed a history photo walk around beautiful Freiburg, learning more about the town and having the chance to take some photos.

    Want To Join In The Fun?

    We packed a lot into those few days! If you were there, we hope that you enjoyed it as much as we did. It was great to meet so many of you.

    Conference attendees throwing balloons Balloons! (Photo credit: Drew McLellan)

    If you would like to be part of the SmashingConf fun next year, we have launched our full schedule of events for next year. You can join us in San Francisco, Freiburg, New York, or our new city of Austin! The conferences this year all sold out well in advance, so if there is an event you have your eye on, grab a ticket at early-bird pricing today!

    Smashing Editorial(il)
    Save time by using these builders for portfolio websites and pages

    September 30 2019


    Beneath The Autumn Leaves (October 2019 Wallpapers Edition)

    Beneath The Autumn Leaves (October 2019 Wallpapers Edition)

    Beneath The Autumn Leaves (October 2019 Wallpapers Edition)

    Cosima Mielke

    Misty mornings, pumpkins, leaves shining in bright red, yellow, and orange hues — these are just some of the things about October that inspired artists and designers to participate in this month’s wallpapers challenge.

    The monthly challenge has been going on for more than nine years already, and each time anew, creatives from all across the globe submit their designs to it to cater for some variety on your desktop and mobile screens — and for a bit of fresh inspiration, of course.

    In this collection, you’ll find their wallpaper designs for October 2019. They come in versions with and without a calendar so that you can continue to use your favorite even after the month has ended. Speaking of favorites: As a little extra goodie, we compiled some favorites from past wallpapers editions at the end of this post. A big thank-you to everyone who shared their designs with us this time around. Happy October!

    Please note that:

    • All images can be clicked on and lead to the preview of the wallpaper,
    • We respect and carefully consider the ideas and motivation behind each and every artist’s work. This is why we give all artists the full freedom to explore their creativity and express emotions and experience through their works. This is also why the themes of the wallpapers weren’t anyhow influenced by us but rather designed from scratch by the artists themselves.

    Submit your wallpaper

    We are always looking for designers and artists to be featured in our wallpapers posts. So if you’re feeling creative, please don’t hesitate to submit your design. We’d love to see what you’ll come up with for November. Join in! →

    First Scarf And The Beach

    “When I was little my parents always took me and my sister for a walk at the beach in Nieuwpoort, we didn’t really do those beach walks in the summer but always when the sky started to turn grey and the days became colder. My sister and I always took out our warmest scarfs and played in the sand while my parents walked behind us. I really loved those Saturday or Sunday mornings where we were all together. I think October (when it’s not raining) is the perfect month to go to the beach for ‘uitwaaien’ (to blow out), to walk in the wind and take a break and clear your head, relieve the stress or forget one’s problems.” — Designed by Gwen Bogaert from Belgium.

    First Scarf And The Beach

    Rain And Acorns

    “Waiting at the bus stop when it’s raining in October can be a sad and wet experience. The bus is late, the dry spot is taken by other people and you’re just standing there in the rain with your hands in your pockets with nowhere to go. Acorns must have a hard time like that too! Waiting in the rain for the squirrels to come and pick them up.” — Designed by Casey Dulst from Belgium.

    Rain And Acorns


    “To me, October is a transitional month. We gradually slide from summer to autumn. That’s why I chose to use a lot of gradients. I also wanted to work with simple shapes, because I think of October as the ‘back to nature/back to basics month’.” — Designed by Jelle Denturck from Belgium.


    Autumn Is In The Air

    “October reminds me of autumn, the season where you see fall leaves, squirrels, the weather that’s changing. Ever walked into the woods when it’s autumn? You can hear the magical sound of the wind blowing away the leaves. The woods are the most beautiful at fall, everything starts to color into yellow, orange, and brown. And you can meet some nice squirrels at the corner of a tree.” — Designed by Delphine Wylin from Belgium.

    Autumn Is In The Air

    The Return

    Designed by Ricardo Gimenes from Sweden.

    The Return

    Sleepy Hedgehog

    “Hedgehogs usually start to hibernate around October. This little hedgehog is celebrating Halloween on his own terms, while he is asleep.” — Designed by Aaron Harinck from Belgium.

    Sleepy Hedgehog

    The Month Of Tricks And Treats

    “The fiery pumpkins blaze in the dark. The bonfires, the songs, the dancing around and the sumptuous feast. There is so much to look forward to this month.” — Designed by Mobile App Development from India.

    The Month Of Tricks And Treats

    Turtles In Space

    “Finished September, with October comes the month of routines. This year we share it with turtles that explore space.” — Designed by Veronica Valenzuela from Spain.

    Turtles In Space

    Halloween House Call

    “Halloween brings a nighttime of fun for all the family. With trick-or-treating round the neighborhood, it’s a pastime families love to take part in nationwide. We wanted to celebrate this event by coming up with a design concept that would pay homage to the most iconic Halloween fruit of them all, the mighty Pumpkin! What better way to look forward to this spooktacular night than with a geometric art pumpkin calendar. Enjoy your night, whatever you have planned!” — Designed by Ever Increasing Circles from the United Kingdom.

    Halloween House Call

    Create More

    “The colors of the sun inspired me.” — Designed by Hitesh Puri from India.

    Create More

    Sober October

    “Every year when October begins, my family and I light up the fireplace for the first time. This time of the year the leaves start falling and it starts to become cold outside which makes it even cosier.” — Designed by Jasper Vermeulen from Belgium.

    Sober October


    “October 2019 will always be remembered as Brexit-month so I wanted to create a wallpaper that’s inspired by Brexit. At the same time I wanted to stay away from the classic Brexit/Europe colours. I came up with a pop-up window to imply that maybe, before really exiting the EU, the UK should reconsider what they are doing. ‘Is it ok to take this huge decision while people are screaming for another referendum’ is only one of the questions I want the British government to ask themselves.” — Designed by Nand Rogge from Belgium.


    Month Of Gratitude

    “As autumn advances, the leaves descend in great gratitude, they return to Earth to rise again. Under the shedding tree the students and teachers learn, for a teacher sheds her years so that the students can grow.” — Designed by Mindster from India.

    Month Of Gratitude

    Disarmament Week

    “According to research, 44 million Americans own firearms. The last week of October is Disarmament Week, so we are inspired by states like Liechtenstein, who abolished army and don’t use weapons. This monthly calendar is dedicated to all those who follow this trend. If the whole world was like Liechtenstein, we would be happier and cheerful. So, let’s all stand together against guns and bombs and establish a world without ammunition.” — Designed by PopArt Studio from Serbia.

    Disarmament Week


    “Apples are known all throughout the world yet barely anyone knows about Apple Day. For this reason I decided to put Apple Day in an extra spotlight and create a calendar about it. I hope others may enjoy apples as much as I do.” — Designed by Miguel De Pelsmaeker from Belgium.


    Wandering In Woods

    “The icy mountains keeping the body frozen, yet the mind wandering over the expansive woods.” — Designed by Sweans Technologies from London.

    Wandering In Woods


    “When I think about October, I immediately say ‘Oktoberfest’, partly for the obvious October part, but mostly for the ‘fest’ one. As we all know, Oktoberfest is a German traditional celebration dedicated to beer, that annually gathers friends from everywhere around the world, all having in common the passion for good beer (in large quantities), traditional food and the fun factor. And what can be more entertaining than having fun with your friends while drinking beer in an authentic German scenario?” — Designed by Loredana Codau (@loricacucrizanteme on Instagram) from Romania.


    Oldies But Goodies

    Hidden in our wallpapers archives, we rediscovered some nearly-forgotten treasures from past editions. May we present… (Please note that these designs don’t come with a calendar.)

    Shades Of Gold

    “We are about to experience the magical imagery of nature, with all the yellows, ochers, oranges, and reds coming our way this fall. With all the subtle sunrises and the burning sunsets before us, we feel so joyful that we are going to shout it out to the world from the top of the mountains.” — Designed by PopArt Studio from Serbia.

    Shades Of Gold

    Flying Home For Halloween

    “You can only fully master the sky wearing an aviator hat and goggles. Like this little bat, flying home to celebrate Halloween with his family and friends.” — Designed by Franke Margrete from the Netherlands.

    Flying Home For Halloween


    “The term ‘Hanlu’ literally translates as ‘Cold Dew.’ The cold dew brings brisk mornings and evenings. Eventually the briskness will turn cold, as winter is coming soon. And chrysanthemum is the iconic flower of Cold Dew.” — Designed by Hong, ZI-Qing from Taiwan.


    Strange October Journey

    “October makes the leaves fall to cover the land with lovely auburn colors and brings out all types of weird with them.” — Designed by Mi Ni Studio from Serbia.

    Strange October Journey

    Fallen Woods

    Designed by Dan Ioanitescu from Canada.

    Desktop Wallpaper - October 2012
    • preview
    • without calendar: 1280x720, 1280x800, 1680x1050, 1920x1080, 2560x1440

    Autumn Gate

    “The days are colder, but the colors are warmer, and with every step we go further, new earthly architecture reveals itself, making the best of winters’ dawn.” — Designed by Ana Masnikosa from Belgrade, Serbia.

    Autumn Gate

    Discovering The Universe!

    “Autumn is the best moment for discovering the universe. I am looking for a new galaxy or maybe… a UFO!” — Designed by Verónica Valenzuela from Spain.

    Discovering The Universe!

    All The Things

    “During our recent rebrand, everyone in our team got their very own icon, each one has been custom illustrated by a lovely man called Paul, who wears glasses. The icons have all been chosen to represent something personal to each individual as well as all the other usual suspects you’d expect from an iconset.” — Designed by Engage Interactive from the United Kingdom.

    All the things


    “In my travels to Selinsgrove, PA this past month, I had another opportunity to appreciate the beauty that surrounded me: trees, mountains, streams, rivers and fauna. This exploration was the inspiration for this piece encouraging others to explore new places and cherish the experience of being outdoors.” — Designed by Gabrielle Gorney from the United States.



    “The moment when you just walk and your imagination fills up your mind with thoughts.” — Designed by Gal Shir from Israel.


    Say “Bye” To Summer

    “And hello to Autumn! The Summer heat and high season is over. It’s time to pack our backpacks and head for the mountains — there are many treasures waiting to be discovered!” Designed by Agnes Sobon from Poland.

    Desktop Wallpaper - October 2012
    • preview
    • without calendar: 1280x800, 1440x900, 1680x1050, 1920x1080, 1920x1200, 2560x1440

    Haunted House

    Designed by Mad Fish Digital from the United States.

    Trick Or Treat


    “Autumn is the mushroom season. Be vigilant. Do not abuse.” Designed by from Russia.

    Free Desktop Wallpaper - October 2011
    • preview
    • without calendar: 1024x768, 1280x800, 1280x1024, 1440x900, 1680x1050, 1920x1200

    Save Water, Drink Rain

    Designed by Marika Smirnova from Russia.

    Smashing Wallpaper - october 11
    • preview
    • without calendar: 320x480, 1024x768, 1024x1024, 1280x800, 1280x1024, 1440x900, 1680x1050, 1920x1080, 1920x1200, 2560x1440

    Autumn Colors

    “I love the autumn colors and making pictures, this is a collage of bits and pieces of various autumn photos from previous seasons. Enjoy!” — Designed by Agnes Swart from the Netherlands.

    Autumn colors

    A Time For Reflection

    “‘We’re all equal before a wave.’ (Laird Hamilton)” — Designed by Shawna Armstrong from the United States.

    A Time for Reflection

    Join In Next Month!

    Thank you to all designers for their participation. Join in next month!

    September 27 2019


    SmashingConf 2020 – San Francisco, Freiburg, New York And Austin

    SmashingConf 2020 &ndash; San Francisco, Freiburg, New York And Austin

    SmashingConf 2020 &ndash; San Francisco, Freiburg, New York And Austin

    Rachel Andrew

    We’ve been running SmashingConf since 2012, when we held our very first conference in Freiburg, Germany. Since then, we’ve continued to experiment and improve on our conference experience. Our aim is that you enjoy your time with us, but also return to work with new insights and knowledge. Each time we hope to leave you with practical takeaways that will help you in your own work and want to share with your team.

    What is a SmashingConf like? It’s hard to explain until you have been there, however ,this video compilation from Toronto might just give you an idea!

    Experimenting With Presentation Formats

    Back in 2018, we began to experiment with the live-coding format. While not every presentation at SmashingConf was live-coded, many presenters brought a live element to their talk. Some speakers opted to present without slides completely, and these interactive sessions have been incredibly popular with audiences. Being able to watch an expert doing their work, seeing the tools they use and the choices they make in real time, brought many subjects to life.

    “I love the fact that this talk format also kind of rid me of the expectation that it needed to be flawless.”

    Sara Soueidan

    Many of our speakers enjoyed the chance to try something different on stage; some have gone so far as to decide to make live-coding part of how they present in the future.

    “I didn’t expect this, but I’m now seriously considering this format as a way I do talks at other conferences.”

    Dan Mall

    Not every talk fits a live-coding format, of course. Throughout 2019, we feel that we’ve found a great balance of practical live-coded (or live-designed) sessions, more traditional presentations with slides, and some which have mixed the two approaches. SmashingConf audiences are a mixture of designers and developers, of visual thinkers and those who learn best from seeing a lot of code.

    As Dan Mall noted in his write-up of his live-coded talk:

    “A few designers felt validated in their processes by seeing mine [...]

    “A few developers said design felt less intimidating now, both to understand as well as to try.”

    In mixing up the formats as well as the subjects being discussed, we hope to bring parts of the industry to life — even for those who don’t normally work in that area.

    Vitaly interviewing Val Head on stage at Smashing Conf Freiburg 2019 Talks are usually followed by an interview. (Photo credit: Drew McLellan)

    In addition to playing with the format of presentations, we encourage audiences to engage with the speakers and each other. Talks are followed by an interview on stage — with the emcee posing questions asked by the audience. We publish a live Google Doc, so everyone can share their thoughts and ideas with the speakers as well as each other. Most of our speakers will attend the entire event, and enjoy the chance to chat with attendees. We believe everyone has useful knowledge to share — whether on stage or from the comfort of your seat!

    Looking Forward To 2020

    SmashingConf has always taken a holistic approach to the web. We believe that we all do better work when we work together and understand something of the roles of other team members. In 2020, we hope to build on the successes of 2019 by continuing to bring you some of the best live sessions — mixed with case studies, opportunities for networking, and surfacing some topics that are sometimes forgotten when focusing on design and development! We’ll cover topics such as HTML email, internationalization and localization, how to provide more accurate estimates, privacy, security, refactoring, debugging and the way designers and developers think as they work through their tasks and challenges.

    We’re currently working hard on curating the line-up for all of the events next year. So, the big question is… where will you join us?

    San Francisco, Freiburg, New York Or Austin!

    The Smashing Cat will soon be on its way to Austin for the first time. We’re really excited about heading to Texas and about our events in cities we already know and love. Over the next few months, we’ll be announcing speakers and schedules for all of the events, but early-bird tickets are already available for San Francisco, Austin, and Freiburg 2020.

    This year’s events have all been sold out well in advance of the conference dates, so mark the following dates in your calendars, have a chat with your boss, and work out where you will be heading to spend a fun and educational few days with the Smashing crew!

    San Francisco, USA

    Smashing San FranciscoSmashingConf SF will be taking place on April 21–22 where we’ll be bringing back two full days packed with front-end, UX and all that jazz! Live sessions on performance, accessibility, security, interface design, debugging and fancy CSS/JS techniques — and a few surprises along the way, of course! 🎸

    Austin, USA

    Smashing AustinSmashingConf Austin will be taking place in the wonderful ZACH Theatre on June 9–10, 2020. Tacos, cats, and a friendly community — see ya in Austin, I reckon? 🌮

    Freiburg, Germany

    Smashing FreiburgWe will be returning to our hometown for SmashingConf Freiburg on the 7-8 September 2020. We pour our hearts into creating friendly, inclusive events that are focused on real-world problems and solutions. Our focus is on front-end and UX, but we cover all things web — be it UI design or machine learning. The Freiburg edition is, of course, no exception!

    New York, USA

    Join us for SmashingConf NYC on the 20-21 October 2020. This event is always a popular one, so watch out for tickets going on sale very soon!

    Smashing Editorial(ra, vf, il)

    Frankenstein Migration: Framework-Agnostic Approach (Part 2)

    Frankenstein Migration: Framework-Agnostic Approach (Part 2)

    Frankenstein Migration: Framework-Agnostic Approach (Part 2)

    Denys Mishunov

    In this article, we’ll be putting all the theory to the test by performing step-by-step migration of an application, following the recommendations from the previous part. To make things straightforward, reduce uncertainties, unknowns, and unnecessary guessing, for the practical example of migration, I decided to demonstrate the practice on a simple to-do application.

    It’s time to put the theory to the test It’s time to put the theory to the test. (Large preview)

    In general, I assume that you have a good understanding of how a generic to-do application works. This type of application suits our needs very well: it’s predictable, yet has a minimum viable number of required components to demonstrate different aspects of Frankenstein Migration. However, no matter the size and complexity of your real application, the approach is well-scalable and is supposed to be suitable for projects of any size.

    A default view of a TodoMVC application A default view of a TodoMVC application (Large preview)

    For this article, as a starting point, I picked a jQuery application from the TodoMVC project — an example that may already be familiar to a lot of you. jQuery is legacy enough, might reflect a real situation with your projects, and most importantly, requires significant maintenance and hacks for powering a modern dynamic application. (This should be enough to consider migration to something more flexible.)

    What is this “more flexible” that we are going to migrate to then? To show a highly-practical case useful in real life, I had to choose among the two most popular frameworks these days: React and Vue. However, whichever I would pick, we would miss some aspects of the other direction.

    So in this part, we’ll be running through both of the following:

    • A migration of a jQuery application to React, and
    • A migration of a jQuery application to Vue.
    Our goals: results of the migration to React and Vue Our goals: results of the migration to React and Vue. (Large preview)

    Code Repositories

    All the code mentioned here is publicly available, and you can get to it whenever you want. There are two repositories available for you to play with:

    • Frankenstein TodoMVC
      This repository contains TodoMVC applications in different frameworks/libraries. For example, you can find branches like vue, angularjs, react and jquery in this repository.
    • Frankenstein Demo
      It contains several branches, each of which represents a particular migration direction between applications, available in the first repository. There are branches like migration/jquery-to-react and migration/jquery-to-vue, in particular, that we’ll be covering later on.

    Both repositories are work-in-progress and new branches with new applications and migration directions should be added to them regularly. (You’re free to contribute as well!) Commits history in migration branches is well structured and might serve as additional documentation with even more details than I could cover in this article.

    Now, let’s get our hands dirty! We have a long way ahead, so don’t expect it to be a smooth ride. It’s up to you to decide how you want to follow along with this article, but you could do the following:

    • Clone the jquery branch from the Frankenstein TodoMVC repository and strictly follow all of the instructions below.
    • Alternatively, you can open a branch dedicated to either migration to React or migration to Vue from the Frankenstein Demo repository and follow along with commits history.
    • Alternatively, you can relax and keep reading because I am going to highlight the most critical code right here, and it’s much more important to understand the mechanics of the process rather than the actual code.

    I’d like to mention one more time that we’ll strictly be following the steps presented in the theoretical first part of the article.

    Let’s dive right in!

    1. Identify Microservices
    2. Allow Host-to-Alien Access
    3. Write An Alien Microservice/Component
    4. Write Web Component Wrapper Around Alien Service
    5. Replace Host Service With Web Component
    6. Rinse & Repeat For All Of Your Components
    7. Switch To Alien

    1. Identify Microservices

    As Part 1 suggests, in this step, we have to structure our application into small, independent services dedicated to one particular job. The attentive reader might notice that our to-do application is already small and independent and can represent one single microservice on its own. This is how I would treat it myself if this application would live in some broader context. Remember, however, that the process of identifying microservices is entirely subjective and there is no one correct answer.

    So, in order to see the process of Frankenstein Migration in more detail, we can go a step further and split this to-do application into two independent microservices:

    1. An input field for adding a new item.
      This service can also contain the application’s header, based purely on positioning proximity of these elements.
    2. A list of already added items.
      This service is more advanced, and together with the list itself, it also contains actions like filtering, list item’s actions, and so on.
    TodoMVC application split into two independent microservices TodoMVC application split into two independent microservices. (Large preview)

    Tip: To check whether the picked services are genuinely independent, remove HTML markup, representing each of these services. Make sure that the remaining functions still work. In our case, it should be possible to add new entries into localStorage (that this application is using as storage) from the input field without the list, while the list still renders the entries from localStorage even if the input field is missing. If your application throws errors when you remove markup for potential microservice, take a look at the “Refactor If Needed” section in Part 1 for an example of how to deal with such cases.

    Of course, we could go on and split the second service and the listing of the items even further into independent microservices for each particular item. However, it might be too granular for this example. So, for now, we conclude that our application is going to have two services; they are independent, and each of them works towards its own particular task. Hence, we have split our application into microservices.

    2. Allow Host-to-Alien Access

    Let me briefly remind you of what these are.

    • Host
      This is what our current application is called. It is written with the framework from which we’re about to move away from. In this particular case, our jQuery application.
    • Alien
      Simply put, this one’s a gradual re-write of Host on the new framework that we are about to move to. Again, in this particular case, it’s a React or Vue application.

    The rule of thumb when splitting Host and Alien is that you should be able to develop and deploy any of them without breaking the other one — at any point in time.

    Keeping Host and Alien independent from each other is crucial for Frankenstein Migration. However, this makes arranging communication between the two a bit challenging. How do we allow Host access Alien without smashing the two together?

    Adding Alien As A Submodule Of Your Host

    Even though there are several ways to achieve the setup we need, the simplest form of organizing your project to meet this criterion is probably git submodules. This is what we’re going to use in this article. I’ll leave it up to you to read carefully about how submodules in git work in order to understand limitations and gotchas of this structure.

    The general principles of our project’s architecture with git submodules should look like this:

    • Both Host and Alien are independent and are kept in separate git repositories;
    • Host references Alien as a submodule. At this stage, Host picks a particular state (commit) of Alien and adds it as, what looks like, a subfolder in Host’s folder structure.
    React TodoMVC added as a git submodule into jQuery TodoMVC application React TodoMVC added as a git submodule into jQuery TodoMVC application. (Large preview)

    The process of adding a submodule is the same for any application. Teaching git submodules is beyond the scope of this article and is not directly related to Frankenstein Migration itself. So let’s just take a brief look at the possible examples.

    In the snippets below, we use the React direction as an example. For any other migration direction, replace react with the name of a branch from Frankenstein TodoMVC or adjust to custom values where needed.

    If you follow along using the original jQuery TodoMVC application:

    $ git submodule add -b react react
    $ git submodule update --remote
    $ cd react
    $ npm i

    If you follow along with migration/jquery-to-react (or any other migration direction) branch from the Frankenstein Demo repository, the Alien application should already be in there as a git submodule, and you should see a respective folder. However, the folder is empty by default, and you need to update and initialize the registered submodules.

    From the root of your project (your Host):

    $ git submodule update --init
    $ cd react
    $ npm i

    Note that in both cases we install dependencies for the Alien application, but those become sandboxed to the subfolder and won’t pollute our Host.

    After adding the Alien application as a submodule of your Host, you get independent (in terms of microservices) Alien and Host applications. However, Host considers Alien a subfolder in this case, and obviously, that allows Host to access Alien without a problem.

    3. Write An Alien Microservice/Component

    At this step, we have to decide what microservice to migrate first and write/use it on the Alien’s side. Let’s follow the same order of services we identified in Step 1 and start with the first one: input field for adding a new item. However, before we begin, let’s agree that beyond this point, we are going to use a more favorable term component instead of microservice or service as we are moving towards the premises of frontend frameworks and the term component follows the definitions of pretty much any modern framework.

    Branches of Frankenstein TodoMVC repository contain a resulting component that represents the first service “Input field for adding a new item” as a Header component:

    Writing components in the framework of your choice is beyond the scope of this article and is not part of Frankenstein Migration. However, there are a couple of things to keep in mind while writing an Alien component.


    First of all, the components in Alien should follow the same principle of independence, previously set up on the Host’s side: components should not depend on other components in any way.


    Thanks to the independence of the services, most probably, components in your Host communicate in some well-established way be it a state management system, communication through some shared storage or, directly via a system of DOM events. “Interoperability” of Alien components means that they should be able to connect to the same source of communication, established by Host, to dispatch information about its state changes and listen to changes in other components. In practice, this means that if components in your Host communicate via DOM events, building your Alien component exclusively with state management in mind won’t work flawlessly for this type of migration, unfortunately.

    As an example, take a look at the js/storage.js file that is the primary communication channel for our jQuery components:

    fetch: function() {
      return JSON.parse(localStorage.getItem(STORAGE_KEY) || "[]");
    save: function(todos) {
      localStorage.setItem(STORAGE_KEY, JSON.stringify(todos));
      var event = new CustomEvent("store-update", { detail: { todos } });

    Here, we use localStorage (as this example is not security-critical) to store our to-do items, and once the changes to the storage get recorded, we dispatch a custom DOM event on the document element that any component can listen to.

    At the same time, on the Alien’s side (let’s say React) we can set up as complex state management communication as we want. However, it’s probably smart to keep it for the future: to successfully integrate our Alien React component into Host, we have to connect to the same communication channel used by Host. In this case, it’s localStorage. To make things simple, we just copied over Host’s storage file into Alien and hooked up our components to it:

    import todoStorage from "../storage";
    class Header extends Component {
      constructor(props) {
        this.state = {
          todos: todoStorage.fetch()
      componentDidMount() {
        document.addEventListener("store-update", this.updateTodos);
      componentWillUnmount() {
        document.removeEventListener("store-update", this.updateTodos);
      componentDidUpdate(prevProps, prevState) {
        if (prevState.todos !== this.state.todos) {

    Now, our Alien components can talk the same language with Host components and vice versa.

    4. Write Web Component Wrapper Around Alien Service

    Even though we’re now only on the fourth step, we have achieved quite a lot:

    • We’ve split our Host application into independent services which are ready to be replaced by Alien services;
    • We’ve set up Host and Alien to be completely independent of each other, yet very well connected via git submodules;
    • We’ve written our first Alien component using the new framework.

    Now it’s time to set up a bridge between Host and Alien so that the new Alien component could function in the Host.

    Reminder from Part 1: Make sure that your Host has a package bundler available. In this article, we rely on Webpack, but it doesn’t mean that the technique won’t work with Rollup or any other bundler of your choice. However, I leave the mapping from Webpack to your experiments.

    Naming Convention

    As mentioned in the previous article, we are going to use Web Components to integrate Alien into Host. On the Host’s side, we create a new file: js/frankenstein-wrappers/Header-wrapper.js. (It’s going to be our first Frankenstein wrapper.) Keep in mind that it’s a good idea to name your wrappers the same as your components in Alien application, e.g. just by adding a “-wrapper” suffix. You”ll see later on why this is a good idea, but for now, let’s agree that this means that if the Alien component is called Header.js (in React) or Header.vue (in Vue), the corresponding wrapper on the Host’s side should be called Header-wrapper.js.

    In our first wrapper, we begin with the fundamental boilerplate for registering a custom element:

    class FrankensteinWrapper extends HTMLElement {}
    customElements.define("frankenstein-header-wrapper", FrankensteinWrapper);

    Next, we have to initialize Shadow DOM for this element.

    Please refer to Part 1 to get reasoning on why we use Shadow DOM.

    class FrankensteinWrapper extends HTMLElement {
      connectedCallback() {
        this.attachShadow({ mode: "open" });

    With this, we have all the essential bits of the Web Component set up, and it’s time to add our Alien component into the mix. First of all, at the beginning of our Frankenstein wrapper, we should import all the bits responsible for the Alien component’s rendering.

    import React from "../../react/node_modules/react";
    import ReactDOM from "../../react/node_modules/react-dom";
    import HeaderApp from "../../react/src/components/Header";

    Here we have to pause for a second. Note that we do not import Alien’s dependencies from Host’s node_modules. Everything comes from the Alien itself that sits in react/ subfolder. That is why Step 2 is so important, and it is crucial to make sure the Host has full access to assets of Alien.

    Now, we can render our Alien component within Web Component’s Shadow DOM:

    connectedCallback() {
      ReactDOM.render(<HeaderApp />, this.shadowRoot);

    Note: In this case, React doesn’t need anything else. However, to render the Vue component, you need to add a wrapping node to contain your Vue component like the following:

    connectedCallback() {
      const mountPoint = document.createElement("div");
      this.attachShadow({ mode: "open" }).appendChild(mountPoint);
      new Vue({
        render: h => h(VueHeader)

    The reason for this is the difference in how React and Vue render components: React appends component to referenced DOM node, while Vue replaces referenced DOM node with the component. Hence, if we do .$mount(this.shadowRoot) for Vue, it essentially replaces the Shadow DOM.

    That’s all we have to do to our wrapper for now. The current result for Frankenstein wrapper in both jQuery-to-React and jQuery-to-Vue migration directions can be found over here:

    To sum up the mechanics of the Frankenstein wrapper:

    1. Create a custom element,
    2. Initiate Shadow DOM,
    3. Import everything needed for rendering an Alien component,
    4. Render the Alien component within the custom element’s Shadow DOM.

    However, this doesn’t render our Alien in Host automatically. We have to replace the existing Host markup with our new Frankenstein wrapper.

    Fasten your seatbelts, it may not be as straightforward as one would expect!

    5. Replace Host Service With Web Component

    Let’s go on and add our new Header-wrapper.js file to index.html and replace the existing header markup with the newly-created <frankenstein-header-wrapper> custom element.

    <!-- <header class="header">-->
    <!--   <h1>todos</h1>-->
    <!--   <input class="new-todo" placeholder="What needs to be done?" autofocus>-->
    <!-- </header>-->
    <script type="module"

    Unfortunately, this won’t work as simple as that. If you open a browser and check the console, there is the Uncaught SyntaxError waiting for you. Depending on the browser and its support for ES6 modules, it will either be related to ES6 imports or to the way the Alien component gets rendered. Either way, we have to do something about it, but the problem and solution should be familiar and clear to most of the readers.

    5.1. Update Webpack and Babel where needed

    We should involve some Webpack and Babel magic before integrating our Frankenstein wrapper. Wrangling these tools is beyond the scope of the article, but you can take a look at the corresponding commits in the Frankenstein Demo repository:

    Essentially, we set up the processing of the files as well as a new entry point frankenstein in Webpack’s configuration to contain everything related to Frankenstein wrappers in one place.

    Once Webpack in Host knows how to process the Alien component and Web Components, we’re ready to replace Host’s markup with the new Frankenstein wrapper.

    5.2. Actual Component’s Replacement

    The component’s replacement should be straightforward now. In index.html of your Host, do the following:

    1. Replace <header class="header"> DOM element with <frankenstein-header-wrapper>;
    2. Add a new script frankenstein.js. This is the new entry point in Webpack that contains everything related to Frankenstein wrappers.
    <!-- We replace <header class="header"> -->
    <script src="./frankenstein.js"></script>

    That’s it! Restart your server if needed and witness the magic of the Alien component integrated into Host.

    However, something still seemd to be is missing. The Alien component in the Host context doesn’t look the same way as it does in the context of the standalone Alien application. It’s simply unstyled.

    Unstyled Alien React component after being integrated into Host Unstyled Alien React component after being integrated into Host (Large preview)

    Why is it so? Shouldn’t the component’s styles be integrated with the Alien component into Host automatically? I wish they would, but as in too many situations, it depends. We’re getting to the challenging part of Frankenstein Migration.

    5.3. General Information On The Styling Of The Alien Component

    First of all, the irony is that there is no bug in the way things work. Everything is as it’s designed to work. To explain this, let’s briefly mention different ways of styling components.

    Global Styles

    We all are familiar with these: global styles can be (and usually are) distributed without any particular component and get applied to the whole page. Global styles affect all DOM nodes with matching selectors.

    A few examples of global styles are <style> and <link rel="stylesheet"> tags found into your index.html. Alternatively, a global stylesheet can be imported into some root JS module so that all components could get access to it as well.

    The problem of styling applications in this way is obvious: maintaining monolithic stylesheets for large applications becomes very hard. Also, as we saw in the previous article, global styles can easily break components that are rendered straight in the main DOM tree like it is in React or Vue.

    Bundled Styles

    These styles usually are tightly coupled with a component itself and are rarely distributed without the component. The styles typically reside in the same file with the component. Good examples of this type of styling are styled-components in React or CSS Modules and Scoped CSS in single file components in Vue. However, no matter the variety of tools for writing bundled styles, the underlying principle in most of them is the same: the tools provide a scoping mechanism to lock down styles defined in a component so that the styles don’t break other components or global styles.

    Why Could Scoped Styles Be Fragile?

    In Part 1, when justifying the use of Shadow DOM in Frankenstein Migration, we briefly covered the topic of scoping vs. encapsulation) and how encapsulation of Shadow DOM is different from scoping styling tools. However, we did not explain why scoping tools provide such fragile styling for our components, and now, when we faced the unstyled Alien component, it becomes essential for understanding.

    All scoping tools for modern frameworks work similarly:

    • You write styles for your component in some way without thinking much about scope or encapsulation;
    • You run your components with imported/embedded stylesheets through some bundling system, like Webpack or Rollup;
    • The bundler generates unique CSS classes or other attributes, creating and injecting individual selectors for both your HTML and corresponding stylesheets;
    • The bundler makes a <style> entry in the <head> of your document and puts your components’ styles with unique mingled selectors in there.

    That’s pretty much it. It does work and works fine in many cases. Except for when it does not: when styles for all components live in the global styling scope, it becomes easy to break those, for example, using higher specificity. This explains the potential fragility of scoping tools, but why is our Alien component completely unstyled?

    Let’s take a look at the current Host using DevTools. When inspecting the newly-added Frankenstein wrapper with the Alien React component, for example, we can see something like this:

    Frankenstein wrapper with Alien component inside. Note unique CSS classes on the Alien’s nodes. Frankenstein wrapper with Alien component inside. Note unique CSS classes on the Alien’s nodes. (Large preview)

    So, Webpack does generate unique CSS classes for our component. Great! Where are the styles then? Well, the styles are precisely where they are designed to be — in the document’s <head>.

    While Alien component is within Frankenstein wrapper, its styles are in document’s head. While Alien component is within Frankenstein wrapper, its styles are in document’s <head>. (Large preview)

    So everything works as it should, and this is the main problem. Since our Alien component resides in Shadow DOM, and as explained in Part #1, Shadow DOM provides full encapsulation of components from the rest of the page and global styles, including those newly-generated stylesheets for the component that cannot cross the shadow border and get to the Alien component. Hence, the Alien component is left unstyled. However, now, the tactics of solving the problem should be clear: we should somehow place the component’s styles in the same Shadow DOM where our component resides (instead of the document’s <head>).

    5.4. Fixing Styles For The Alien Component

    Up until now, the process of migrating to any framework was the same. However, things start diverging here: every framework has its recommendations on how to style components, and hence, the ways of tackling the problem differ. Here, we discuss most common cases but, if the framework you work with uses some unique way of styling components, you need to keep in mind the basic tactics such as putting the component’s styles into Shadow DOM instead of <head>.

    In this chapter, we are covering fixes for:

    • Bundled styles with CSS Modules in Vue (tactics for Scoped CSS are the same);
    • Bundled styles with styled-components in React;
    • Generic CSS Modules and global styles. I combine these because CSS Modules, in general, are very similar to the global stylesheets and can be imported by any component making the styles disconnected from any particular component.

    Constraints first: anything we do to fix styling should not break the Alien component itself. Otherwise, we lose the independence of our Alien and Host systems. So, to address the styling issue, we are going to rely on either bundler’s configuration or the Frankenstein wrapper.

    Bundled Styles In Vue And Shadow DOM

    If you’re writing a Vue application, then you’re most probably using single file components. If you’re also using Webpack, you should be familiar with two loaders vue-loader and vue-style-loader. The former allows you to write those single file components while the latter dynamically injects the component’s CSS into a document as a <style> tag. By default, vue-style-loader injects the component’s styles into the document’s <head>. However, both packages accept the shadowMode option in configuration which allows us to easily change the default behavior and inject styles (as the option’s name implies) into Shadow DOM. Let’s see it in action.

    Webpack Configuration

    At a bare minimum, the Webpack configuration file should contain the following:

    const VueLoaderPlugin = require('vue-loader/lib/plugin');
    module: {
      rules: [
          test: /\.vue$/,
          loader: 'vue-loader',
          options: {
            shadowMode: true
          test: /\.css$/,
          include: path.resolve(__dirname, '../vue'),
          use: [
              options: {
                shadowMode: true
      plugins: [
        new VueLoaderPlugin()

    In a real application, your test: /\.css$/ block will be more sophisticated (probably involving the oneOf rule) to account for both Host and Alien configurations. However, in this case, our jQuery is styled with simple <link rel="stylesheet"> in index.html, so we don’t build styles for Host via Webpack, and it’s safe to cater for Alien only.

    Wrapper Configuration

    In addition to Webpack configuration, we also need to update our Frankenstein wrapper, pointing Vue to the correct Shadow DOM. In our Header-wrapper.js, rendering of the Vue component should include the shadowRoot property leading to shadowRoot of our Frankenstein wrapper:

    new Vue({
      shadowRoot: this.shadowRoot,
      render: h => h(VueHeader)

    After you update the files and restart your server, you should be getting something like this in your DevTools:

    Styles bundled with Alien Vue component placed within Frankenstein wrapper with all unique CSS classes preserved. Styles bundled with Alien Vue component placed within Frankenstein wrapper with all unique CSS classes preserved. (Large preview)

    Finally, styles for the Vue component are within our Shadow DOM. At the same time, your application should look like this:

    Header component starts to look more like it should. However, something is still missing. Header component starts to look more like it should. However, something is still missing. (Large preview)

    We start getting something resembling our Vue application: styles bundled with the component, are injected into the wrapper’s Shadow DOM, but the component still looks not as it is supposed to. The reason is that in the original Vue application, the component is styled not only with the bundled styles but also partially with global styles. However, before fixing the global styles, we have to get our React integration to the same state as the Vue one.

    Bundled Styles In React And Shadow DOM

    Because there are many ways one can style a React component, the particular solution to fix an Alien component in Frankenstein Migration depends on the way we style the component in the first place. Let’s briefly cover the most commonly used alternatives.


    styled-components is one of the most popular ways of styling React components. For the Header React component, styled-components is precisely the way we style it. Since this is a classic CSS-in-JS approach, there is no file with a dedicated extension that we could hook our bundler onto as we do for .css or .js files, for example. Luckily, styled-components allow the injection of component’s styles into a custom node (Shadow DOM in our case) instead of the document’s headwith the help of the StyleSheetManager helping component. It is a pre-defined component, installed with the styled-components package that accepts target property, defining “an alternate DOM node to inject styles info”. Exactly what we need! Moreover, we do not even need to change our Webpack configuration: everything is up to our Frankenstein wrapper.

    We should update our Header-wrapper.js that contains the React Alien component with the following lines:

    import { StyleSheetManager } from "../../react/node_modules/styled-components";
    const target = this.shadowRoot;
      <StyleSheetManager target={target}>
        <HeaderApp />

    Here, we import the StyleSheetManager component (from Alien, and not from Host) and wrap our React component with it. At the same time, we send the target property pointing to our shadowRoot. That’s it. If you restart the server, you have to see something like this in your DevTools:

    Styles bundled with React Alien component placed within Frankenstein wrapper with all unique CSS classes preserved. Styles bundled with React Alien component placed within Frankenstein wrapper with all unique CSS classes preserved. (Large preview)

    Now, our component’s styles are in Shadow DOM instead of <head>. This way, the rendering of our app now resembles what we have seen with the Vue app previously.

    After moving bundled styles into Frankenstein wrapper, the Alien React component begins to look better. However, we’re not there yet. After moving bundled styles into Frankenstein wrapper, the Alien React component begins to look better. However, we’re not there yet. (Large preview)

    Same story: styled-components are responsible just for the bundled part of the React component’s styles, and the global styles manage the remaining bits. We get back to global styles in a bit after we review one more type of styling components.

    CSS Modules

    If you take a closer look at the Vue component that we have fixed earlier, you might notice that CSS Modules is precisely the way we style that component. However, even if we style it with Scoped CSS (another recommended way of styling Vue components) the way we fix our unstyled component doesn’t change: it is still up to vue-loader and vue-style-loader to handle it through shadowMode: true option.

    When it comes to CSS Modules in React (or any other system using CSS Modules without any dedicated tools), things get a bit more complicated and less flexible, unfortunately.

    Let’s take a look at the same React component which we’ve just integrated, but this time styled with CSS Modules instead of styled-components. The main thing to note in this component is a separate import for stylesheet:

    import styles from './Header.module.css'

    The .module.css extension is a standard way to tell React applications built with the create-react-app utility that the imported stylesheet is a CSS Module. The stylesheet itself is very basic and does precisely the same our styled-components do.

    Integrating CSS modules into a Frankenstein wrapper consists of two parts:

    • Enabling CSS Modules in bundler,
    • Pushing resulting stylesheet into Shadow DOM.

    I believe the first point is trivial: all you need to do is set { modules: true } for css-loader in your Webpack configuration. Since, in this particular case, we have a dedicated extension for our CSS Modules (.module.css), we can have a dedicated configuration block for it under the general .css configuration:

      test: /\.css$/,
      oneOf: [
          test: /\.module\.css$/,
          use: [
              loader: 'css-loader',
              options: {
                modules: true,

    Note: A modules option for css-loader is all we have to know about CSS Modules no matter whether it’s React or any other system. When it comes to pushing resulting stylesheet into Shadow DOM, however, CSS Modules are no different from any other global stylesheet.

    By now, we went through the ways of integrating bundled styles into Shadow DOM for the following conventional scenarios:

    • Vue components, styled with CSS Modules. Dealing with Scoped CSS in Vue components won’t be any different;
    • React components, styled with styled-components;
    • Components styled with raw CSS Modules (without dedicated tools like those in Vue). For these, we have enabled support for CSS modules in Webpack configuration.

    However, our components still don’t look as they are supposed to because their styles partially come from global styles. Those global styles do not come to our Frankenstein wrappers automatically. Moreover, you might get into a situation in which your Alien components are styled exclusively with global styles without any bundled styles whatsoever. So let’s finally fix this side of the story.

    Global Styles And Shadow DOM

    Having your components styled with global styles is neither wrong nor bad per se: every project has its requirements and limitations. However, the best you can do for your components if they rely on some global styles is to pull those styles into the component itself. This way, you have proper easy-to-maintain self-contained components with bundled styles.

    Nevertheless, it’s not always possible or reasonable to do so: several components might share some styling, or your whole styling architecture could be built using global stylesheets that are split into the modular structure, and so on.

    So having an opportunity to pull in global styles into our Frankenstein wrappers wherever it’s required is essential for the success of this type of migration. Before we get to an example, keep in mind that this part is the same for pretty much any framework of your choice — be it React, Vue or anything else using global stylesheets!

    Let’s get back to our Header component from the Vue application. Take a look at this import:

    import "todomvc-app-css/index.css";

    This import is where we pull in the global stylesheet. In this case, we do it from the component itself. It’s only one way of using global stylesheet to style your component, but it’s not necessarily like this in your application.

    Some parent module might add a global stylesheet like in our React application where we import index.css only in index.js, and then our components expect it to be available in the global scope. Your component’s styling might even rely on a stylesheet, added with <style> or <link> to your index.html. It doesn’t matter. What matters, however, is that you should expect to either import global stylesheets in your Alien component (if it doesn’t harm the Alien application) or explicitly in the Frankenstein wrapper. Otherwise, the wrapper would not know that the Alien component needs any stylesheet other than the ones already bundled with it.

    Caution. If there are many global stylesheets to be shared between Alien components and you have a lot of such components, this might harm the performance of your Host application under the migration period.

    Here is how import of a global stylesheet, required for the Header component, is done in Frankenstein wrapper for React component:

    // we import directly from react/, not from Host
    import '../../react/node_modules/todomvc-app-css/index.css'

    Nevertheless, by importing a stylesheet this way, we still bring the styles to the global scope of our Host, while what we need is to pull in the styles into our Shadow DOM. How do we do this?

    Webpack configuration for global stylesheets & Shadow DOM

    First of all, you might want to add an explicit test to make sure that we process only the stylesheets coming from our Alien. In case of our React migration, it will look similar to this:

    test: /\.css$/,
    oneOf: [
      // this matches stylesheets coming from /react/ subfolder
        test: /\/react\//,
        use: []

    In case of Vue application, obviously, you change test: /\/react\// with something like test: /\/vue\//. Apart from that, the configuration will be the same for any framework. Next, let’s specify the required loaders for this block.

    use: [
        loader: 'style-loader',
        options: {

    Two things to note. First, you have to specify modules: true in css-loader’s configuration if you’re processing CSS Modules of your Alien application.

    Second, we should convert styles into <style> tag before injecting those into Shadow DOM. In the case of Webpack, for that, we use style-loader. The default behavior for this loader is to insert styles into the document’s head. Typically. And this is precisely what we don’t want: our goal is to get stylesheets into Shadow DOM. However, in the same way we used target property for styled-components in React or shadowMode option for Vue components that allowed us to specify custom insertion point for our <style> tags, regular style-loader provides us with nearly same functionality for any stylesheet: the insert configuration option is exactly what helps us achieve our primary goal. Great news! Let’s add it to our configuration.

      loader: 'style-loader',
      options: {
        insert: 'frankenstein-header-wrapper'

    However, not everything is so smooth here with a couple of things to keep in mind.

    Global stylesheets and insert option of style-loader

    If you check documentation for this option, you notice, that this option takes one selector per configuration. This means that if you have several Alien components requiring global styles pulled into a Frankenstein wrapper, you have to specify style-loader for each of the Frankenstein wrappers. In practice, this means that you, probably, have to rely on oneOf rule in your configuration block to serve to all wrappers.

      test: /\/react\//,
      oneOf: [
          test: /1-TEST-FOR-ALIEN-FILE-PATH$/,
          use: [
              loader: 'style-loader',
              options: {
                insert: '1-frankenstein-wrapper'
          test: /2-TEST-FOR-ALIEN-FILE-PATH$/,
          use: [
              loader: 'style-loader',
              options: {
                insert: '2-frankenstein-wrapper'
        // etc.

    Not very flexible, I agree. Nevertheless, it’s not a big deal as long as you don’t have hundreds of components to migrate. Otherwise, it might make your Webpack configuration hard to maintain. The real problem, however, is that we can not write a CSS selector for Shadow DOM.

    Trying to solve this, we might note that the insert option can also take a function instead of a plain selector to specify more advanced logic for insertion. With this, we can use this option to insert stylesheets straight into Shadow DOM! In simplified form it might look similar to this:

    insert: function(element) {
      var parent = document.querySelector('frankenstein-header-wrapper').shadowRoot;
      parent.insertBefore(element, parent.firstChild);

    Tempting, isn’t it? However, this won’t work for our scenario or will work far from optimal. Our <frankenstein-header-wrapper> is indeed available from index.html (because we added it in Step 5.2). But when Webpack processes all dependencies (incl. the stylesheets) for either an Alien component or a Frankenstein wrapper, Shadow DOM is not yet initialized in the Frankenstein wrapper: imports are processed before that. Hence, pointing insert straight to shadowRoot will result in an error.

    There is only one case when we can guarantee that Shadow DOM is initialized before Webpack processes our stylesheet dependency. If Alien component does not import a stylesheet itself and it becomes up to Frankenstein wrapper to import it, we might employ dynamic import and import the required stylesheet after we set up Shadow DOM:

    this.attachShadow({ mode: "open" });

    This will work: such import, combined with the insert configuration above, will indeed find correct Shadow DOM and insert <style> tag into it. Nevertheless, getting and processing stylesheet will take time, which means your users on a slow connection or slow devices might face a moment of the unstyled component before your stylesheet gets on its place within wrapper’s Shadow DOM.

    Unstyled Alien component gets rendered before the global stylesheet is imported and added to the Shadow DOM.Unstyled Alien component gets rendered before the global stylesheet is imported and added to the Shadow DOM. (Large preview)

    So all in all, even though insert accepts function, unfortunately, it’s not enough for us, and we have to fall back to plain CSS selectors like frankenstein-header-wrapper. This doesn’t place stylesheets into Shadow DOM automatically, however, and the stylesheets reside in <frankenstein-header-wrapper> outside of Shadow DOM.

    style-loader puts imported stylesheet into the Frankenstein wrapper, but outside of Shadow DOM. style-loader puts imported stylesheet into the Frankenstein wrapper, but outside of Shadow DOM. (Large preview)

    We need one more piece of the puzzle.

    Wrapper configuration for global stylesheets & Shadow DOM

    Luckily, the fix is quite straightforward on the wrapper’s side: when Shadow DOM gets initialized, we need to check for any pending stylesheets in the current wrapper and pull them into Shadow DOM.

    The current state of the global stylesheet’s import is as follows:

    • We import a stylesheet that has to be added into Shadow DOM. The stylesheet can be imported in either the Alien component itself or, explicitly in the Frankenstein wrapper. In the case of migration to React, for example, the import is initialized from the wrapper. However, in migration to Vue, the similar component itself imports the required stylesheet, and we don’t have to import anything in the wrapper.
    • As pointed out above, when Webpack processes .css imports for the Alien component, thanks to the insert option of style-loader, the stylesheets get injected into a Frankenstein wrapper, but outside of Shadow DOM.

    Simplified initialization of Shadow DOM in Frankenstein wrapper, should currently (before we pull in any stylesheets) look similar to this:

    this.attachShadow({ mode: "open" });
    ReactDOM.render(); // or `new Vue()`

    Now, to avoid flickering of the unstyled component, what we need to do now is pull in all the required stylesheets after initialization of the Shadow DOM, but before the Alien component’s rendering.

    this.attachShadow({ mode: "open" });
      .forEach(style => {
    ReactDOM.render(); // or new Vue({})

    It was a long explanation with a lot of details, but mainly, all it takes to pull in global stylesheets into Shadow DOM:

    • In Webpack configuration add style-loader with insert option pointing to required Frankenstein wrapper.
    • In the wrapper itself, pull in “pending” stylesheets after initialization of Shadow DOM, but before the Alien component’s rendering.

    After implementing these changes, your component should have everything it needs. The only thing you might want (this is not a requirement) to add is some custom CSS to fine-tune an Alien component in Host’s environment. You might even style your Alien component completely different when used in Host. It goes beyond the main point of the article, but you look at the final code for the wrapper, where you can find examples of how to override simple styles on the wrapper level.

    You can also take a look at the Webpack configuration at this step of migration:

    And finally, our components look exactly as we intended them to look like.

    Result of migrating Header component written with Vue and React. The listing of the to-do items is still jQuery application. Result of migrating Header component written with Vue and React. The listing of the to-do items is still jQuery application. (Large preview)

    5.5. Summary of fixing styles for the Alien component

    This is a great moment to sum up what we have learned in this chapter so far. It might look like we had to do enormous work to fix styling of the Alien component; however, it all boils down to:

    • Fixing bundled styles implemented with styled-components in React or CSS modules and Scoped CSS in Vue is as simple as a couple of lines in Frankenstein wrapper or Webpack configuration.
    • Fixing styles, implemented with CSS Modules, starts with just one line in css-loader configuration. After that, CSS Modules are treated as a global stylesheet.
    • Fixing global stylesheets requires configuring style-loader package with insert option in Webpack, and updating Frankenstein wrapper to pull in the stylesheets into Shadow DOM at the right moment of the wrapper’s lifecycle.

    After all, we have got properly styled Alien component migrated into the Host. There is just one thing that might or might not bother you depending on what framework you migrate to, however.

    Good news first: If you’re migrating to Vue, the demo should be working just fine, and you should be able to add new to-do items from migrated Vue component. However, if you’re migrating to React, and try to add a new to-do item, you won’t succeed. Adding new items simply doesn’t work, and no entries are added to the list. But why? What’s the problem? No prejudice, but React has its own opinions on some things.

    5.6. React And JS Events In Shadow DOM

    No matter what React documentation tells you, React is not very friendly to Web Components. The simplicity of the example in the documentation doesn’t stand any criticism, and anything more complicated than rendering a link in Web Component requires some research and investigation.

    As you have seen while fixing the styling for our Alien component, contrary to Vue where things fit Web Components nearly out of the box, React is not that Web Components-ready. For now, we have an understanding of how to make React components at least look good within Web Components, but there is also functionality and JavaScript events to fix.

    Long story short: Shadow DOM encapsulates events and retargets them, while React does not support this behavior of Shadow DOM natively and hence does not catch events coming from within Shadow DOM. There are deeper reasons for this behavior, and there is even an open issue in React’s bug tracker if you want to dive into more details and discussions.

    Luckily, smart people prepared a solution for us. @josephnvu provided the basis for the solution, and Lukas Bombach converted it into react-shadow-dom-retarget-events npm module. So you can install the package, follow instructions on the packages’ page, update your wrapper’s code and your Alien component will magically start working:

    import retargetEvents from 'react-shadow-dom-retarget-events';

    If you want to have it more performant, you can make a local copy of the package (MIT license allows that) and limit the number of events to listen to as it is done in Frankenstein Demo repository. For this example, I know what events I need to retarget and specify only those.

    With this, we are finally (I know it was a long process) done with proper migration of the first styled and fully-functional Alien component. Get yourself a good drink. You deserve it!

    6. Rinse & Repeat For All Of Your Components

    After we migrated the first component, we should repeat the process for all of our components. In the case of Frankenstein Demo, there is only one left, however: the one, responsible for rendering the listing of to-do items.

    New Wrappers For New Components

    Let’s start with adding a new wrapper. Following the naming convention, discussed above (since our React component is called MainSection.js), the corresponding wrapper in migration to React should be called MainSection-wrapper.js. At the same time, a similar component in Vue is called Listing.vue, hence the corresponding wrapper in the migration to Vue should be called Listing-wrapper.js. However, no matter the naming convention, the wrapper itself is going to be nearly identical to the one we already have:

    There is just one interesting thing we introduce in this second component in React application. Sometimes, for that or another reason, you might want to use some jQuery plugin in your components. In case of our React component, we introduced two things:

    • Tooltip plugin from Bootstrap that uses jQuery,
    • A toggle for CSS classes like .addClass() and .removeClass().

      Note: This use of jQuery for adding/removing classes is purely illustrative. Please don’t use jQuery for this scenario in real projects — rely on plain JavaScript instead.

    Of course, it might look weird to introduce jQuery in an Alien component when we migrate away from jQuery, but your Host might be different from the Host in this example — you might migrate away from AngularJS or anything else. Also, jQuery functionality in a component and global jQuery are not necessarily the same thing.

    However, the problem is that even if you confirm that component works just fine in the context of your Alien application, when you put it into Shadow DOM, your jQuery plugins and other code that rely on jQuery just won’t work.

    jQuery In Shadow DOM

    Let’s take a look at a general initialization of a random jQuery plugin:


    This way, all elements with .my-selector are going to be processed by fancyPlugin. This form of initialization assumes that .my-selector is present in global DOM. However, once such an element is put into Shadow DOM, just like with styles, shadow boundaries prevent jQuery from sneaking into it. As a result, jQuery can not find elements within Shadow DOM.

    The solution is to provide an optional second parameter to the selector that defines the root element for jQuery to search from. And this is, where we can supply our shadowRoot.

    $('.my-selector', this.shadowRoot).fancyPlugin();

    This way, jQuery selectors and, as a result, the plugins will work just fine.

    Keep in mind though that the Alien components are intended to be used both: in Alien without shadow DOM, and in Host within Shadow DOM. Hence we need a more unified solution that would not assume the presence of Shadow DOM by default.

    Analyzing MainSection component in our React application, we find that it sets documentRoot property.

    this.documentRoot = this.props.root? this.props.root: document;

    So, we check for passed root property, and if it exists, this is what we use as documentRoot. Otherwise, we fall back to document.

    Here is the initialize of the tooltip plugin that uses this property:

    $('[data-toggle="tooltip"]', this.documentRoot).tooltip({
      container: this.props.root || 'body'

    As a bonus, we use the same root property to define a container for injecting the tooltip in this case.

    Now, when the Alien component is ready to accept the root property, we update rendering of the component in corresponding Frankenstein wrapper:

    // `appWrapper` is the root element within wrapper’s Shadow DOM.
    ReactDOM.render(<MainApp root={ appWrapper } />, appWrapper);

    And that’s it! The component works as fine in Shadow DOM as it does in the global DOM.

    Webpack configuration for multi-wrappers scenario

    The exciting part is happening in Webpack’s configuration when using several wrappers. Nothing changes for the bundled styles like those CSS Modules in Vue components, or styled-components in React. However, global styles should get a little twist now.

    Remember, we said that style-loader (responsible for injecting global stylesheets into correct Shadow DOM) is inflexible as it takes just one selector at a time for its insert option. This means that we should split the .css rule in Webpack to have one sub-rule per wrapper using oneOf rule or similar, if you’re on a bundler other than Webpack.

    It’s always easier to explain by using an example, so let’s talk about the one from migration to Vue this time (the one in migration to React, however, is nearly identical):

    oneOf: [
        issuer: /Header/,
        use: [
            loader: 'style-loader',
            options: {
              insert: 'frankenstein-header-wrapper'
        issuer: /Listing/,
        use: [
            loader: 'style-loader',
            options: {
              insert: 'frankenstein-listing-wrapper'

    I have excluded css-loader as its configuration is the same in all cases. Let’s talk about style-loader instead. In this configuration, we insert <style> tag into either *-header-* or *-listing-*, depending on the name of the file requesting that stylesheet (issuer rule in Webpack). But we have to remember that the global stylesheet required for rendering an Alien component might be imported in two places:

    • The Alien component itself,
    • A Frankenstein wrapper.

    And here, we should appreciate the naming convention for wrappers, described above, when the name of an Alien component and a corresponding wrapper match. If, for example, we have a stylesheet, imported in a Vue component called Header.vue, it gets to correct *-header-* wrapper. At the same time, if we, instead, import the stylesheet in the wrapper, such stylesheet follows precisely the same rule if the wrapper is called Header-wrapper.js without any changes in the configuration. Same thing for the Listing.vue component and its corresponding wrapper Listing-wrapper.js. Using this naming convention, we reduce the configuration in our bundler.

    After all of your components migrated, it’s time for the final step of the migration.

    7. Switch To Alien

    At some point, you find out that the components you identified at the very first step of the migration, are all replaced with Frankenstein wrappers. No jQuery application is left really and what you have is, essentially, the Alien application that is glued together using the means of Host.

    For example, the content part of index.html in the jQuery application — after migration of both microservices — looks something like this now:

    <section class="todoapp">

    At this moment, there is no point in keeping our jQuery application around: instead, we should switch to Vue application and forget about all of our wrappers, Shadow DOM and fancy Webpack configurations. To do this, we have an elegant solution.

    Let’s talk about HTTP requests. I will mention Apache configuration here, but this is just an implementation detail: doing the switch in Nginx or anything else should be as trivial as in Apache.

    Imagine that you have your site served from the /var/www/html folder on your server. In this case, your httpd.conf or httpd-vhost.conf should have an entry that points to that folder like:

    DocumentRoot "/var/www/html"

    To switch your application after the Frankenstein migration from jQuery to React, all you need to do is update the DocumentRoot entry to something like:

    DocumentRoot "/var/www/html/react/build"

    Build your Alien application, restart your server, and your application is served directly from the Alien’s folder: the React application served from the react/ folder. However, the same is true for Vue, of course, or any other framework you have migrated too. This is why it is so vital to keep Host and Alien completely independent and functional at any point in time because your Alien becomes your Host at this step.

    Now you can safely remove everything around your Alien’s folder, including all the Shadow DOM, Frankenstein wrappers and any other migration-related artifact. It was a rough path at moments, but you have migrated your site. Congratulations!


    We definitely went through somewhat rough terrain in this article. However, after we started with a jQuery application, we have managed to migrate it to both Vue and React. We have discovered some unexpected and not-so-trivial issues along the way: we had to fix styling, we had to fix JavaScript functionality, introduce some bundler configurations, and so much more. However, it gave us a better overview of what to expect in real projects. In the end, we have got a contemporary application without any remaining bits from the jQuery application even though we had all the rights to be skeptical about the end result while the migration was in progress.

    After the switch to Alien, Frankenstein can be retired. After the switch to Alien, Frankenstein can be retired. (Large preview)

    Frankenstein Migration is neither a silver bullet nor should it be a scary process. It’s just the defined algorithm, applicable to a lot of projects, that helps to transform projects into something new and robust in a predictable manner.

    Smashing Editorial(dm, yk, il)

    September 26 2019


    Frankenstein Migration: Framework-Agnostic Approach (Part 1)

    Frankenstein Migration: Framework-Agnostic Approach (Part 1)

    Frankenstein Migration: Framework-Agnostic Approach (Part 1)

    Denys Mishunov

    Migration, according to Oxford Learner’s Dictionary, is “the slow or gradual movement of something from one place to another.” This term describes many things and phenomena in our world — both with positive and negative tint. In software development, the word “migration,” when we need to upgrade or change technology in a project, usually falls under the latter case, unfortunately.

    “Good,” “Fast,” “Cheap”. We used to pick only two in many situations when we need to make a choice either in development, in business, or in life in general. Typically, front-end migration, which is the main subject of this article, does not allow even that: “cheap” is out of reach for any migration, and you have to pick either “good” or “fast.” However, you cannot have both. Typically.

    Frankenstein monster should not necessarily be terrible. He can be cute. Sometimes. Frankenstein monster should not necessarily be terrible. He can be cute. Sometimes. (Large preview)

    In an attempt of breaking the stereotypes, this article suggests a not-so-typical approach to framework-independent migration of front-end applications: the “Frankenstein Migration.” This approach allows us to combine “good” and “fast” while keeping the costs of migration at bay.

    It’s not a silver bullet, nonetheless. Instead, I like to think about it as a small migration revolution. And like any other revolution, this approach might have side-effects, issues, and people full of energy to claim that this is not going to work even before they try.

    We will certainly get to the potential issues of this approach further in the article, but bear with me and, maybe, you will still find one or two ideas useful for your next migration.

    Furthermore, the same approach that we are going to discuss can be used for a broader range of tasks that are not directly related to migration:

    • Combining different bits of your application, written in different frameworks. It could be useful for rapid prototyping, bootstrapping, and even production-ready experiments.
    • Decoupling different features of your application in order to be able to deploy without re-building the whole application. Maybe even set your core features on the more frequent release cycle. It can be useful in large projects. In particular, those running through CI/CD every time you push things into master (that might take very long) and helps to save time on feature releases.
    • This approach might even allow you to have flexible hiring policy: you could hire smart developers even if they do not work with the framework of your project just yet. Developers can keep using tools and frameworks they are comfortable with and bring value to your company from day 1 (especially valuable in startups) while learning how your project works and picking the framework of your choice.

    Nevertheless, this article is all about migration and before we dive deep into the dark waters of Frankenstein Migration, let’s see where we are with those “good” and “fast” migration alternatives to be aware of their strong as well as weak sides.

    “Good” Migration: Complete Re-Write

    Usually, complete re-write is considered to be a better way of migrating your applications in terms of quality. It makes sense: you’re writing your application from scratch, and hence, you can bring all of your experience and wisdom from current implementation into the new one right from the beginning, not as an afterthought. It is a big plus for this type of migration. However, there is a not-so-obvious problem with complete re-write.

    To achieve this quality, you need time. Sometimes, a lot of time. Alternatively, many developers dedicated exclusively to re-write. Not every company can afford these options. Because of this, the most suitable scenario for this type of migration is either a small/personal project without a need for developing new features all the time or the project that is not mission-critical for your business.

    To give you a perspective of time: once, I’ve been to a complete re-write of an application that took two years. Still, during all this time, the old project with all of its bugs was up and running. Nobody wanted to touch it and, instead, concentrated on the “new and shiny” one. Typically.

    As a summary for this type of migration:


    • Resulting quality.


    • The time required to get that quality to the end-user;
    • The amount of work to be done during complete re-write is overwhelming, making it hard to estimate the time and resources required for this type of migration upfront.

    Those who plan to migrate but cannot afford complete re-write due to time or resource constraints might want to look at the next migration type.

    “Fast” Migration: Gradual Migration

    Contrary to complete re-write, gradual migration does not require you to wait for the complete migration. Instead, you migrate application bit-by-bit and make those new bits available to your users as soon as they are ready. Calling this type of migration “fast” is a bit of a stretch, of course, if we talk about the whole application, but separate features clearly can be delivered to the users much faster. Though, let’s give gradual migration unbiased pros and cons as well:


    • When it comes to delivering separate application portions to the end-user, gradual migration is indeed faster than complete re-write since we don’t need to wait for the whole application to be re-written.
    • By delivering new, migrated bits gradually, we get feedback on them (from the end-users) as we go. It allows us to catch bugs and issues faster and in a more isolated manner, comparing to complete re-write, where we deploy the migrated application as a whole and might overlook some smaller issues or bugs.

    To better understand problems of gradual migration, try installing React in parallel with Vue in the same project as in Vue-to-React migration. I believe you have to truly enjoy digging configurations and solving console errors to enjoy this process. However, we don’t even need to get that deep. Let’s consider the following legacy example:

    Components, no matter CSS Modules, are very vulnerable to global styles. In this simple example, we have at least four ways to break the Vue component visually. Components, no matter CSS Modules, are very vulnerable to global styles. In this simple example, we have at least four ways to break the Vue component visually. (Source) (Large preview)

    Here, we are integrating a Vue component into a Vanilla JS application as in potential Vanilla-to-Vue migration scenario. CSS Modules are responsible for the styling of the Vue component and provide proper scope for your components. As you can see, however, even though styling for the Vue component tells the subheader to be green, it is entirely off, and the example presents as many as four (but there are really many more) trivial ways of breaking component’s styling.

    Also, other global styles getting into this Vue component can extend the look of our component entirely and, even though it might be seen as a feature in some projects, makes things hard to predict, maintain and is not necessarily what we want. This example reveals the most common and hard-to-tackle problem of gradual migration: the “Cascade” part of CSS can easily break components.

    This artificially simplified example also reveals several other big problems related to gradual migration:

    • Because we’re combining two different systems, the result might turn out very cluttered: we have to support two different systems with their dependencies, requirements, and opinions simultaneously in the same project. Different frameworks might require the same dependencies, but in different versions that result in version conflicts.
    • Since the integrated application (Vue in our case) is rendered in the main DOM tree, global scope in JavaScript is conflicts-prone: both systems might want to manipulate DOM nodes that do not belong to them.
    • Furthermore, let me repeat this, as we are going to get to this point several times in this article: Because of the global nature of this integration, CSS overflows from one system to another without much control, polluting the global scope the same way JavaScript does.

    To fix these issues (or at least to keep them at bay) we need to implement workarounds, hacks and implement development style for the whole team to follow. It all leads to lower, compromised-driven, result quality after gradual migration. It’s also harder to maintain such a project than that after complete re-write.

    Both of the existing options have limitations and constraints, but we still have to pick one if migration is required. However, should this choice be as painful? Wouldn’t it be great to combine the best parts of both somehow, while minimizing the negative side-effects? Is it possible at all?

    Let me introduce Frankenstein Migration to you.

    Frankenstein Migration. Part1: Theory

    This part of the series answers what Frankenstein Migration is. We are going to find out how it is different from other migration types. Also, most importantly, we are going to dive into the theory of technologies and approaches that make this type of migration even possible.

    Why "Frankenstein"?

    The name comes from the way the approach works. In essence, it provides a roadmap for two or more applications, written in entirely different frameworks, to work as one solid well-orchestrated body. Just like Victor Frankenstein built his monster in Mary Shelley’s book “Frankenstein; or, The Modern Prometheus”.

    People tend to be afraid of monsters. Typically. People tend to be afraid of monsters. Typically. (Large preview)

    Keep in mind that recently different people and organizations independently have explored the problem of combining different frameworks in the same project: Micro Frontends, Allegro Tech, etc. Frankenstein Migration, however, is an independent, structured approach to migration in the first place.

    There are two fundamental technologies/approaches in the heart of Frankenstein Migration:

    Microservices Architecture

    The main idea behind microservices (contrary to monolithic architecture) is that you architect your application with the help of isolated and independent services dedicated to one particular small job.

    I’ll repeat the things you need to keep in mind:

    • “independent”
    • “one job”
    Microservices architecture is a set of independent services that are all connected into a network. Microservices architecture is a set of independent services that are all connected into a network. (Large preview)

    In an application, such services get connected into a communicational network that can get new services added/removed/replaced easily at any time, and that’s what we call “microservices.” This flexible approach is well-established and widely-adopted by back-end and server architects. However, can we have real microservices on the frontend?

    Let’s take a look at the main features of service in such architecture:

    • Small in size,
    • Bounded by contexts,
    • Built and released with automated processes,
    • Autonomously developed, and
    • Independently deployable.

    The first three points are not a problem for front-end technologies. Pretty much all of the modern frameworks and libraries provide one or another type of abstraction to satisfy these three requirements. However, independence of services for both development and deployment has always been a problem for front-end technologies. Even in the landscape of modern frameworks that provide a paradigm of a component (like React or Vue), those components are usually still very dependent on the system and cannot be autonomous or independent from the framework that initialized them. You can always fall back to iframe, of course, and get this level of independence. However, let’s find a better — not so radical — alternative.

    There is one type of component that gets close to this level of independence, and that is Web Components. So this is the second building block of Frankenstein Migration.

    Web Components

    People say that it’s enough to mention “Web Components” to start a fight nowadays. People like Rich Harris even write blog posts about why they don’t use Web Components. However, the purpose of this article is not to convince you that Web Components are useful or to initiate a hot debate on the topic. Web Components is not a make-everything-OK tool. As with any other tool, there might be limitations and possible side effects.

    Serhii Kulykov provides a series of better-grounded articles on the subject and also curates a “Web Components the Right Way” repository in which you can find much more information for general Web Components discussion. However, when it comes to Frankenstein Migration, Web Components prove to be a very suitable instrument.

    Let’s take a quick look at the main elements of Web Components that make them suitable candidates for closing gaps in microservices adoption by the frontend:

    In particular, Shadow DOM is the tool capable of fixing the issues we typically meet in gradual migration and provides an actual encapsulation mechanism for component’s CSS. Previously, we mentioned that maintaining a cascade of CSS is problematic when we try to use components written with different frameworks or libraries side-by-side in the global scope.

    Now, let’s see how Shadow DOM solves this problem.

    CSS Scoping vs. Encapsulation. The Shadow DOM style

    The encapsulation mechanism of Shadow DOM is essential for understanding as it’s different from how popular tools like CSS Modules or scoped attribute in Vue work. These tools provide scoping for styles, defined in a component, without breaking global styles and other components. However, they don’t protect components from global styles leaking into the component (the very problem of cascade discussed above) and hence, potentially breaking your components.

    At the same time, styles defined within Shadow DOM are not only scoped to the current component but are also protected from global styles that don’t have explicit access to the internals of Shadow DOM no matter the specificity. To see it in action, take a look at the updated example:

    Here, we moved styles out of the Vue component, straight into the Shadow DOM and that’s what’s happening (automatic though) when you set up your Vue components to work within Shadow DOM. This example shows that Shadow DOM provides a mechanism for genuinely independent components that can be used in any context (library, framework) while preserving the look and functionality of these components.

    Now let’s talk through the main concepts and steps of Frankenstein Migration to see how exactly microservices and Web Components help us in the migration of front-end applications.

    Let’s assume you have a project that you want to migrate to another framework.

    Our demo project on a not-so-hot-anymore framework that we want to migrate. Our demo project on a not-so-hot-anymore framework that we want to migrate. (Large preview)

    It doesn’t matter what framework/library we migrate away from and what framework/library we want to get to; the principle and steps are the same for more or less any tool you pick (some generic exceptions are mentioned further in the article). That’s why Frankenstein Migration is called the “framework-agnostic” approach.

    Now, where do we start?

    1. Identify Microservices
    2. Allow Host-to-Alien Access
    3. Write An Alien Component
    4. Write Web Component Wrapper Around Alien Service
    5. Replace Host Service With Web Component
    6. Rinse And Repeat
    7. Switch To Alien

    1. Identify Microservices

    It is the core step, essential for the whole process’ success or failure. So we should dive more in-depth here.

    Technically, we have to split our existing application into microservices virtually. It is an entirely subjective process though and doesn’t have a “correct” answer. However, what does it mean in practice then?

    By “virtually” I mean that in general, you don’t need to change your existing application physically: it’s enough to have structure settled in any form even if only on paper.

    We have to have a clear split in our current application into services that are:

    • Independent;
    • Dedicated to one small job.

    An input field for adding new items to a database could be an example of a service: it’s dedicated to one particular job (adding new items) and does the job without dependency on any other service. Alternatively, the whole listing of items already added to the database: it’s trivial in functionality and, again, doesn’t depend on other components for listing items. It doesn’t sound too complicated, I believe, but that might be a deceptive feeling.

    Let’s start with the easy parts: If a framework in your current project is based on a concept of “component” (React, Vue), you probably already have a reasonable basis for this type of migration. You can treat every component of your application as a separate service in a microservices architecture.

    If your project currently is on a legacy basis (e.g. such as jQuery), you should turn on your imagination and think through how you would like to structure your application, following microservices’ principles of independence and one-job per service.

    We can structure our application any way we want to just as long as we follow the principles of microservices. We can structure our application any way we want to just as long as we follow the principles of microservices. (Large preview)

    Refactor If Needed

    I hate my ability to repeat things multiple times, but in this case, it makes much sense: be sure that your services (or components, or containers, or whatever you prefer to call your building blocks) do not depend on other services. Otherwise, both of the services should be treated as one — for the sake of independence and isolation.

    A simple test to make sure your service is appropriately independent: Remove HTML for your component/service from the Host and reload the application. If there are no JS errors in the console and the remaining part of the application works as expected, the service in question is most probably independent enough from the rest of the application.

    To give you a better explanation, let’s consider the following, artificially simplified, legacy example:


    <form id="form">
      <input id="inputTodo" type="text" placeholder="New Todo"/>
      <button type="submit">Add Todo</button>
    <ul id="listing" class="d-none"></ul>


    const form = document.getElementById("form");
    form.addEventListener("submit", ev => {
      const listing = document.getElementById("listing");
      const input = document.getElementById("inputTodo");
      const newEntry = document.createElement("li");
      newEntry.innerHTML = input.value;
      input.value = "";

    Here, #form expects #listing to be present in the markup as its submit handler updates the listing directly. Hence these two depend on each other, and we cannot split them into separate services: they are parts of the same job and help each other to serve the same purpose.

    However, as a possibly better alternative, we could refactor this code to make the two components independent from each other and satisfy the requirement of independence:


    function notifyAboutNewItem(ev) {
      const input = document.getElementById("inputTodo");
      const event = new CustomEvent("new-todo", { detail: { val: input.value } });
      input.value = "";
    function updateList(ev) {
      const listing = document.getElementById("listing");
      const newEntry = document.createElement("li");
      newEntry.innerHTML = ev.detail.val;
    document.getElementById("form").addEventListener("submit", notifyAboutNewItem);
    document.addEventListener("new-todo", updateList);

    Now, our #form and #listing components do not communicate with each other directly, but through the DOM event (it can be a state management or any other storing mechanism with notification instead): when a new item is added, notifyAboutNewItem() dispatches an event, while we subscribe #listing to listen to this event. Now any component can dispatch this event. Moreover, any component can listen to it: our components became independent from each other, and hence we can treat them separately in our migration.

    Too Small For A Service?

    Another thing to keep in mind: when splitting your application with already-existing components (like React or Vue) into services, some of your components might be too small for a proper service. It’s not to say they cannot be small, because nothing stops you from structuring your application as atomic as you wish, but most of the simple re-usable UI components (like the form button or input field in the previous example) are better included in broader services for the sake of minimizing work for you.

    On a larger scale, you can approach Step #1 as chaotic as you wish. You don’t need to start Frankenstein Migration with the global plan: you can start with just one element of your application. For example, split some complex <section> into services. Alternatively, you can structure your app one whole route or page at a time and then, maybe, your <section> becomes one single service. It doesn’t matter much; any structure is better than heavy, hard-to-maintain monolithic application. However, I would suggest being careful with the too granular approach — it’s boring and doesn’t give you many benefits in this case.

    My rule of thumb: you get the best flow of process with services that can be migrated and pushed into production in one week. If it takes less, then your services are a tad too small. If it takes longer, you might be trying to chew too many large pieces, so it’s better to split those. However, it all depends on your capacity and your project’s needs.

    After virtually splitting your current application into services, we’re ready to move on to the next step.

    2. Allow Host-to-Alien Access

    This should come as absolutely unclear title, of course. Neither have we discussed what is Host nor have we mentioned Alien yet. So let’s clear these out first.

    We have mentioned that services in our current application should be independent. However, this is not the only place where we strive for independence. Contrary to the typical gradual migration approach, where we put everything in the same pot and develop new components alongside the old ones, Frankenstein Migration requires us to develop new components outside of the current application.

    Bear with me.

    Further, in the article, we are going to use word Host to refer to the current application, written with the framework we’re about to migrate away from. At the same time, the new application, written with the framework we are migrating to will be called Alien, as it injects its services into Host at some point.

    Host — is our current application; Alien — our migrated application on the new framework ‘Host’ is our current application while ‘Alien’ is our migrated application on the new framework. (Large preview)

    Yes, we do not treat Alien as just a set of components, but as a proper application that we build over time. Technically, both Host and Alien should be two completely different applications written with any framework you want, with own dependencies, bundling tools, and so on. It is essential to avoid typical problems of gradual migration, however, there is a significant additional benefit to this approach. By keeping Host and Alien independent, we get both systems deployable anytime — should we need this at some point of migration.

    There are several ways you can organize Host and Alien:

    • Different domains or IP addresses;
    • Different folders on your server;
    • git submodules;
    • And so on.

    The primary condition for any scenario you pick, though, is that the Host should have access to Alien’s assets. So, if you choose to work with different domains, you have to take a look at setting up CORS for your Alien domain. If you decide to organize it as simple as different folders on your server, make sure resources from Host’s folder have access to Alien’s folder. If you go with git submodule, before adding Alien as a submodule of your Host, make sure you read the documentation and know how it works: it’s not as hard as it may sound.

    Host should have access to Alien Host should have access to Alien. (Large preview)

    After you have set up your applications and provided access from Host to Alien, things go quite straightforward.

    3. Write An Alien Component

    The title should be self-explanatory, I believe. At this point, we have:

    • A clear overview of the services in our Host application,
    • Set up application basis for Alien, and
    • Allowed access to Alien’s assets from Host.

    Now it’s time to pick a Host service we want to migrate first and re-write this service in Alien application, using the new framework. Keep in mind: we do not wait for the whole application to be re-written as in “complete re-write.” Instead, we migrate bit-by-bit as in gradual migration.

    The next, practical part of the article will contain more details of actual tips on how to write your Alien component for easier integration. However, for now, you might have a question:

    If Alien and Host are entirely different systems, how on Earth are we supposed to integrate our newly-written Alien service into Host?

    Here is where we get to the second building block of the approach: the Web Components.

    4. Write Web Component Wrapper Around Alien Service

    The Web Component wrapper is the core of our integration part. Before I cover more on this, there are a couple of things to keep in mind:

    1. First of all, you are free to pick any abstraction layer you want for your Web Component. You can pick lit-element, Stencil, or really anything that gives you Web Components at the end. However, the Web Components that we need for Frankenstein Migration are so pure (they are just the wrappers and nothing more) that I think using an abstraction layer for this is overkill.
    2. Secondly, your Web Component wrapper lives on the Host’s side. So, based on the needs and requirements of your Host, you have to decide for yourself whether or not you need to polyfill Web Components. Just check the support for two technologies that we are going to rely upon:
      1. Shadow DOM, and
      2. Custom Elements.

        The support for both is quite similar, and with Edge switching to Chromium in version 75, native support for Web Components in browsers is very impressive. Nevertheless, should you need the polyfills to run your Web Components in IE11, for example, take a look at the stable polyfill.
    Web Component is a pure wrapper around Alien service Web Component is a pure wrapper around Alien service. (Large preview)

    The main functions of our Web Component wrapper:

    • Setting up a boilerplate for a new Custom Element with Shadow DOM;
    • Importing our Alien component;
    • Rendering Alien component within Shadow DOM of the wrapper;
    • Importing relevant styles and putting them in the Shadow DOM together with the Alien component itself (only if required by the Alien component).

    As a sneak-preview of how such component can feel like, take a look at the very basic example of importing a React component (HeaderApp) into Web Component wrapper (frankenstein-header-wrapper):

    import React from "../../react/node_modules/react";
    import ReactDOM from "../../react/node_modules/react-dom";
    import HeaderApp from "../../react/src/components/Header";
    class FrankensteinWrapper extends HTMLElement {
      connectedCallback() {
        const mountPoint = document.createElement("div");
        this.attachShadow({ mode: "open" }).appendChild(mountPoint);
        ReactDOM.render(, mountPoint);
    customElements.define("frankenstein-header-wrapper", FrankensteinWrapper);

    Note: Take a closer look at the imports. We do not install React in our Host but instead import everything from Alien’s location with all of its dependencies. In this case, Alien has been added to Host as a git submodule and hence is visible to Host as a sub-folder that makes accessing its contents from Host a trivial task. Here, Alien is still a separate entity that is independent from Host though. It should explain the importance of Step #2 where we allowed access from Host to Alien.

    That’s pretty much it for the functions of the wrapper. After you wrote your Web Component, imported your Alien service and rendered it within the Web Component, we need to replace our Host service with our Web Component (that brings Alien service with itself).

    5. Replace Host Service With Web Component

    This step is very trivial, I believe. What you need to do effectively is replace markup of your Host service with your Web Component. The next chapter will cover different ways of setting up communication between your Host and Alien (that sits within Web Component) components, but in essence, there is no rocket science here:

    1. We have to connect both services to the same storage;
    2. We have to dispatch and listen (on both sides) to events when storage gets updated.
    After we’ve wrapped Alien’s service with the Web Component wrapper, it’s time to replace the corresponding Host service with the wrapper After we’ve wrapped Alien’s service with the Web Component wrapper, it’s time to replace the corresponding Host service with the wrapper. (Large preview)

    This schema should be the same no matter whether you have a state management system(s), route your communication through localStorage, or communicate with simple DOM events. By replacing your Host service with the Web Component wrapper, you finish the migration of the service and can enjoy this cute Frankenstein in your project.

    However, it doesn’t smell like a real migration just yet. There has to be something else to it.

    6. Rinse And Repeat

    After you’ve migrated your first service, you need to go through Steps 3 to 5 for all of your services/components. All the principles and recommendations remain valid. Just continue evolving your Alien as if you do a complete re-write: you’re working on a new application in parallel with your Host. You have to be able to start and build your Alien at any time and any way you want. The only difference now is that you can push your Alien services into production on Host whenever they are ready.

    At some point, you get all your services migrated, but you won’t have Host services anymore because all of them are replaced with Web Component wrappers that containing Alien services. Technically speaking, you get Alien application with remaining glue from Host. You could leave your application like this, but it’s not performant (we discuss performance tips and tricks in one of the next parts of the article) and looks quite messy, to be honest. There is a better way.

    When all of the Host services got replaced with Web Component wrappers, our Host resembles Alien and it’s time for a simple trick When all of the Host services got replaced with Web Component wrappers, our Host resembles Alien and it’s time for a simple trick. (Large preview)

    I have to repeat the core idea: “At this point, you have Alien application with remaining glue from Host.” It means that instead of serving our users this not-so-cute-anymore Frankenstein, we can serve real Alien instead of Host. At this moment, Alien should represent precisely the same picture as we have in Host, but orchestrated by Alien’s natural means and without any Web Components. The only question is: “How do we do that?”

    7. Switch To Alien

    Remember when we said that an independence of Host and Alien is essential for this type of migration, and so we split them into two separate applications? Well, now it’s time to enjoy the benefits of that decision.

    If you kept your Host and Alien independent after all Host services got replaced, you should be able to switch your server configuration to serve requests from Alien and forget about Frankenstein If you kept your Host and Alien independent after all Host services got replaced, you should be able to switch your server configuration to serve requests from Alien and forget about Frankenstein. (Large preview)

    I assume you serve your Host with a configurable web server. By “configurable”, I mean that you have control over the configuration file of your server. It allows you to control routing to your site.

    If this assumption is correct, you should be able to switch your server to serve requests from your Alien’s folder instead of Host for all incoming HTTP requests. For example, in your Apache’s httpd.conf, if you used git submodule for adding a React application to your Host, you should be able to update DocumentRoot.

    For example, the default setting:

    DocumentRoot "/var/www/html"

    becomes something like:

    DocumentRoot "/var/www/html/react/dist"

    That’s it! From now on, we’re directing HTTP traffic to our React subfolder.

    When this configuration is confirmed to be working and your users are served your fully migrated Alien application instead of your Host, your Alien becomes your new Host. Now, the old Host and all of its Frankenstein parts (including the Web Component wrappers) are not needed anymore and can be safely thrown away! Your migration is over.


    All in all, Frankenstein Migration — is an attempt to combine “good” and “fast” migration types in which we get high-quality results such as the complete re-write that is combined with the delivery speed of gradual migration. This way, we’re able to deliver migrated services to the end-users as soon as the services are ready.

    I realize that the ideas in this article may feel provoking for some readers. Others may feel like we’re overdoing things. Keep in mind that this type of migration still needs testing with as many possible frameworks, libraries, and their combinations. The next part of this article is going to show practical examples of this approach along with code examples and git repositories for you to play with at your own pace. We wouldn’t want people to form a false opinion by claiming that it’s not going to work without even trying, would we?

    Frankenstein, even if cute, has to go for now. See you in the next part, Frank. Frankenstein, even if cute, has to go for now. See you in the next part, Frank! (Large preview)
    Smashing Editorial(dm, yk, il)

    September 25 2019


    Creating Tables In Figma

    Creating Tables In Figma

    Creating Tables In Figma

    Sasha Belichenko

    In this tutorial, we will talk about how tables can be created in Figma by using components and Atomic Design methodology. We will also take a look at the basic elements of the table layout and how components can be included in the component library so that they can become part of the design system you are using.

    To make it easy for you, I’ve prepared a mockup example that uses all of the components we need for this tutorial.

    To follow along, you will need to have at least some understanding of the basic Figma concepts, its interface, and how to work with Figma components. However, if you’re new to Figma and working with table data, I recommend watching the “Getting Started” video to help you better understand Figma end-to-end, as well as the article “How To Architect A Complex Web Table” that was published not too long ago here on Smashing Magazine.

    To simplify the scope of this tutorial, let’s assume that the colors, fonts, and effects already exist as styles in the Figma project you’re about to begin. In terms of Atomic Design, they are atoms. (To learn more, the folks at littleBits wrote a great article on the topic.)

    The target audience for this tutorial are designers (UX, UI) who have either already adopted Figma into their workflows or are planning to try Figma in their next design projects but aren’t sure how to get started.

    So, without further ado, let’s dig in!

    Quick Note: While writing this article, Figma introduced plugins. At the time of publishing, there weren’t any good ones for working with tables, but things might change fast. Who knows, maybe this article will actually help an aspiring Figma plugin developer to create a really neat Figma Tables plugin, or at least, I hope it will. 😉


    Imagine the table as an organism. The table cell is then a molecule which is comprised of individual atoms. In design terms, they’re cell properties.

    So, let’s start with the cell. It has three properties:

    1. Background
    2. Border
    3. Content

    Now we’ll take a closer look at each one of them.


    The background will be a separate component in Figma. The size doesn’t really matter since we can stretch the component as we need, but let’s begin with setting the size to 100×36 pixels.

    In this component, add a rectangle of the same size as the component itself. It will be the only object inside the component. We need to attach the rectangle’s borders to the component’s borders by using constraints (set constraints to “Left & Right” and “Top & Bottom” at the right panel in the Constraints section), so that the rectangle stretches automatically to the size of the component.

    If you’d like to see this in action, watch this tutorial on how the constraints work in Figma.

    The Background Component The Background Component (the ‘atom’) (Large preview)

    The fill color of the rectangle will determine the background color of the cell. Let’s pick the white color for it. I recommend choosing that color from the color styles that are configured at the beginning of the project.

    Background colorChanging the background color (Large preview)


    This one is a bit trickier than the background. You can’t just create one rectangle with a stroke. We may need different kinds of borders: one for the separate cells (with borders around), one for the whole row of cells with only top and bottom borders, or one for the table header that we might want to separate from the rest with a wider line. There are many options.

    Border properties:

    • Border line (left, right, top, bottom, or absence of any of them)
    • Line width
    • Line color
    • Line style

    Each line within the cell border might havea different width, color, and style. For example, the left one could be a continuous red line, and the top one a dotted grey line.

    Let’s create a component with a size of 100×36 pixels (the same as we did before). Inside the component, we need to add 4 lines for each border. Now pay attention to how we are going to do this.

    1. Add a line for the bottom border with the length of the component width;
    2. Set its position to the bottom border and constraints to stretch horizontally and stick to the bottom border;
    3. For the top border, duplicate the line for the bottom border, rotate it by 180 degrees and stick to the top of the component. (Don’t forget to change its constraints to stick to the top and stretch horizontally.);
    4. Next, for the left border, simply rotate by -90 degrees and set its position and constraints to be at the left side sticking to the left border and stretching vertically;
    5. Last but not least, you can create the right border by rotating it by 90 degrees and setting its position and constraints. Set stroke color and stroke width for each line to gray (select from the color styles) and 1 pixel respectively.

    Note: You may be asking yourself why we rotated the line for the bottom border. Well, when you change the stroke width for a line in Figma, it will rise. So we had to set this “rise” direction to the center of the component. Changing the line’s stroke width (in our case it is the border size) won’t expand outside the component (cell).

    Now we can hide or customize the styles separately for every border in the cell.

    The Border Component A border component with 1px stroke (Large preview)

    If your project has several styles for table borders (a few border examples shown below), you should create a separate component for each style. Simply create a new master component as we did before and customize it the way you need.

    Border Styles A few extra examples of border styles. Note that the white background is not included in the component. (Large preview)

    The separate stroke component will save up lots of your time and add scalability. If you change the stroke color inside the master component, the whole table will adjust. Same as with the background color above, each individual cell can have its own stroke parameters.

    Border’s width and colorChanging border’s width and color (Large preview)


    This is the most complex component of all.

    We need to create all possible variations of the table content in the project: plain text, a text with an icon (left or right, different alignment), checkboxes, switches, and any other content that a cell may possibly contain. To simplify this tutorial, please check the components in the mockup file. How to create and organize components in Figma is a topic for another article.

    However, there are a few requirements for content components:

    • Components should stretch easily both vertically and horizontally to fit inside a cell;
    • The minimum size of the component should be less than the default cell size (especially height, keep in mind possible cell paddings);
    • Avoid any margins, so the components can align properly inside a cell;
    • Avoid unnecessary backgrounds because a cell itself has it already.
    Content components examples Examples of cell content in components. This is not a complete list; you can use most of the components of your design system inside a table. (Large preview)

    Content components can be created gradually: start with the basic ones like text components and add new ones as the project grows in size.

    The reason we want the content to be in components is the same as with other elements — it saves uptime. To change the cell’s content, we just need to switch it in the component.

    Changing the component inside the cellEditing the table using cells components (Large preview)

    Creating A Cell Component

    We created all the atoms we need: background, border, content. It’s time to create a cell component, i.e. the molecule made from atoms. Let’s gather all the components in a cell.

    The cell component The cell component (the ‘molecule’) (Large preview)

    Set the background component as the bottom layer and stretch it to the whole cell size (set constraints to “Left & Right” and “Top & Bottom”).

    Add the border component with the same constraints as the background component.

    Now to the most complicated part — the content content.

    The cell has paddings, so you need to make a frame with the component’s content. That frame should be stretched to the whole cell size except for the paddings. The content component should also be stretched to the whole frame size. The content itself needs to be deprived of any margins, so all paddings will be set by the cell.

    At the end of the day, cell paddings are the only property in a component that we will set only once without an opportunity to change it later. In the example above, I made it 4px for all sides.

    Note: As a fix, you can create columns with empty cells (with no content and width of 16px for example) left and right to the column where extra margin is needed. Or if your table’s design allows, you can add horizontal paddings inside the cell component. For example, cells in Google Material Design have 16px paddings by default.

    Don’t forget to remove the “Clip content” option for the cell and frame (this can be done at the right-hand panel in the Properties section). The cell’s content can go out of its borders; for example, when a dropdown is inside your cell and you want to show its state with a popup.

    Note: We’ll be using this cell style as the main one. Don’t worry if your table has additional styles — we’ll cover that in the Table States and Components, Not Overrides sections.

    Cell Options For A Standard Table

    This step could be optional but if your table needs states then you can’t go without it. And even more so if there is more than one border style in the table.

    So let’s create additional cell components from which it’d be easier to build up a table. When working with a table, we will select the appropriate component depending on its position in the table (e.g. depending on the type of borders).

    In order to do that, let’s take our cell component and create eight more masters from it. We also need to disable the appropriate layers responsible for borders. The result should look like the image below.

    Cell options The cell options we need to build a table. Note that there could be a few extra depending on your table borders styles. (Large preview)

    The top row is for the cells on top and in the middle of the table. The bottom row is only for the cells at the bottom. This way we’ll be able to put the cells one after another with no gaps and keep the same stroke width.

    A few examples:

    The First example If each cell in the table has a border, we’d only need cells 1, 4, 5 and 8. (Large preview) The Second example If there are merged cells or border absence, we must apply the rest 2 and 3 cells as well as 6 and 7 to the bottom row. (Large preview) The Third example If the table design considers the absence of vertical borders, cells 2 and 6 would be enough. (Large preview)

    Note: For each border style created above, it’d be good to add master components like the ones described earlier.

    So we have excluded the necessity of overriding cell’s instances (disabling the appropriate layers, to be precise). Instead of that, we use various components. Now if, for example, a column uses a different style from the default (the fill color or border), you can choose this column and simply change the relative component. And everything will be alright. On the opposite side, changing a border of each cell manually (disabling the appropriate borders) is a pain you don’t want to bother with.

    Now we are ready to create tables (in terms of Atomic Design — organisms) from the various cell components (molecules) we made.

    Customizing The Table

    Changing the row’s height in the whole table is relatively easy: highlight the table, change the element height (in this case, the cell’s height, H in the right-hand panel in the Properties section), and then change the vertical margin from the element to 0. That’s it: changing the line height took two clicks!

    Changing the row heightChanging the row height for the whole table (Large preview)

    Changing the column width: highlight the column and change the width size. After moving the rest of the table close up, select the whole table by using the Tide Up option in the Alignment panel as well as the first item in the dropdown list under the rightmost icon.

    Changing the column widthChanging the column width. (Large preview)

    Note: I wouldn’t recommend grouping rows and columns. If you change the column size extending the elements, you’ll get fractional values for width and height. If you don’t group them and snap to the pixel grid, the cell size will remain an integer number.

    The background color, stroke type, and content data can be changed in the appropriate component or in one of the eight cells master components (cells that had different stroke styles). The only parameter that can’t be changed right away is the cell margins, e.g. content paddings. The rest are easily customizable.

    Components, Not Overrides

    Looking at what we got in the end, it might seem like overkill. And it is if there is only one table in your project. In this case, you can simply create one cell component and leave the background and stroke components off. Simply include them in the cell component, create the table and do the necessary customization for each separate cell.

    But if components are included in a library that is used by a number of other files, here comes the most interesting stuff.

    Note: *I do not recommend changing the background color and stroke in components’ instances. Change them only in the master. By doing so, those instances with overrides won’t get updated. This means you would have to do that manually and that’s what we’re trying to avoid. So let’s stick to the master components.*

    If we need to create an additional type of table cells (e.g. the table header), we add the necessary set of master components for cells with the appropriate styles (just like we did above with the eight cells that had different stroke styles), and use it. Yes, it takes longer than overriding components’ instances but this way you will avoid the case when changing the masters will apply those changes to all layouts.

    Table States

    Let’s talk about the states of the table’s elements. A cell can have three states: default, hover, and selected. Same for columns and rows.

    If your project is relatively small, all states can be set by overrides inside instances of your table components. But if it’s a big one, and you’d want to be able to change the look of the states in the future, you’ll have to create separate components for everything.

    You’ll need to add all eight cells with different stroke variants for each of the states (maybe less, depends on the stroke style). And yes, we’ll need separate components for the background color and the stroke for the states as well.

    In the end, it’ll look similar to this:

    Hover and Selected The cells’ states (hover and selected) (Large preview)

    Here’s where a bit of trouble comes in. Unfortunately, if we do everything as described above (when changing the component’s state from one to another), there is a risk of losing the cell’s content. We’ll have to update it apart from the case when the content type is the same as in the master cell. At this point, we can’t do anything about it.

    Table with rows’ states Table with various rows’ states. (Large preview)

    I added tables in the mockup file that were made in a few different ways:

    • Using this tutorial (separate components for cells’ styles);
    • Using the cell component (components for borders, background, and content);
    • Using the cell component that unites everything (with only content components in addition).

    Try to play around and change the cell’s styles.

    Changing the stateChanging the state of the row. (Large preview)


    If you’re using the same components library in several projects and you’ve got a reasonable number of tables in each of them, you can create a local copy of components (cells components with stroke styles and, if needed, cells components with different states), customize them, and use them in the project. The cell content can be set based on local components.

    Also, if you’re using the table for one large project with different kinds of tables, all the above-mentioned components are easily scaled. The table components can be improved to infinity and beyond, like creating the cell states when hovering and other kinds of interactions.

    Questions, feedback, thoughts? Leave a comment below, and I’ll do my best to help you!

    Figma Table Mockup Download

    As promised, I created a complete version of the Figma table mockup that you’re welcome to use for learning purposes or anything else you like. Enjoy!

    Tables in Figma mockup design Here’s a Figma table mockup that you can use for learning purposes — let the creativity begin!

    Related Reading

    Useful Resources

    • Figma YouTube Channel
      The official Figma channel on YouTube — it’s the first thing to watch if you are new to Figma.
    • Google Sheets Sync
      A Figma plugin that helps you get data from Google Sheets into your Figma file. This should work fine with the techniques from this tutoria, but you’ll need to invest some time into renaming all the text layers for this to work properly.
    Smashing Editorial(mb, yk, il)

    September 24 2019


    Designing Complex Responsive Tables In WordPress

    Designing Complex Responsive Tables In WordPress

    Designing Complex Responsive Tables In WordPress

    Suzanne Scacca

    (This is a sponsored article.) Mobile devices can be problematic for displaying complex tables and charts that would otherwise stretch the entire width of a laptop or desktop screen. This may leave some of you wondering whether it’s even worth showing tables to mobile and tablet visitors of your website.

    But that doesn’t make sense. In many cases, a table isn’t some stylistic choice for displaying content on a website. Tables are critical elements for gathering, organizing and sharing large quantities of complex and valuable data. Without them, your mobile visitors’ experience will be compromised.

    You can’t afford to leave out the data. So, what do you do about it?

    This requires a more strategic solution. This means understanding what purpose the data serves and then designing the complex web table in a way that makes sense for mobile consumption.

    A WordPress table plugin called wpDataTables has made light work of designing both desktop and mobile compatible tables, so I’ve included examples of these complex tables throughout this post. Keep reading to explore the possibilities.

    The Most Common Use Cases For Tables On The Web

    There’s a lot of value in presenting data in a table format on a website.

    Your writers could probably find a way to tackle each data point one-by-one or to provide a high-level summary of the data as a whole. However, when data is handled this way, your visitors are left with too much work to do, which will only hinder the decision-making process.

    On the other hand, tables are great for organizing large quantities of data while also giving visitors an easier way to sift through the data on their own.

    As such, your visitors would greatly benefit from having complex data sets presented as tables — across a wide variety of use cases, too.

    Feature Lists

    There are a couple of ways to use tables to show off product features.

    For e-commerce sites, the product inventory is broken up by its most pertinent features, allowing visitors to filter their results based on what’s most important to them:

    e-commerce product tables e-Commerce sites can use product tables to quickly list out all products and their key features. (Image source: wpDataTables) (Large preview)

    This would be great for any large vendor that has dozens or hundreds of similar-looking products they want customers to be able to filter and sort through.

    You could also use a table to compare your product’s features directly against the competition’s. This would be better for a third-party marketplace where vendors sell their goods.

    Amazon includes these kinds of tables:

    Side-by-side competitor tables Marketplace sites use side-by-side competitor tables to simplify decision-making. (Image source: Amazon) (Large preview)

    By displaying the data in this format, customers can quickly do a side-by-side comparison of similar products to find the one that checks off all their requirements.

    Pricing Tables

    If you’re designing a website where services or memberships are sold instead of products, you can still use tables to display the information.

    You’ll find a good example of this on the BuzzSumo website:

    Service-based companies list prices in tables Companies that sell services, like BuzzSumo, use tables to display pricing and features. (Image source: BuzzSumo) (Large preview)

    Even though there’s less data to compile, you can see how the structure of the table and the stacking of the services side-by-side really help visitors make a more well-informed and easier buying decision.


    A catalog is useful for providing visitors with an alphabetized or numerically ordered list. You might use one to organize a physical or digital inventory as this example demonstrates:

    Catalog tables Catalog tables make it easier for users to find what they’re looking for. (Image source: wpDataTables) (Large preview)

    This would be good for bookstores, libraries and websites that have their own repository of reference material or content.

    You might also use a catalog to help customers improve the accuracy of their orders:

    Catalogs for order accuracy Catalog tables can be used to aid shoppers with order accuracy. (Image source: wpDataTables) (Large preview)

    This type of table provides customers with key specifications of available products to ensure they’re ordering the right kinds of parts or equipment.

    Best Of Lists

    There are tons of resources online that provide rundowns of the “Top” winners or “Best Of” lists. Tables are a useful way to summarize the findings of the article or report before readers scroll down to learn more.

    This is something that websites like PC Mag (and, really, any tech or product review site) do really well:

    Best-of reviews table PC Mag organizes a summary of best-of reviews in a table format. (Image source: PC Mag) (Large preview)

    This helps readers get a sense for what’s to come. It also allows those who are short on time to make a faster decision.

    Directory Tables

    Directory websites have ever-growing and regularly updated lists of data. These are your real estate listing sites, travel sites, professional directories and other sites containing high volumes of complex data that really shouldn’t be consumed without a filterable table.

    Case in point: this list of available apartments:

    Directory website table Directory websites that change often need tables to keep listings organized. (Image source: wpDataTables) (Large preview)

    This makes it much easier for visitors to see all options in a single glance, rather than have to go one-by-one through individual entries that matched a search query.

    General Data

    There are other data lists that are just too complex to handle as loose text. Sports data, for instance, should always be presented in this format:

    Sports statistics table Basic statistics, like for sports teams, should never be presented as loose data. (Image source: wpDataTables) (Large preview)

    You can see how this keeps all data in one place and in a searchable list. Whether visitors are looking for their home team’s stats, or want to compare the performance of different teams from their fantasy sports league, it’s all right there.

    How To Design Complex Responsive Tables

    Regardless of what type of data you’re tasked with presenting on a website, the goal is to do so in a clear fashion so visitors can take quicker action.

    Now, it’s time to figure out how to best format this data for mobile visitors.

    Delete, Delete, Delete

    If your client has pulled their data from an automated report, they may not have taken time to clean up the results. So, before you start any design work on the table, I would suggest reviewing the data they’ve given you.

    First, ask yourself: Is there enough data that it warrants a table?

    If it’s a simple and small enough list, it might make more sense to ditch the table.

    Then, go over each column: Is each of these useful?

    You may find that some of the columns included aren’t necessary and can be stripped out altogether.

    You may also find that some columns, while an essential part of each item’s individual specifications list, won’t help visitors make a decision within the table. This would be the case if the column contains an identical data point for every item.

    Finally, talk to your writer or data manager: Is there any way to shorten the columns?

    The table’s labels and data may have been written in full, but your writer may have a way to simplify the responses without compromising on comprehension.

    When possible, have them work their magic to shrink up the text so that columns don’t take up as much space and more can be revealed on mobile. Don’t just do this for mobile users either. Even on desktop and tablet screens where more screen real estate is available, the shortening of labels can help conserve space.

    It may be as simple as changing the word “Rank” to the number symbol (#) and abbreviating “Points” as “Pts”.

    Make data smaller Designers and writers need to work together to create smaller tables. (Image source: wpDataTables) (Large preview)

    While it might not seem like one word will make much of a difference, it adds up the more complex and lengthier your tables are.

    Start With Two Columns

    By default, mobile tables should always start with two columns. It’s about all the screen’s width will allow for without compromising the readability of the data within, so it’s best to start with the basics.

    When you contrast a full-screen table on desktop against its counterpart on mobile, you can see how easy it is to identify the two columns to include. For example, a mobile statistics table includes a column for item type and one for the profits earned from each:

    Mobile table with two columns It’s a good idea to design responsive tables with two columns to start. (Image source: wpDataTables) (Large preview)

    This doesn’t mean that all other data is lost on mobile. You just need to let visitors know how they can expand the table’s view.

    In this example, when visitors select the eyeball icon above the table, they have the option to add more columns to the table:

    Column view options If visitors want to scroll right, give them column view options. (Image source: wpDataTables) (Large preview)

    In allowing for this option on mobile, your visitors can control how they consume data while also selecting only the data points that are most important to them.

    The result will then look like this:

    Mobile table with more than two columns An example of a mobile table with additional columns. (Image source: wpDataTables) (Large preview)

    While users will have to scroll right to see the rest of the table, the control they wield over column views helps keep this a reasonable task. With just one scroll right, they’ll see the rest of the table:

    Horizontal scrolling on mobile Even with more columns on mobile, horizontal scrolling is kept to a minimum. (Image source: wpDataTables) (Large preview)

    This is a good option to have for lists of products where the side-by-side comparison is useful in expediting the decision-making process.

    Use An Accordion For Standalone Entries

    There’s another option you can include which will give visitors more control over how they view table content.

    For this example, we’ll look at a list of available cryptocurrencies:

    Expandable accordions for mobile tables Data lists (as opposed to product comparison) lists can use expandable accordions. (Image source: wpDataTables) (Large preview)

    As you can see, the default here is still to only show two columns. In this case, though, a click of the plus-sign (+) will reveal a new way to view the table:

    Expanded row on mobile An example of what an expanded row looks like on mobile tables. (Image source: wpDataTables) (Large preview)

    When open, all of the data that would otherwise force visitors to scroll right is now visible within a single screenful.

    While you can certainly include an expandable accordion in any responsive table you create, it would be best suited to ones where a direct side-by-side comparison between products or services isn’t necessary.

    Keep Vertical Scrolling To A Minimum

    Just as you want to prevent your visitors from having to scroll past the horizontal boundaries of the mobile website’s pages, you should limit how much vertical scrolling they have to do as well.

    Data consumption, in general, isn’t always an easy task, so the more you can minimize the work they have to do to get to it, the better.

    One way to limit how much vertical scrolling your visitors do is by breaking a table with dozens or hundreds of rows into pages.

    A table of annual temperatures on desktop and mobile An example of how to shrink an extra-large table down to a couple columns and multiple pages. (Image source: wpDataTables) (Large preview)

    Just remember to make it easy for visitors to scroll through the pages. A well-designed set of pagination controls either at the top or bottom of the table would be useful:

    Responsive table pagination Use pagination at the bottom of tables to decrease vertical scrolling. (Image source: wpDataTables) (Large preview)

    This would be especially useful for a handful of pages. Anything more than that and the pagination process may become tedious.

    You can also include a table search function directly above it:

    Mobile table search function Above-the-table search helps reduce the work of scrolling on mobile. (Image source: wpDataTables) (Large preview)

    This allows for a quick shortcut when your users have a good idea of what they’re looking for and want to jump straight to it.

    Include Both Filtering And Sorting For Larger Data Sets

    So, let’s say that you have a very extensive list of data. You don’t want to force users to scroll through dozens of table pages, but you also can’t afford to remove any of the data sets. It’s all pertinent.

    In that case, you’re going to hand some of the control back to your visitors. This way, their choices will determine how much of the table they end up seeing.

    Let’s use this list of mutual funds as an example:

    Complex table example An example of a complex table on mobile. (Image source: wpDataTables) (Large preview)

    The image above is the default view visitors would see if they scrolled immediately to the table. However, they might find it to be intimidating and decide that filtering out bad results will improve the view:

    Table filters Filtering allows users to greatly narrow down how many rows are displayed on mobile. (Image source: wpDataTables) (Large preview)

    What’s nice about including filters on mobile tables is that they function the same way your mobile contact forms do. So, visitors should have an easy time filling in and moving between fields, which will get them quicker to the results they want to see.

    Another way to improve how their results are displayed is by using the sorting feature. When they click on the top label of any column, it will automatically sort the column in descending order. Another click will reverse it.

    Table sorting Sorting allows users to see results in descending/ascending order. (Image source: wpDataTables) (Large preview)

    These two features are a must-have for any table you build, though they’re especially important for mobile visitors that don’t have as much time or attention to give to your tables.

    Wrapping Up

    You’re here because you want a better way to present complex tables to your mobile visitors.

    The key to doing this right is by first familiarizing yourself with the kinds of tables you can create. Even if mobile devices limit how much can be seen at first glance, that doesn’t make it impossible to share that kind of data with them.

    Next, you need to build user control into your tables, so that visitors can decide what they see and how they see it.

    And, finally, you’d do well to find a tool built specifically for this complex task. For those of you building websites with WordPress, wpDataTables is a WordPress table plugin that’s able to create responsive tables and charts. It doesn’t matter how large your data set, or what use case it’s for, it will enable you to quickly and effectively organize and display responsive tables on your WordPress website.

    Smashing Editorial(ms, yk, il)

    September 23 2019


    Is There Such A Thing As Too Much Social Proof?

    Is There Such A Thing As Too Much Social Proof?

    Is There Such A Thing As Too Much Social Proof?

    Suzanne Scacca

    It’s very easy to start a business these days. But succeeding in that business is another story. There are just too many people who want to escape the 9-to-5, do something with their big idea and make a better life for themselves in the process. I totally applaud that.

    However, it’s not practical to think that the idea will sell itself. Consumers need to be given some reason to trust that their money (or time) will be well spent. And when a business or product is new, the best way to gain this trust is by getting clients, customers and others to vouch for you.

    That said, is it possible to go overboard with testimonials, reviews, case studies, client logos and other forms of social proof? And is there a wrong way to build social proof into a mobile website or PWA?

    Yes and yes!

    When Too Much Social Proof Is A Bad Thing

    I was working on the copy for a new website earlier this year. My client told me that the design team had prepared a wireframe for the home page and wanted me to use that as a framework for the copy. Normally, I would be stoked. When I work as a writer, I want to stay in writer mode and not have to worry about layout and design suggestions.

    The only problem was that the home page they wanted was littered with social proof and trust marks. It would’ve looked like this (note: the purple boxes contain social proof):

    Sample wireframe with social proof A sample wireframe of a home page with too much social proof. (Source: Canva) (Large preview)

    In reviewing the wireframe, I had a number of gripes. For starters, it was way too long, especially for mobile visitors.

    There was no way people were going to scroll seven times to find the section that finally invites them to take action.

    Secondly, there was too much social proof. I know that seems counterintuitive. After all, isn’t it better to have more customer validation? I think in some cases that’s correct. Like with product reviews.

    In BrightLocal’s 2018 Local Consumer Review Survey, respondents said they want to see at least 40 product reviews, on average, before believing a star rating.

    BrightLocal number of reviews to believe start rating BrightLocal’s consumer review survey says that consumers want to see 40 review before believing a business’s start rating. (Source: BrightLocal) (Large preview)

    Even then, consumers aren’t looking for a perfect score. As you can see here, only 9% of respondents need a business to have a perfect rating or review in order to buy something from them:

    BrightLocal star rating preference BrightLocal survey respondents prefer to see a minimum of 3- or 4-star ratings instead of 5. (Source: BrightLocal) (Large preview)

    And I can tell you why that’s the case.

    I used to write product reviews. One of the things I’d do when assessing the quality of a product (before making my own judgments) was to look at what online reviewers — professional reviewers and customers — had to say about it. And let me tell you… there are tons of fake reviews out there.

    They’re not always easy to spot on their own. However, if you look at enough reviews at once, you’ll start to notice that they all use the same verbiage. That usually means the company paid them to leave the review or gave family, friends and employees pre-written reviews to drop.

    I’m not the only one who’s noticed this trend either. BrightLocal’s respondents have as well:

    BrightLocal fake reviews 33% of BrightLocal respondents have seen lots of fake reviews while 42% have seen at least one. (Source: BrightLocal) (Large preview)

    Only 26% of respondents said they hadn’t come across a fake review while 42% had seen at least one in the last year and 33% had seen a lot.

    When it comes to things like testimonials and case studies, I think consumers are growing just as weary about the truthfulness of the praise.

    TrustRadius surveyed B2B buyers on the subject of online reviews vs. case studies. This is what it found:

    TrustRadius customer reviews vs. case studies TrustRadius asked respondents to assess their feelings on customer reviews vs. case studies (Source: TrustRadius) (Large preview)

    It makes sense why consumers don’t feel as though case studies are all that authentic, trustworthy or balanced. Case studies are written by the companies themselves, so of course they’re only going to share a flattering portrait of the business or product.

    Having worked in the digital marketing space for a number of years, I can tell you that many customer testimonials aren’t always genuine either. That's why businesses need need to stop worrying about how much social proof they have and start paying more attention to the truthfulness and quality of what they're sharing with visitors.

    The point I’m trying to make isn’t that we should ditch social proof. It’s an important part of the decision-making process for consumers. But just because it can affect their decision, it doesn’t mean that repeatedly bashing them over the head with it will work either. If your website and its messaging can’t seal the deal, a bunch of logos and quotes meant to convince them to buy won’t either.

    What you need to focus on when building social proof into a mobile site or PWA is quality over quantity. Sure, you might want to highlight the sheer quantity of reviews that have been gathered on a product, but in terms of space on your website? With social proof, less is more.

    Tips For Building Social Proof Into A Mobile Website Or PWA

    You don’t have a lot of room to spare on mobile and you don’t want to make your visitors dig and dig to find the important details. So, while you do need social proof to help sell the business and its product, you need to do so wisely.

    That means giving your content room to shine and strategically enhancing it with social proof when it makes the most sense to do so.

    Consolidate Social Proof on the Home Page

    I know how hard it can be to convince people to work with you or buy from you when your business is new. That’s especially the case when you’re entering a field that’s already dominated by well-known and well-reviewed companies.

    However, rather than make your home page longer than it needs to be — for desktop or mobile visitors — why not consolidate the strongest social proof you have and put it in one section?

    What’s neat about this option is that you can get creative with how you mix and match your social proof.

    Customer Reviews + Trust Seals

    Two Men and a Truck is the kind of company that needs customer testimonials. It’s the only way they’re going to effectively convince new customers to trust them to enter their home and carefully transport their belongings from one location to another.

    Two Men and a Truck social proof Local movers Two Men and a Truck stack a testimonial on top of trust seals on the home page. (Source: Two Men and a Truck) (Large preview)

    Rather than bog down their home page with testimonials, Two Men and a Truck use one especially positive review and a number of professional trust seals to close the deal in one fell swoop.

    Google Reviews + Facebook Reviews

    Another way to consolidate social proof on the home page is by aggregating reviews from other platforms as the website of Drs. Rubinstein and Ducoff does:

    Drs. Rubinstein and Ducoff home page with Google and Facebook reviews The home page of Drs. Rubinstein and Ducoff shows off the latest reviews from Google and Facebook along with an average star rating across all platforms. (Source: Drs. Rubinstein and Ducoff) (Large preview)

    This is a tiny section — it doesn’t even fill the entire screen — and yet it packs a lot of punch.

    First, you have the total number of reviews and average star rating shown at the top. Remember that survey from BrightLocal? This is the kind of thing that would go a long way in convincing new patients to sign up. There’s a good amount of reviews to go on and the average rating seems realistic.

    Also, because these reviews come from Google and Facebook, they’re connected to real people’s profiles. Plus, the date is included in the Google review.

    Unlike testimonials which are just a quote and a person’s name (if we’re lucky), this is a quote, a star rating and the date it was published. This way, prospective patients don’t have to wonder how long ago it was that Drs. Rubinstein and Ducoff received these reviews.

    Twitter + App Store Reviews + Awards

    You’ll find another creative example of consolidated social proof on the Pocket website.

    Pocket aggregates social proof from a number of sources Pocket uses Twitter, the Google App Store, the Google Play Store Webby Awards as trust marks. (Source: Pocket) (Large preview)

    Even though Pocket is free to use, that’s not necessarily enough to convince someone to try a new piece of software — especially if you want them to download it as a mobile app.

    Rather than rely on faceless testimonials, though, Pocket has chosen to show off some convincing and verifiable social proof:

    • A quote from a Twitter user with a healthy follower base,
    • The actual rating of its app on both apps stores,
    • The number of times it’s won a Webby award.

    It’s a unique patchwork of social proof which is sure to stand out from the traditional quote block many websites use to promote their products.

    Make It Sticky

    One of the great things about making the move to a PWA is you can use app-like elements like a sticky bar to show off important information to visitors. If it makes sense to do so, you could even put some social proof there.

    Google Reviews Widget

    There’s been a big surge in independent mattress companies in recent years. Tuft & Needle. Loom & Leaf. Saatva. They all seem to promise the same thing — a better quality memory foam mattress at a steal of a price — so it’s got to be hard for consumers to choose between them.

    One way to make this differentiation is with Google Reviews.

    On the desktop website for Lull, the home page reviews callout is tucked into the bottom-left corner.

    Lull Google customer reviews on desktop Lull shares Google customer reviews in a widget on its desktop website. (Source: Lull) (Large preview)

    It’s almost too small to notice the reviews with so much more to take in on the home page. That’s a good thing though. The social proof is always present without being overwhelming.

    What’s interesting to note, though, is that the mobile counterpart doesn’t show any Google reviews on the home page. It’s not until someone gets to the Mattress page where they’re able to see what other customers have said.

    Lull Google customer reviews on mobile Lull shares Google customer reviews in a sticky bar on its PWA. (Source: Lull) (Large preview)

    In this particular screenshot, you can see that the Mattress page on the PWA has a section promoting the product’s reviews. However, even when visitors scroll past that section, the sticky bar continues to remind them about the quantity and quality of reviews the mattress has received on Google.

    CTA Banner

    Another type of website this sticky social proof would be useful for would be one in hospitality. For example, this website for the Hyatt Regency San Antonio:

    Hyatt Regency San Antonio Suites page An example of one of the Suites pages on the Hyatt Regency San Antonio website. (Source: Hyatt Regency San Antonio) (Large preview)

    Just like the Lull example above, the Hyatt Regency tucks its social proof into a sticky bar on its internal sales pages.

    Hyatt Regency sticky bar with social proof The Hyatt Regency places TripAdvisor reviews next to its conversion elements in a sticky bar. (Source: Hyatt Regency San Antonio) (Large preview)

    Visitors see the number of TripAdvisor reviews and star ratings when they first enter the Suites page. When they scroll downwards, the sticky bar stays in place just long enough (about one full scroll) for visitors to realize, “Cool. It’ll be there if or when I’m ready to do more research.”

    What’s nice about how this particular sticky bar is designed is that the reviews are part of the conversion bar. It’s kind of like saying, “Want to book your trip, but feeling nervous about it? Here’s one last thing to look at before you make up your mind!”

    Create a Dedicated Page for Social Proof

    If you’re not building a PWA or you have too much social proof to show off in a small space, create a dedicated page for it. This is a great option, too, if you plan to share something other than just testimonials or reviews.


    Winkworth is an estate agency in the UK. Testimonials are a useful way to convince other sellers and lessors to work with the agency. Yet, the home page doesn’t have any. Instead, the company has chosen to place them on a Testimonials page.

    Winkworth testimonials page The Winkworth estate agency keeps its home page free of testimonials and instead places them on a dedicated page. (Source: Winkworth) (Large preview)

    It’s not as though this page is just a throwaway of every positive thing people have said. The testimonials look like they’ve been hand-picked by Winkworth, especially the longer ones that contain more details about the experience and the people they worked with.

    Winkworth testimonials An example of some of the hand-picked testimonials Winkworth has gathered for its Testimonials page. (Source: Winkworth) (Large preview)

    Each testimonial includes the person’s name as well as which Winkworth location they’re referring to. This way, visitors can learn more about the experience at specific locations instead of just hearing how great Winkworth is as a whole.

    Case Studies

    It’s not just testimonials that could use their own page. Case studies shouldn’t clutter up the home page either.

    While Bang Marketing promotes its case studies with a promotional banner on the home page, that’s all you hear of it there. They save their customers’ stories for individual pages like this one:

    Bang Marketing case studies Bang Marketing includes a video testimonial with every case study. (Source: Bang Marketing) (Large preview)

    Each case study page is minimally designed, but captures all of the information needed to tell the story.

    First, there’s a video from the client explaining what Bang Marketing was able to do for them. Then, there’s a brief description of what the team worked on. Finally, high-quality images provide visitors with a look at the resulting product.

    This is a much more effective way to share case studies than placing a barrage of portfolio images all over the home page.


    There are two ways to handle the Press section of a website. The company could publish its own press releases or it can share information about where it’s been featured in the press.

    While the former is useful for sharing company news and wins with visitors, it’s just too self-promotional and won’t help much with conversion. The latter option could really make a big impact though.

    This, for instance, is what visitors will find on the About & Press page for The Dean Hotel:

    The Dean Hotel Boston magazine cover The Dean Hotel includes magazine covers and article screenshots as social proof on its website. (Source: The Dean Hotel) (Large preview)

    After a short intro of the hotel, the rest of the page is covered in magazine covers and article screenshots that go back as far as 2013. Visitors can click through to read each of the articles, too.

    Dean Hotel social proof The Dean Hotel uses articles as social proof on its website. (Source: The Dean Hotel) (Large preview)

    This is a unique way for a website of any type to share social proof with visitors.

    If your client happens to have a bunch of positive press and never-ending hype surrounding its brand, try to leverage that on the site. Plus, by including screenshots from the articles themselves, you get another opportunity to show off the product (or, in this case, the hotel and its rooms).

    Wrapping Up

    Consumers have become very savvy when it comes to marketing and sales online. That’s not to say that they don’t fall for it — usually, when it’s done genuinely and with transparency. However, we’re at a point where a brand saying, “We’re the best! Trust us! Buy from us!”, doesn’t usually cut it. They need more validation than that.

    At the end of the day, your mobile website or PWA needs social proof to convince visitors to convert.

    That said, be careful with how you build social proof into the site, especially on the home page. You don’t have time or space to waste, so don’t create something unnecessarily bulky just so you can show off how many testimonials, reviews, case studies, client logos high-profile partnerships you have. This is about quality over quantity, so make it count.

    Smashing Editorial(ra, yk, il)

    September 20 2019


    15 Questions To Ask Your Next Potential Employer

    15 Questions To Ask Your Next Potential Employer

    15 Questions To Ask Your Next Potential Employer

    Robert Hoekman Jr

    In my book “Experience Required”, I encourage in-house UX professionals to leave companies who refuse to advance their UX intelligence and capability. There are far too many companies these days who understand the value of UX to waste your time being a martyr for one who will only frustrate you. Your best chance of doing a good job is to avoid a bad position.

    Smartly, during a recent Q&A about the book, an audience member asked how we can avoid taking these jobs in the first place. What kinds of questions, he wondered, can you ask during an interview to spot red flags before the company stabs the whole flagpole into your sacred UX heart?

    Know What You Want To Know

    There’s the usual stuff, sure, such as asking why the position you’re applying for is currently open. What the company’s turnover rate is like. Why that turnover rate is so low or high. A little Googling will easily enough net you a decent list of broad questions you can ask any employer.

    But what you really want is to get UX-specific. You want to hone in on precisely what your life might be like should you take the position.

    Your best chance of doing a good job is to avoid a bad position.

    Sadly, I lacked a great answer at the time to the question about interview questions, so I let it eat at me until I woke up at three a.m two days later and started writing notes. That morning, I emailed my reply to the moderator.

    Ask A Great Question, Then Shut Up

    To devise the list below, I considered what kinds of things I’d wish a company knew and understood about UX prior to working with them. I can operate in all kinds of situations—as a UX and process innovation consultant, this has been my job, and pleasure, for nearly 13 years now—but I want to know from the start, every time, that the effort will be set up for success. These questions aim to uncover the dirty details that will tell me what I’m walking into.

    Much like a good validation session or user interview, these questions are open-ended and designed to draw out thoughtful, long-winded responses. (One-word answers are useless.) I strongly recommend that when and if you ask them, you follow each question with a long, stealthy vow of silence. People will tell you all about who they are if you just shut up long enough to hear them do it. Stay quiet for at least ten seconds longer than you think is reasonable and you’ll get the world.

    People will tell you all about who they are if you just shut up long enough to hear them do it.

    I’d ask these questions of as many individuals as possible. Given that tech interviews are often hours-long and involve many interviewers, you should be able to grab yourself a wealth of good answers before you head out the door to process and sleep.

    If, on the contrary, you are given too little time to ask all these questions, prioritize the ones you’re personally most concerned about, and then consider that insufficient interview time might be a red flag.

    Important: The key to the answers you receive is to read between the lines. Listen to what is said, note what is not said, and decide how to interpret the answers you get. I’ve included some red flags to watch out for along with each question below.

    Let’s get right to it.

    1. How does this company define UX? As in, what do you believe is the purpose, scope, and result of good UX work?

    Literally every person on Earth who is asked this question will give a slightly, or wildly, different answer than you expect or hope for. At the very least, the person interviewing you should have an opinion. They should have a sense of how the company views UX, what the various UX roles have to offer, and what effect they should have.

    Red Flag(s)

    The UX team has a very limited role, has no real influence, and the team, for the most part, is stretched so thin you could put them on a cracker.

    2. How do the non-UX people on your product team currently participate in UX decisions?

    Follow-ups: Describe a recent example of this kind of participation. What was the UX objective? How was that objective vetted as a real need? What did you do to achieve the objective, step-by-step? How did it turn out? What did you learn?

    Find out how the entire product team approaches UX and how collaborative and supportive they might be in acquiring and acting on good research insights.

    Red Flag(s)

    They don’t participate in UX decisions.

    3. What UX roles exist in the organization, and what do they do?

    Determine where you’ll fit in, and how difficult it might be for you to gain influence, experience, or mentorship (depending on what you’re after). Also, build on the previous question about who does what and how.

    Red Flag(s)

    UX people at the company are heavily skilled in graphic design, and not so skilled in strategy. The current team members have limited influence. Your role will be similar. Strategy is handled by someone else, and it trickles down to the UX team for execution.

    4. Who is your most experienced UX person and in what ways does that experience separate them from others?

    Determine the range of UX intelligence on the team from highest to lowest. Is the person at the top whip-smart and a fantastic leader? Does that person mentor the others and make them better?

    Red Flag(s)

    The interviewer cannot articulate what makes that person better or more compelling than others. If they can’t answer this question, you’re speaking to someone who has no business making a UX hiring decision. Ask to speak to someone with more inside knowledge.

    Noteworthy, but not necessarily a red flag: If you learn that the most experienced person on the team is actually someone with a very sleight skill set, this can mean either there’s room for you to become an influencer, or the company puts so little value on UX that they’ve selected only employees with a small view of UX. The latter could mean you’ll spend all your time trying to prove the value of bigger UX involvement and more strategic work. You may like that sort of thing. I do. This would not be a red flag for me. It might be for you.

    5. What are the company’s plans for UX long-term? (Expand it? Reduce it? How so, and why? Is there a budget for its expansion? Who controls it and how is it determined?)

    Map out your road for the next couple of years. Can you rise into the role you want? Or will you be stuck in a cul-de-sac with zero chance of professional growth?

    Red Flag(s)

    We plan to keep doing exactly what we do now, and what we do now is pretty boring or weak. Also, we have no budget—like, ever—so if you want to bring in a consultant, attend a seminar, hire another person, or run a comprehensive usability study with outside customers, well, good luck with that.

    6. How do UX professionals here communicate their recommendations?

    Follow-up: How could they improve?

    Learn how they do it now, and more importantly, whether or not it works.

    Red Flag(s)

    The interviewer has no answer, or—far worse—has an anti-answer that involves lots of arm-waving and ideas falling on deaf ears. The former can, again, mean the interviewer has no business interviewing a UX candidate. The latter can mean the UX team is terrible at communicating and selling its ideas. While this can be overcome with your much better communication skills, it will almost certainly mean the company has some baggage to wade through. Poor experiences in the past will put other product team members on defense. You’ll have to play some politics and work extra heard on building rapport to get anywhere.

    7. Who tends to offer the most resistance to UX recommendations and methods and why?

    Follow-up: And how much power does that person have?

    This person will either give you the most grief or will give you the great opportunity to improve your communication skills (remember: design is communication!). Knowing who it is up front and how that person operates can tell you what the experience will be like.

    Red Flag(s)

    Executives, because they distrust UX. If you lack support at the top, it will be a daily struggle to achieve anything substantive.

    8. What do UX practitioners here do to advance their values and methods beyond project work? Please be specific.

    See how motivated the UX team is to perpetuate UX values to the rest of the company and improve how the team works.

    Red Flag(s)

    They don’t.

    9. What do you think they should do differently? Why?

    Discover how your interviewer feels about UX. This is, after all, a person who has a say in hiring you. Presumably, this person will be a big factor in your success.

    Red Flag(s)

    Keep their noses out of product development, stop telling the engineers what to do (speaks to perception of pushy UX people).

    10. Describe a typical project process. (How does it start? What happens first? Next? And then?)

    Find out if there is a process, what it looks like, and how well it aligns with your beliefs as a UX professional.

    Red Flag(s)

    You’ll be assigned projects from the top. You’ll research them, design a bunch of stuff in a vacuum with no way to validate and without any iteration method, and then you’ll hand all your work to the Engineering team, who will then have a thousand questions because you never spoke to each other until just now.

    Bonus Question

    How and when does the team try to improve on its process? (If it doesn’t, let’s call that a potential red flag as well.)

    11. How has your company learned from its past decisions, and what have you done with those learnings?

    UX is an everlasting experiment. Find out if this company understands it’s supposed to learn from the work and become smarter as a result.

    Red Flag(s)

    No examples, no thoughts.

    12. If this is an agency who produces work for clients: What kind of support or backup does this agency provide for its UX recommendations, and how much power does the UX group have to push back against wrongheaded client ideas?

    Follow-ups: How does the team go about challenging those ideas? Provide a recent example.

    Find out how often you’ll be thrown under the proverbial bus when a client pushes back against what you know to be the right approach to a given problem. Your job will be to make intelligence-based recommendations; don’t torture yourself by working with people who refuse to hear them.

    Red Flag(s)

    The interviewer says the agency does whatever the clients demand. You will be a glorified wireframe monkey with no real power to change the world for the better.

    13. How does the company support the UX group’s work and methods?

    Determine how the company as a whole thinks about UX, both as a team and a practice. Is UX the strange alien in the corner of the room, or is it embraced and participated in by every product team member?

    Red Flag(s)

    UX is a strange alien. Good luck getting anyone to listen to you.

    14. What design tools (software) does your team use and why?

    Follow-ups: How receptive are people to trying new tools? How does evolution happen?

    Know what software you should be familiar with, why the team uses it, and how you might go about introducing new tools that could be better in some situations.

    Red Flag(s)

    Gain insight into how the team thinks about the UI portion of the design process. Does it start with loose ideas drawn on napkins and gradually move toward higher-quality? Or does it attempt to start with perfection and end up throwing out a lot of work? (See the next question for more on this.)

    15. Does a digital design start low-fi or high-fi, and what is the thinking behind this approach?

    Follow-up: If you start lo-if, how does a design progress?

    You can waste a lot of hours on pixel-perfect work you end up throwing out. A company who burns through money like that is also going to be the first one to cut staff when things get tight. No idea should be carried through to its pixel-perfect end until it’s been collaborated on and vetted somehow, so you want to know that the company is smart enough to start lo-fidelity and move gradually to hi-fidelity. Hi-fi work should be the result of validation and iteration, not the start of it. A lo-fi > hi-fi process mitigates risk.

    Red Flag(s)

    All design work starts and ends in Photoshop or Sketch, and is expected to be 100% flawless and final before anyone sees what you’ve produced.

    Running The Interview

    In an unrelated Q&A years ago, a hiring manager asked how to spot a good UX professional during an interview. I answered that he should look for the person asking all the questions. I repeated this advice in Experience Required.

    Now you can be the one asking all the questions.

    And in doing so, not only will you increase your odds of being offered the gig, you’ll know long before the offer shows up whether to accept it.

    If you, dear reader, have more ideas on how to scavenger-hunt a company’s red flags, we’re all ears. Tell us about it in the comments below.

    Smashing Editorial(cc, il)

    August 20 2019

    6 Must Have Developer Tools and Services for Your Projects in 2019
    Older posts are this way If this message doesn't go away, click anywhere on the page to continue loading posts.
    Could not load more posts
    Maybe Soup is currently being updated? I'll try again automatically in a few seconds...
    Just a second, loading more posts...
    You've reached the end.

    Don't be the product, buy the product!