Build & publish your own private npm package for free
Tags: npm, tutorial, javascript, a11y
Published: 2020-04-26 23:24:02

*Note: This is a real example, not a tutorial on how to print "hello world" with an npm package. So buckle up buckaroo.* 🤠 

Do you want to easily share code between projects? Do you want to keep that code private but avoid the monthly fee for privately publishing to npmjs dot com? Then this is the tutorial for you.

We'll be building an npm package, adding JavaScript and CSS, uploading to a private git repo on Bitbucket and making a simple project to test the package with.

> Final product: https://github.com/mocasalter/npm-package-demo

When we're done your package will accessibly✨ hide outline focus styles for mouse users but show them for keyboard users*. Like this:

![Button Outline Demo](http://i.imgur.com/8zVT8We.gif)

## Pre reqs

I assume that you know how to use the command line, have the [npm CLI and NodeJs](https://nodejs.org/en/) installed and know how to use them, and have [git](https://www.atlassian.com/git/tutorials/install-git) installed and have a decent grasp of how it works.

## 1. Start a new package

In your CLI, run these commands to make a new folder, navigate into that folder and initialize a new npm package.

```bash
mkdir smart-focus-ring
cd smart-focus-ring
npm init -y
```

Make a new folder called lib and a new file called index.js. Index is the default entry point file for an npm package, and lib will hold the custom files.

```bash
mkdir lib
touch index.js
```

Then open the smart-focus-ring folder in a text editor. If you have Visual Studio Code installed you can run the command `$ code .`.

Open package.json and add this files array. That will ensure the lib directory is downloaded whenever the package is installed.

```json
{
  "otherStuff": "",
  "files": [
     "lib"
  ]
}
```

## 2. Add JavaScript

Create a new file in lib called smart-focus-ring.js and paste in this code.

```javascript
function handleFirstTab(e) {
  if (e.keyCode === 9) {
    // the "I am a keyboard user" key
    document.body.classList.add('user-is-tabbing');
    window.removeEventListener('keydown', handleFirstTab);
  }
}

function smartFocusRing() {
  window.addEventListener('keydown', handleFirstTab);
}

module.exports = smartFocusRing;
```

It adds a class `user-is-tabbing` to the body when the user hits the tab key.

That last line `module.exports` exposes the `smartFocusRing` function as a module so we can use it in index.js.

## 3. Export the function

Now import `smartFocusRing` into index.js.

```javascript
const smartFocusRing = require('./lib/smart-focus-ring.js');
module.exports = smartFocusRing;
```

`module.export`-ing  from the package's entry point (index.js) makes `smartFocusRing` available to any project that has installed the smart-focus-ring package.

## 4. Add CSS

Now add CSS to make the style changes based on whether the `user-is-tabbing` class is present on the body. 

In the lib folder, add a new file called styles.css and paste in this code.

```css
/* Hide the focus ring until we know it's needed */
button:focus,
input:focus,
select:focus,
textarea:focus {
    outline: none;
}

.user-is-tabbing button:focus,
.user-is-tabbing input:focus,
.user-is-tabbing select:focus,
.user-is-tabbing textarea:focus {
    outline: 2px solid #7aacfe !important; /* for non-webkit browsers */
    outline: 5px auto -webkit-focus-ring-color !important;
}
```

Your directory should look like this.

```
└───lib
│   │   smart-focus-ring.js
│   │   styles.css
│   index.js
│   package.json
```

## 5. Publish to Bitbucket

At this point you could publish to npm if you wanted to but there's a monthly fee for private packages so we'll use Bitbucket instead.

Run these commands to create a new repo inside the smart-focus-ring folder.

```bash
cd /path-to/smart-focus-ring
git init
git add .
git commit -m "Initial commit"
```

Then create an account on bitbucket.org and a new, private git repo on Bitbucket.

![Bitbucket's Create New Repo Screen](https://dev-to-uploads.s3.amazonaws.com/i/f38zllyvz8q4houstvmo.PNG)

Run these commands to upload your local repo to Bitbucket.

```bash
git remote add origin git@bitbucket.org:YOURUSERNAME/smart-focus-ring.git
git push -u origin master
```

And you'll see a warning that looks something like this.

![Warning, permission denied](https://dev-to-uploads.s3.amazonaws.com/i/d7q447qtqbu6e7l3uvpe.PNG)

This is where things get interesting.

### SSH keys

That warning comes up because you haven't given your computer permission to use your private Bitbucket repo yet. To do so, follow Atlassian's walk through on [setting up SSH keys for Bitbucket](https://confluence.atlassian.com/bitbucket/set-up-an-ssh-key-728138079.html) for your operating system.

...Or if your privacy isn't *that* important, you can go to your Bitbucket repo, select Settings and uncheck the box for "This is a private repository."

Then run this command again and that warning should be gone.

```bash
git push -u origin master
```

## 6. Make a test project

Create a new project folder, initialize npm and make some files.

```bash
mkdir tester-project
cd tester-project 
npm init -y
touch index.js
touch index.html
```

Add some html to index.html.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Tester Project</title>
    <style>
        body{font-family:"Open Sans",sans-serif;}
        button{border:none;border-radius:0;padding:0.65em 1.2em;cursor:pointer;color:#fff;background:#8d6e91;}
        button:focus{background:#AB90B2}
    </style>
</head>
<body>
    <h1>Tester Project</h1>
    <button type="button">button</button>
    <script src="index.js"></script>
</body>
</html>
```

And install a bundler so we'll have ES6 module support.

```bash
npm install -g parcel-bundler
```

Run the bundler and go to the url it gives you. Mine was localhost:1234.

```bash
parcel index.html
```

Now try clicking the button. See how it has a focus ring? Once the package is installed, that focus ring will only show if you've indicated keyboard navigation by hitting the tab key.

![Button with Outline](https://dev-to-uploads.s3.amazonaws.com/i/4irp0nukwqe26mlabzyp.jpg)

## 7. Import the module

Install the package using your Bitbucket user name.

```bash
npm i git+ssh://git@bitbucket.org:YOUR-USER-NAME/smart-focus-ring.git
```

Import the smart-focus-ring assets into the index.js file and call the `smartFocusRing` function.

```javascript
import smartFocusRing from 'smart-focus-ring';
import './node_modules/smart-focus-ring/lib/styles.css';
smartFocusRing();
```

Then run Parcel and go to the url it provides.

```bash
parcel index.html
```

Now if you click the button the focus ring will be gone, but it will appear when you hit the tab key. All thanks to your npm package! Congratulations! 🥳
![Button Outline Demo](http://i.imgur.com/8zVT8We.gif)
<hr />
*\*As seen in [Removing that ugly :focus ring (and keeping it too)](https://medium.com/hackernoon/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2).*