How can we make your first month awesome?

My first month at every job is a period of self-loathing, usually characterized by frequent white-hot panics in which I believe that I’m not good enough for the job, not a real programmer, or just profoundly stupid. This experience is what I thought everyone meant by the term “onboarding.”

So, when I looked at the schedule for PyCon this year, the talk “Technical on-boarding, training, and mentoring” stood out. I ducked in and sat in the last row, so I could easily slip away if necessary.

Instead of what could have been a soul-crushing grind about resource efficiency, I was delighted to hear the presenters Kate Heddleston and Nicole Zuckerman describe onboarding techniques that they had used to make new employees feel like humans welcomed into a group of other humans. Imagine if the next person we hired at Safari didn’t feel like we had set them on fire and asked them to find the water!

Activities for new engineers

As the talk progressed, I began to realize that we are all doing onboarding wrong. I wrote typo-ridden notes, struggling to keep up with all the great examples of onboarding activities that the presenters discussed, many of which I had never done nor asked a new person to do. Here are a few examples, paraphrased and sometimes given a Safari twist:

  • Buddy up the new engineer with the last person who got the development environment running

Not the most experienced person on the team, not the team lead or the person who built the dev environment from scratch two years ago, but the last person who set it up.

  • Ask the new engineer to start emailing things they didn’t understand or learned every week (2–3 things per week)

This one is great because even if a manager or a more experienced engineer sets aside time for one-on-ones, a new person might avoid or delay asking questions for several reasons. They might not want to bother someone who is obviously busy, or want to avoid asking what they think are foolish questions. Asking them to send questions invites them to open up and sets the expectation that they won’t understand some things. This could be a big win for some of the more reticent personalities joining a team.

  • Give the new engineer a map of people on the team, what they work on, and their areas of expertise

I wish that every time I had joined a team someone had given me this document. Imagine if, as a new engineer, you could easily find the person on the team who knew the most about Redis, or a particular internal web service or build process. Invaluable!

  • If they are more of a junior engineer, ask them to give a 5 to 10 minute presentation on a small topic biweekly or monthly (internal products, Python or JavaScript language features, testing methods). These should be things they can research independently that are useful to know.

This one is cool because it sounds super annoying, but it could really benefit junior programmers and interns. Just the other day, my boss was like, “How does SAML work again?” and I struggled through a hand-wavy explanation before giving up and admitting that I still didn’t have some of the details down. I guarantee you that if a junior engineer joins the team, I will ask them to give a presentation on SAML.

There was tons of other great advice, like having “code labs,” which are times that a new engineer could ask a more senior person any question, even something simple or embarrassing [A reddit AMA?—Ed.]. Also shadowing or short-term pairing, where the engineer sits (or remote screen-shares) with someone on the team to get exposure to the whole development workflow that the team uses.

Summing up, and more resources

One of the main ideas that I took away from the talk was that a new engineer’s first month could be very explicitly about the team welcoming them and guiding them through what is always a very complex, fast-moving world of new code and people. It sounded great, and I immediately wanted to go back and make the onboarding process at Safari even more awesome. I put together a proposed schedule of onboarding activities that we can try with new hires based on what the presenters suggested. I’m stoked for our next employee!

Kate Heddleston & Nicole Zuckerman gave a talk "Technical on-boarding, training, and mentoring" at PyCon 2014

The video from Kate Heddleston & Nicole Zuckerman’s great talk “Technical on-boarding, training, and mentoring” at PyCon 2014

Now that PyCon is over, the talks are all online, so you can watch a video recording of “Technical on-boarding, training, and mentoring”.

For a completely different perspective on onboarding, check out how WordPress does it by making everyone rotate through their customer service team (from The Year Without Pants).

Search suggestions with Solr using multiple analyzers

There are some great new search suggestion (aka autocomplete) features showing up in Lucene and Solr. The Solr documentation hasn’t quite caught up, so I thought sharing my experience might be helpful to others working on using these features. The Solr features build on capabilities added to Lucene which are described well in a series of blog posts by Lucene guru Mike McCandless starting with this one, but it still requires a bit of finagling to decide exactly how to use these features.  I’ll describe our use case, and present some interesting extensions I needed in order to get things working just how we wanted.

Continue reading

5 Tips to Get Started with Android Development

With sales of Android devices growing, there’s no better time to get started crafting your first Android app. Here are the five things you need to know before creating that first killer app.

1. Understand the Java Programming Language. Java is Android’s main programming language. Learn object-oriented programming concepts, Java language fundamentals, including packages, classes and objects, interfaces and inheritance, numbers and strings, Generics, Collections, and concurrency. The more you understand Java, the more robust and elegant your Android apps will be. The best-selling book Head First Java is a great place to start learning the fundamentals.
head first java

2. Choose Your Development Environment and Tools. Get familiar with the integrated development environment and the build automation tools. For development tools, you can use Eclipse, or the newer Android Studio IDE. Both are free. In Developing with Eclipse, from Android Developer Tools, you’ll learn about the basics about Eclipse and many ways to use IDE to improve your code.dev with eclipse

For build automation, learn Apache Ant, Apache Maven, and Gradle, which provide a robust set of tools to manage your builds. Finally, get familiar with source control concepts and tools: learn git and create a git-source repository by creating an account on GitHub or Bitbucket. The Git Pocket Guide will help you understand the basic terms and concepts of how the platform operates. git pocket guide

3. Be Aware of Fragmentation. Given Google’s philosophy with respect to openness, Android is a fragmented market with its different OS versions and devices. Keep in mind that the more versions and devices your app supports, the more testing and maintenance (and related costs) that you will have.

The Gingerbread (introduced in 2011) version of Android still commands 20% of the Android device distribution. The market, however, is consolidating on Android 4.x and newer (this represents the last three major Android releases). Smartphones, tablets, and hybrid “phablets” each have different sizes and resolutions. You’ll need the appropriate assets, fonts and layouts that ensure the best possible experience across such different screen characteristics. See Design Apps for Tablets from the Android Developers Blog.

You also need to consider the array of Android supported sensors and/or UI facilities. For example, not all Android devices may support the same kind of camera, and they may not support Bluetooth. A good example is the Kindle, which is based on Android 2.3, but it doesn’t provide support for many of the hardware sensors or UI facilities found on other Android devices.

4. Understand the Android Application, Activity, Fragments and Services Application Components. All Android apps consist of an application class, along with one or more activities with one or more fragments. You may or may not have services for background tasks that need to continuously run. Android Fundamentals, from Building Hybrid Android Apps with Java and JavaScript, will help you learn the essentials of these components.
android fundamentals

5. Learn About Threads, Tasks, and Loaders. Delivering a “great user experience” is the golden rule on mobile, so the main system (user interface) thread must never be blocked to ensure a great and smooth user interface. So, long operations (network, I/O, computations) must all be run asynchronously in the background, typically on a different thread of execution. For this, you must learn the Java language concurrency facilities. Read about thread and synchronization in Java: A Beginners Tutorial:java threads

You’ll also want to understand Android’s own facilities that allow parts of your app to run asynchronously in the background. This chapter from Pro Android 4 will walk you through building your first AsyncTask: pro android

Special thanks to C. Enrique Ortiz for his help in writing this blog post. Ortiz (@eortiz) is a well-known expert and author on mobile software development.

Career transition: from a startup to a larger company

Over the course of my career I’ve spent most of my time working at smaller companies (less than 20 employees). I recently joined Safari, so the 150+ employees that work here is my first taste of a “larger company.” I realize to some that’s still a small company, but there’s no shortage of new experiences and things I’ve had to learn.

I’ve seen numerous posts on what it’s like to transition from a larger enterprise to a startup, but I haven’t read anything on the opposite experience. It’s been a wonderful experience so far, and the rest of this post summarizes my learnings.

Remembering names

To kick things off with a bit of humor, remembering names might be my biggest challenge so far. I’m terrible at this, so I find myself talking with coworkers and feeling bad that I have no clue who I just spoke with.

To my chagrin, everyone remembers my name. It helps to have Hipchat list names of coworkers, but remembering everyone is something that will take time.

Startup flexibility vs. BigCo entrenchment

If you work at a smaller company, they will tout the fact that they are more flexible than a large enterprise. This is generally true, yet doesn’t mean that larger companies can’t move quickly. I’ve been very surprised at how quickly Safari is moving.

In Clay Christensen’s book “The Innovator’s Dilemma,” one of the biggest challenges that companies face is when to invest in new technologies/markets. Typically disruptive innovation sneaks up on larger enterprises, and overtakes the old way of doing business very quickly (destroying the BigCo in the process).

This book serves as a cautionary tale, but my point is that many larger companies are fully aware of the need to constantly reinvent themselves. Safari is one of them.

As a result, large companies have smaller products/initiatives they are working on. This is essentially a startup inside a larger company, and there’s plenty of opportunities to move quickly, make an impact, and grow the business in a big way.

blah blah

Photo courtesy of Philippe Lewicki via CC BY-NC-SA 2.0

Balancing processes

I’m a big believer in the power of effective processes. There’s value in establishing a set way of doing things (larger companies) vs. unstructured tasks (typically work at a startup). Clearly this can be a double-edge sword. My role (marketing/growth) requires that I move at a fast pace, yet at the same time I must be cognizant of how to document issues in programs like JIRA and follow normal development sprints (still working on this). The key here is to balance normal processes, while still moving quickly.

Who should I talk to about ________ ?

At an early-stage startup, it’s normal to be the sole person responsible for a particular function. In a larger company, more teamwork is required. As a result, it can take time to understand the people who can help you accomplish particular tasks. If I had any advice on navigating through this process, it’s to ask questions. Get a copy of the company org chart or segment chat rooms related to particular projects.

The “make a difference” myth

Many people join startups because they want to make a difference. That’s a fantastic goal, but you can make a difference at a larger company, too. In fact, I daresay you could make a bigger impact at a larger company.

For example, Safari is participating in the ConnectED initiative, and providing $100 million dollars worth of technology resources to K-12 students.

How many startups have the resources to provide this? Not many.

I’m really excited about this, as I was in high school and would have loved to have access to the Safari library of books/videos. I’m thrilled to help the vocational center that I used to go to receive access to these resources, and they will be early “beta testers.”

Employment “risk”

Startups are not all fun and games. You might have your job one day and lose it the next. If you’re comfortable with ambiguity, a startup might be right for you. If not, I highly recommend working at a well-established organization. I tend to be risk averse, so there’s definitely a sense of comfort around knowing that the company you work for is profitable and growing.

Dynamics of a larger organization

If you work in a startup, and plan to sell your product/service to the enterprise, it’s probably a good idea to understand the dynamics of how a larger organization works. Who holds the credit card and needs convincing? Who’s in charge of a specific function, and what’s their decision-making process look like?

It’s for that reason that I recommend working at larger organization. There’s no better way to learn than by full immersion.

Wrapping things up

If you learned anything from this post, I hope it’s that you shouldn’t trust stereotypes of what it’s like to work at a startup or large organization.  Be open-minded and do your research.

I hope you enjoyed this post, and if you have any comments or thoughts, let me know on Twitter, or just comment below.

Using your iPad to learn about Android?

Android has been trending in the news because of this recent Gartner report, showing the Google OS as the clear number one among new tablet sales in 2013, surpassing iOS.

Not surprisingly, the subject of Android development has been steadily rising in popularity in Safari Flow. During 2013, Android was the twelfth most popular topic among Safari Flow users. During the first two months of 2014, it climbed to our ninth most popular topic. And the week following the release of the Gartner study (March 3), Android surged to the sixth most popular topic. “Android” is also the sixth most common search term since the beginning of the year.

But it’s difficult to ignore the irony that the vast majority of our Flow users sign in with their Apple mobile devices to learn about Android. Of all the visits from mobile devices to Safari Flow, the iOS share increased from 56.7% in 2013 to 62.4% in 2014. Android devices, meanwhile, have dipped slightly from 41.2% of the visits in 2013 to 35.8% in 2014.

Getting started in Android development?

On Wednesday, we’ll offer five tips to help you get started with Android development. Follow our blog (click + on the bottom right of this page) to get a reminder when the post is live.

In the meantime, check out our Android topic page to get a sampling the most popular books and videos about Android. And here are three titles released this year that we highly recommend:

image of book cover
Android: How to Program, January 2014

by Paul Deitel, Harvey Deitel, and Abbey Deitel

 

 

image of book cover


Android Recipes: A Problem-Solution Approach, February 2014

by Dave Smith and Jeff Friesen
 

 

image of book cover
Learning Android, January 2014

by Marko Gargenta and Masumi Nakamura

What publishing needs from the web (and how you can help)

For a few months now I’ve served as co-chair of “DPUB”, the W3C Digital Publishing Interest Group, (with Markus Gylling, who somehow has time to be a wonderful CTO of two different standards organizations). DPUB acts as a channel for those of us in digital publishing to influence the development of web standards like HTML5 and CSS3. The group has already produced two public documents describing use cases for text layout and for annotations, which we’re quite proud of. But we’d like to do more, and we need your help.

Let us know what interests you (and please join the public mailing list).
Continue reading

How you’re using highlights and notes in Flow

We recently added support for creating highlights and notes to Flow. Based on a modified version of Annotator, this feature allows you to highlight some text and, if you like, leave a comment about that text.

Highlighting some text and making a note

Highlighting some text and adding a note

Once you save the highlight, it is automatically posted to the site, like so.

Internally, we’ve been using this feature a lot, both for utility and for fun. The highlights collections page helps one of our engineers track his favorite snippets. Meanwhile, our VP of Engineering saw the perfect opportunity to troll our CEO. (She still works here.)

Until now, we haven’t talked publicly about this new feature, but we’ve been happy to see that some of you have managed to find and use it regardless. I spent some time today looking at the site analytics and individual highlights to see what I could learn about how you’re using this feature. Note that the following data includes users internal to Safari. Also, because the highlights functionality is so new and until now unannounced, we don’t have a lot of data to go on. But it’s still fun to take a look. Here are some things that I noticed.

You don’t like adding notes, much

I was surprised to see that 68.64% of highlights do not include a note of any kind (which is optional, remember). Most of you just highlight what you like and leave it at that.

Even when you do include a note, it is usually a short commentary, with some occasional dry humor thrown in.

You don’t like sharing, much

Notes and highlights include the social sharing buttons that you’re used to seeing on the web (Twitter, Facebook, and Google+, in this case). In fact, you’re apparently so used to seeing them that you’ve become really good at ignoring them.

Only 11.01% of highlights have been shared on social sites via those buttons. Rather than use the social media buttons, some of you simply copy and paste the URL (which is my preferred method, too) from the highlight page into your Twitter or Facebook client, although that data is more difficult to isolate.

You stay longer when you highlight

If you’re adding highlights as you read, you tend to stay twice as long on average versus those who don’t add highlights. Good work, highlighters. Good to see you’re the diligent sort.

You use highlights to keep the conversation going

Because they are publicly viewable, highlights are a nice way to share content that would otherwise require a Flow account, allowing you to post them and make useful connections to related technical discussions on the web. I’m thrilled to see such a practical and smart use of the tool.

I have no idea what this all means

While it’s fun to look at the data and the individual highlights and we’re excited about the possibilities, it’s probably too early to draw any meaningful conclusions about how we can improve this feature. Now that you know you can add highlights and notes as you read, I hope you find them useful in your work. In any case, let us know what you think. We’ll keep polishing in the meantime.

All of a Sudden – Tech

We’ve all heard stories about career changes “later in life,” and while I’m still enjoying some level of healthy denial as I move swiftly into my fiftieth year on the planet, I find myself apparently living one of these tales.

About a year ago, I decided that I needed something more from a career. I had been working as a Realtor for twelve years and while I enjoyed many aspects of the job, I was not thrilled with the idea of selling myself to really build the business; I’ve never been the handshaking, salesman type, ready to draw out a business card like a pistol at a shoot-out. It’s just not me – it was all I could do to remember to have my business cards with me.

carMy predicament became a topic at a barbecue one afternoon, and a friend asked if I had ever heard of “Salesforce” or a “Salesforce Administrator” – I had not. In fact, I had absolutely no background in the tech industry or anything remotely related. The closest I came to any experience was a basic programming class I completed as a college freshman (back in the Computer Cretaceous Period). I was also something of a math “whiz kid” in high school (see: “Woulda Coulda Shoulda”) but other than these brief brushes – nothing.

What followed the barbecue exchange were a series of conversations and online research over a few weeks until I was convinced and interested enough to take the first training, Administration Essentials for New Admins (ADM-201). I was intrigued by learning something entirely new and interested in the puzzle solving and detective work it seemed would be required as a Salesforce Administrator; I love to unravel problems and hunt for solutions – this was really what motivated me to take that first step – the challenge of it all.

The ADM-201 training is a relatively soft exposure to the Salesforce Customer Relationship Management (“CRM”) platform’s environment. In the exercises, you set-up the users and systems, complete customizations, and set access, among many other things, for a mock corporation’s platform (or the “org.”). A problem I noted right away with the first training is that the Fauxecutives who submit requests do so in almost perfectly articulated Salesforce-speak; in other words, in the real world I knew that issues and requests would not be so perfectly worded. Salesforce Administrators are not just detectives – they are translators, as well.

mouseThat said, my first training was a healthy introduction to the environment and I subsequently sat for the certification test. Common knowledge holds that there is a 60% average failure rate for the first test, a fact that I knew going in and that caused my right eye to twitch slightly; but I passed the first time – and was reassured that, although the hamster in my head may have … um … matured … and played on a rusty wheel, he could still run. Phew!

Once I had my new certification in hand, I updated my LinkedIn profile and really very little else. I did poke around online about how to get into the biz, but no one offered a viable way. I live in rural west Sonoma County and the job market here is limited, at best. For a while it seemed my career change had stalled. I thought, “Now what?”

Four months passed and then suddenly – an email arrived – my LinkedIn profile update had been noticed and well, the rest is (recent) history. Here I sit as a new Salesforce Administrator at an amazing company, Safari Books Online, right in my hometown – and I love it.

Once in, it quickly became clear that I would need more than the somewhat cursory pass at Salesforce that the ADM-201 modules had provided. So, in early March, I completed Building Applications with Force.com (DEV-401) at the Salesforce University, located on the 3rd floor of the Salesforce mother ship in San Francisco. (Turns out, there is an “ice cream floor” at headquarters (It’s Its! All three flavors!), but I’ve been sworn to secrecy as to the exact location – sorry.)

The overarching theme of the DEV-401 training was building Force.com applications. We learned how to create custom objects, fields, lookup relationships, master-detail relationships, lookup filters, applications and tabs and most importantly, learned the differences between these components. We studied the relationships between objects in-depth, with the help of charts, an exercise and a student guide, and solid instruction.

We drilled deeper into our training org., creating layouts, formula fields, cross-object formulas and roll-up summary fields. This section of the training increased our understanding of field dependencies, object relationships (Parent-Child) and how these settings can impact the overall user experience.

We continued by completing exercises designed to provide a clearer understanding of the Salesforce sharing model, with training in Organization-Wide Defaults, Role Hierarchy, Public Groups, Sharing Rules and Apex Sharing Reasons. This section was very helpful and will be key to furthering my understanding of how to provide the appropriate access to end users in our real world org.

sfWe then learned how to embed images directly in records and created hyperlinks. We also looked at data security, and practiced with Validation Rules and field level security settings; these are important aspects to understand as they help to protect the quality and integrity of the data.

A very interesting portion of the training, which I believe will be of direct benefit, were the areas we covered regarding Workflow Rules. The takeaway was that many of our current processes that are now hard-coded could have been easily accomplished declaratively with Workflows and Tasks – a slogan at Salesforce is “Clicks not Code,” and now I know why. The question remains; can these simple point-and-click solutions work now with the code currently in place in the background? We shall see.

The remainder of the training focused on Visualforce, which provides the ability for a Developer to customize the UI that the end user sees. We moved into understanding and creating Flows (simple input frameworks), which I don’t feel will ultimately be that useful but it did expose me to aspects of the platform I didn’t know existed; they’re kind of fun, too! It might be nice, at some point, to create a Flow for new Leads or Account entry through a user-friendlier process for our Sales Reps., for example.

In this module, we also created a Visualforce page relative to our training org., adding new templates, images and web content. This required learning some basics with regard to writing Apex code, and I found this really engaging and interesting. I picked-up several handy tips that will help a lot as I do my detective work with regard to our Apex code. As a beginner, this portion of the training really lit a fire in my belly and fueled my desire to learn more.

binaryTo summarize in the abstract, the DEV-401 class revealed the “Why?” of components and systems that exist in the Salesforce platform, whereas the ADM-201 training is really just an introduction to the core environment and exposure to some basic principles (the “What?” and the “How?”).

I had an excellent instructor in the DEV-401 training, Leah McGowen-Hare, who really took the time to illustrate in simple terms some of the very complex and deeply buried features of Salesforce – she used an entire wall of the room, covering it with diagrams, thereby grounding otherwise cryptic concepts – I’ve never witnessed such skilled use of Dry Erase Markers.

classI feel much more equipped and confident now as I move forward. It also became clear, as a result of our complex business processes and amount of hard-coding here at the home office, that I am already performing development-level work as opposed to basic Administrator tasks, and that realization has helped a lot with my confidence.

The next best training for me would be Introduction to Object-Oriented Programming with Force.com (ADM-231, formerly DEV-531), which is more in-depth with regard to writing/understanding Apex code, and follow that with Apex & Visualforce Controllers (DEV-501) some time in the future.

Until then … may the Salesforce be with you.

greyhoundP.S. It also helps that Safari Flow offers some great titles to help me with my journey. I particularly enjoyed Salesforce.com® For Dummies®, 4th Edition, which is a good way to start exploring the Salesforce universe (actually, it’s more of a multiverse). Another engaging text to check-out is Teach Yourself VISUALLY Salesforce.com, which offers a unique training approach – sort of like a firm handshake between the left and right sides of the brain.

Join our team! Now hiring a UX Copywriter

Safari is busily rethinking and rebuilding our product set, company website, brand identity, and the entire way we communicate with our customers. And we want to hire a remarkable copywriter to play a central role in how we delight the next million customers.

In the past six months, we have launched two new products and committed to a bold new initiative. Our new flagship, Safari Flow, helps people learn by recommending chapters from the world’s best technology, business, and design library. Our second new product, Safari Tutorials, is a lightweight alternative to enterprise learning that’s taking everything we’ve learned about consumer engagement and bringing it to corporate learning. Finally, we pledged with the White House in January to give access to over $100,000,000 worth of books to every school in America to help kids learn how to master technology.

The next six months are going to be even busier, and we need you to help us articulate ourselves in the best possible way to the widest audience, through all of our products.

Scan from peacay, cropped.

Scan by peacay, used under CC-By A / Cropped from original

You will be an extremely autonomous craftsperson who simultaneously delights in your work and understands when your words aren’t working. You’re borderline rabid about testing and incremental improvements, and are equally obsessive about quality and tone of voice. But your attention to detail won’t get in the way of you shipping words or trying out new things. Ideally, you’ll be as happy in GitHub as you are in WordPress, Google Docs, and Twitter.

You’ll help lead the charge on end-to-end product language for new customers coming to us from search or ads, all the way through our marketing content, into the product onboarding, and to our engagement emails and beyond.

You will need to thrive in a dynamic workplace while completing successful projects on tight deadlines.

Responsibilities

  • Participate in all phases of the product development lifecycle from conceptual design through release to make sure the language in each product is clear, direct, and persuasive
  • Partner with designers, engineers, and the product team throughout the product development process to write and edit text for our products and features with a strong focus on the user
  • Perform A/B and multivariate testing on copy, measuring and iterating as you go
  • Write brief, persuasive, focused text that keeps users engaged and encourages adoption of product features
  • Recommend and implement new strategies for communicating product-related information to our users
  • Help establish content style guides and consistent terminology

The UX Copywriter will report to the Program Manager. This position may be based in San Francisco, Boston, or remote.

Learn more about the requirements and apply. Or if you have any questions, feel free to ping me on Twitter.

Your shortcut to awesome

As you may have heard on Twitter, we recently added tons of keyboard shortcuts to Safari Flow. While developing this feature, my goal was to be able to navigate the entire app without picking up my hands from the keyboard. Let us know what you think, but I think it’s wonderful.

To try out the shortcuts, first log into Safari Flow. Once you’re in, you can see a full list of shortcuts from most pages by pressing the ? (Shift + /) key.

screenshot of keyboard shortcuts

Get info on keyboard shortcuts with ?

While I like being able to more easily navigate the reading interface (for example, you can open the table of contents by typing t), my favorite shortcuts are related to navigating through cards and quickly adding them to my queue, removing them from my recommendations, or going directly to a chapter. To try out these shortcuts, use your arrow keys to navigate the cards.

animation of a user cycling through cards

Use the arrow keys to select cards

Any of the arrow keys focus the first card on the page.1 Once a selected card receives focus, you can cycle focus through its individual elements using the Tab key.2 Pressing Enter on a focused element is the same as clicking it.

animation of a user cycling through through individual links within a card

Use tab to cycle through selected card elements

Once you’ve focused on a card there are special shortcuts you can use: q to add the chapter to your queue, d to remove the card from your recommendations, Shift + Enter to go directly to the chapter, and Escape to remove the selection from the card.

How we did it

Changing the tabindex of an HTML element to -1 allows you to set its focus and change it’s tab precedence. Once I read about this on the Twitter blog, I knew that implementing it for our cards would be the bee’s knees.

Walking the DOM

Selecting cards is a simple matter of tracking it’s index in an unordered list (with JavaScript) and then changing it’s attributes. A selected card should have these attributes: a selection HTML class for targeting purposes, -1 tabindex, and focus.

On most pages (Queue, Recommended, and Recent), the cards are stacked inside an unordered list, which makes traversing them easy. The homepage is a bit different—each category of cards is wrapped inside a section HTML5 tag, so you need to know when to “jump” to the next or previous row. This can be accomplished by looking at the :first-child and :last-child of the list items.

Selecting the card above or below it is a bit trickier because they are responsive. In order to jump to the card directly above it or below it within an unordered list, you need to to know how many cards are in the row. If there are three cards, jumping three cards above will take you to the card directly above it in the next row. This is tracked by putting our responsive CSS breakpoints into variables, checking them against the width of the viewport, and storing their index in a “jump” variable.

  var $cards = $('.js-bitlist'),
    $first = $('.js-bitlist:first > li.card:first-child'),
    isHomepage = $('body').hasClass('homepage');

  selectNextCard = function () {
    selectCard('next');
  };

  selectPrevCard = function () {
    selectCard('prev');
  };

  selectUpCard = function () {
    selectCard('up');
  };

  selectDownCard = function () {
    selectCard('down');
  };

   selectCard = function (direction) {
    var $selected = $cards.find('.selected-card.card'),
      prev = direction === 'prev',
      next = direction === 'next',
      up = direction === 'up',
      down = direction === 'down',
      goPrevRow = prev && $selected.is(':first-child'),
      goNextRow = next && $selected.is(':nth-child(3)'),
      width = $('body').outerWidth(true),
      oneAcross = width < 768,
      twoAcross = width > 768 && width < 1280,
      threeAcross = width > 1280 && width < 1600,
      fourAcross = width > 1600,
      cardsInRow = [oneAcross, twoAcross, threeAcross, fourAcross],
      index = $selected.index() + 1;

    _.each(cardsInRow, function (row, i) {
      if (row) {
        this.jump = i + 1;
      }
    });

    if ($cards.length) {
      if (!$selected.length) {
        $first.attr('tabindex', -1)
          .addClass('selected-card')
          .trigger('focus');
      }
      else {
        if (isHomepage) {
          if (!(next || prev)) {
            if (goPrevRow || up) {
              $cards = $selected.parents('section').prev().find('ul');
              removeSelection($selected);

              if (goPrevRow) {
                selectNewCard($cards, 3);
              }
              else {
                selectNewCard($cards, index);
              }
            }
            else if (goNextRow || down) {
              $cards = $selected.parents('section').next().find('ul');
              removeSelection($selected);

              if (goNextRow) {
                selectNewCard($cards, 1);
              }
              else {
                selectNewCard($cards, index);
              }
            }
          }
          else {
            $cards = $selected.parents('ul');
            removeSelection($selected);

            if (next) {
              selectNewCard($cards, index + 1);
            }
            else {
              selectNewCard($cards, index - 1);
            }
          }
        }
        else {
          removeSelection($selected);

          if (next) {
            selectNewCard($cards, index + 1);
          }
          else if (prev) {
            selectNewCard($cards, index - 1);
          }
          else if (up) {
            selectNewCard($cards, index - this.jump);
          }
          else {
            selectNewCard($cards, index + this.jump);
          }
        }
      }
    }
  };

  removeSelection = function ($selected) {
    $selected.removeClass('selected-card')
      .removeAttr('tabIndex');
  };

  selectNewCard = function ($cards, index) {
    $cards.find('li.card:nth-child(' + index + ')')
      .attr('tabIndex', -1)
      .addClass('selected-card')
      .trigger('focus');
  };

Finally, once you’ve set focus on a card, thereby allowing the user to cycle that focus through that card’s individual elements with the Tab key, you’ll just need to style all of its :focus elements.

1. Applies only to Queue, Recent, Recommended, and Home pages.

2. If you’re using the Safari web browser, you must first enable Tab key navigation.