Eventbrite has just released its new event Listing page. Built for the company’s focus on ramping up our two-sided marketplace, it features a modern and responsive user interface designed to work across all mobile devices. It is a layout that strives for clarity and cleanliness across all event listings. Let’s take a look at the Front End aspects of this project, how we built it, and the Responsive Web Design techniques we used.
I had just joined the Eventbrite team when this project kicked off, it was a high priority product that took a lot of planning and resource gathering by the team from lots stakeholders across the company. I had worked on responsive projects previously, but none that had as much care and focus on best practices as this one.
Why Update Event Pages?
There are lots of reasons why we wanted to update the event pages (I won’t try to cover them all here), but the primary focus of the project was to improve the mobile experience.
Anyone who has bought a ticket on Eventbrite through our mobile web interface (not our fantastic native apps) will agree that the experience wasn’t perfect, we’re the first to admit it. Our less-than-great mobile interface was using a completely different code base, with a different stack (jQuery mobile). This led to several undesired consequences, not least having to constantly maintain two codebases, so when we wanted to implement a change we had to do it twice (and often in two different ways).
Add to this the fact that the classic desktop UI has aged since its original inception, the need to unify the interface into a responsive design, and to improve conversion rates for our organizers, we knew we had our work cut out for us. Our mission was to create a Responsive, Performant, Accessible and A/B testable listing page with a cleaner codebase.
At Eventbrite, we work in 2 week sprints, in small “one pizza” teams. These teams typically include a Product Manager, Engineering Manager, QA Engineer, Product Designer, UX Engineer and several Engineers.
Our code quality processes include regular code reviews, and lately we have been enforcing more code consistency with ESLint. We also focus on extensive test coverage throughout the stack: unit tests for our Django code, unit/integration tests with Jasmine and Sinon on the Front End, and an extensive suite of integration/acceptance tests with Selenium’s Webdriver to ensure quality control of the whole product.
Once the initial design was approved we created an HTML prototype using the components already available on Eventbrite’s internal style guide which is a living document of patterns and components that we use across the site.
This basic implementation allowed us to build up the frontend and work with the final design from day one, gathering feedback from the product team, customer support, and real users with UX experiments. That feedback was overwhelmingly positive, so we moved forward to the real implementation.
HTML and CSS Implementation
Our next task involved defining the styles of the new components as an iterative process, and for that we started moving the inline styles first to tags, and later to their respective files or style guide definitions.
We actually kept all our HTML and CSS in the same file as long as possible, giving us a chance to look at the markup as a whole, refactoring styles and enforcing semantic markup. We only started slicing the HTML into include files once we were happy with the results and we had the Schema.org properties in place for Microdata support. This turned out to be a great move as we were able to focus in the markup quality and accessibility first.
The Front End team collectively maintains a living style guide that contains our current UI components. We use SASS to keep the consistency of our styles and KSS to generate this style guide, and once we had the components well defined and with the desired responsive behavior, we moved them into a repository as new components.
We are testing a workflow that involves working on components in the style guide initially, and moving them into our production code later. We are still playing around with the best way to to implement this, and if you’re also working on exploratory styleguides, I’d suggest checking out this article about different style guide workflows.
Modularizing our JS
We use a Marionette application object to control the lifecycle of our modules, some of which we initialize selectively depending on the circumstances. Because of this, we use a functional mixin which, added to the application object, allows us to load modules when the DOMContentLoaded event is triggered or when a given DOM element becomes visible on the viewport.
The configuration for all the components are passed from the Back End by setting values into a “Mediator” object loaded by the app and component modules. Under the hood, we use RequireJS to load the app dependencies, and we have asynchronous versions of some of them in order to load them conditionally.
Our components are contained within Marionette modules, and they are responsible for instantiating the views and entities for that features. Let’s take a closer look to some of them:
Currently we are passing some parameters to modules like the map, that receives information about the viewport width. This way we can load a different kind of map (a static image with the location or a fully interactive map) depending on the screen real state we have available.
This module was largely inspired by Airbnb’s map and its huge appeal to us as users, although they have gone the extra mile by styling it a bit. If you are in a desktop browser you should be able to drag the “yellow little man” into the map and turn on street view!
This component involved some work due to its complexity and we are still in the polishing stage. It was born out of the necessity of keeping the main page call to action always visible. It turned out to be a bit tricky, partly because of our ambitious goal of showing the global navigation as a second fixed bar when users scroll up, and partly because of the still precarious (thinking of you, Apple) support of ‘position: fixed’ across the board.
On the performance side, we integrated some grunt tasks to create a tool that keeps track of the webpagetest.org scores of a set of event listing pages. We run this tests daily thanks to a Jenkins task and store the results, so we can access to the historical performance of our pages. I am planning to talk about this little tool in another post soon.
We are also tracking user timing data, storing rendering time values of the hero image and register form. And regarding that new hero image, we are using a safe bet solution as our Responsive Images implementation: Picturefill.
We are currently working on improving the feature support of this new listing page, so we can support more event types and configurations. We are also having conversations about how we can make the page more performant and in-lining the above the fold CSS styles to improve our critical path. We also want to implement a new modal component that will enhance the mobile experience.
The launching process of the new listing has been pretty smooth, and we think we have achieved a modern looking, accessible and performant listing page. Still, we want to know what do you think about it, so feel free to reach out to me directly to chat further.
This is just the first iteration of the product, and we all know several version are typically needed to achieve a truly great product. Future iterations will be based heavy on A/B tests, so keep an eye out to see what we roll out next!
Event Page Examples