Permit.js is a jQuery plugin that makes building interactive, multi-state prototypes for websites and apps easy.

Maybe your website has certain features that are only available to logged-in members and other features only available only to administrators? Or perhaps your app has different features depending on whether it's on- or offline? Or what about the free versus paid versions? These are all examples of states.

Permit.js makes simulating those different situations a breeze. It's designed for use by anyone that does interactive prototype work in HTML and CSS, including information architects and other user interface and user experience (UI/UX) professionals.

Simple Demos

Logging-in / Logging-out

Online / Offline

Multipage Demo

You're currently logged out.
You're still logged in. Return to the demo.

Use Cases:

  • Authentication: Logged-Out / Logged-In
  • Membership: Free / Paid
  • Connectivity: Online / Offline
  • Roles: Writer / Editor / Publisher
  • Permissions: User / Moderator / Administrator
  • Content: English / French / Spanish

Take Your Prototypes to the Next Level

Use Permit.js to improve how your prototypes simulate complex, interactive behaviors.

Laughably Easy to Implement

No server side langauges necessary. Just load Permit.js, specify your states and apply some simple CSS.


Permit.js persists across pages and sections of your website/app. "Issue a permit" and then surf around your entire site to get the full user experience for any of your states.

How Does it Work

It's pretty simple. The plugin combines javascript-generated cookies with a set of dynamically-generated CSS utility classes to show and hide content. When you "issue a permit" with permit.js you're really just creating a cookie that remains in the browser throughout your prototype. Content is then displayed or hidden based on the existence (or non-existence) of the permits that have been issued.

That's all? Did it really need a plugin?

Permit.js greatly simplifies the process of managing cookies and using them to create dynamic, multi-state prototypes. Cookies can be created, updated/swapped, and destroyed solely through your CSS classes (e.g., class="permit-issue-mystate"). Furhter, it provides a highly flexible, universal, and project-specific (semantic) means of doing all of this.

Sure, you could write your own js and css to do the same, but you'll probably find yourself re-writing and altering the code for your next project. Trust me, that's what I found myself doing, and that's why I made it. In addition, if you're not comfortable with javascript, you barely have to touch it.


1 Include dependencies and permit.js

Permit.js requires jQuery and the jquery.cookie plugin. You must load those before you load permit.js.

<script src="js/jquery-1.10.1.min.js"></script>
<script src="js/jquery.cookie.js"></script>
<script src="js/permit.min.js"></script>

Download Permit.js

2 Instantiate

The only required setting is the 'permits' setting. This is where you specify your states.

        permits: ['free','premium','admin']

Currently, the plugin has one additional optional setting.

3 Create a "Permits Agent"

The optional "agent" will help you issue your permits and change between your states. Create a container with an ID of 'permit-agent'. When the script is instantiated, this container will be populated with a dropdown of your available permits. The agent issues a new permit when you click on an element with a class of 'permit-reissue'. You don't have to use the agent. If you prefer you can just issue or revoke permits using the plugin's helper classes.

    <div id="permit-agent">
        <!-- A dropdown with your states. -->
    <button class="permit-reissue">Issue Permit</button>

The demo includes the agent inside a Twitter Bootstrap modal. This is purely for effect. You may place your agent anywhere.

4 Apply CSS

Permit.js creates several personalized helper classes based on your instantiation settings. All you need to do is apply a generic 'permit' class plus one of these personalized classes to your HTML markup. The following example shows how you might apply your CSS classes in the case of three states: free, premium, admin.

Custom Classes

<div class="permit permit-free">
    <p>Visible to free users (only).</p>

<div class="permit permit-premium">
    <p>Visible to premium users (only).</p>

<div class="permit permit-admin">
    <p>Visible to admin users (only).</p>

Combining Classes

You can combine any of your custom classes. For example, if you want a block to show for free and premium users, but not admins, you could do the following:

<div class="permit permit-free permit-premium">
    <p>Visible to free and premium users, but not admins.</p>

Default Classes

In addition, you can use .permit-all and .permit-none classes.

<div class="permit permit-none">
    <p>Visible only when no permits have been issued (e.g, in a fully logged-out state).</p>

<div class="permit permit-all">
    <p>Visible to all permit levels. Invisible if no permits are present.</p>

Additional Helper Classes and Advanced Usage

Permit.js provides additional helper classes that allow you to create even more complex, interactive experiences. Also see the plugin's API for even greater flexibility.


Apply this class to an element (e.g. a button) to issue a permit. Replace [permitName] with one of the states you specified in the permits setting (e.g., permit-issue-premium). By default, the permit will be issued by clicking on the element. The permit that was in place prior to clicking on the element is revoked. You would use this in a variety of situations such as to simulate logging-in, upgrading, or for switching from online to offline mode. When using this class, two optional data attributes are also available: data-permit-trigger and data-permit-destination.

data-permit-trigger (optional)

You can change the default trigger from a click to any other jQuery mouse event by specifying it here. For example, you could change the event to 'hover' or 'dblclick'.

<a class="permit-issue-premium" data-permit-trigger="hover">Upgrade</a>

data-permit-destination (optional)

Set this attribute to a url to redirect the user to that location after execution. You can set this to a local, relative path (e.g., homepage.html) or to a fully valid url (e.g., If you exclude this attribute, the current page will reload.

<a class="permit-issue-premium" data-permit-destination="credit-card.html">Upgrade</a>


Apply this class to an element (e.g. a button) to revoke all permits. By default, it is trigger on a click event. You might use this to simulate a user log-out button. When using this class, you may use the same data-permit-trigger and data-permit-destination attributes described under .permit-issue-[permitName].


Apply this class, along with a custom data-messsage attribute, to replace the element's content with a custom message. For example, apply this class to replace a block of premium features with "Upgrade Now". The content in the data attribute gets injected using jQuery's html() method, so you may include html inside the message attribute.


Set this attribute to specify the custom message that will appear if the required permit level(s) are not present.

<div class="permit permit-force permit-premium" data-permit-message="Please <a href='#'>upgrade</a>">
    <p>This content will show when a premium permit is present, otherwise it shows the message defined in the data-permit-message attribute.</p>

Public API Methods

For the ultimate control on issuing (or revoking) a permit, try the API. You can issue (or revoke) a permit whenever, wherever, and however you want.

Method Description Format Example

Issue a specific permit. The permit parameter must have been specified in the 'permits' setting.

The destination parameter is optional and accepts any relative or absolute url. If the destination parameter is excluded the current page will reload.

$.permit.issuePermit( <permit>, <destination> ); $.permit.issuePermit('premium', 'thanks-for-upgrading.html');

Revoke a specific permit. The permit must have been specified in the 'permits' setting.

The newPermit parameter is optional. Specifying a newPermit will issue that permit to the user as soon as the original is revoked. This might be used in the case of an account downgrade (e.g., from premium to free). If the parameter is excluded, no new permit is issued.

The destination parameter is optional and accepts any relative or absolute url. If the destination parameter is excluded the current page will reload.

$.permit.revokePermit( <permit>, <newPermit>, <destination> ); $.permit.revokePermit('premium', 'free', 'sorry-to-see-you-go.html');

Settings & Options

Setting/Option Description Default Example
permits Object of available states. ['admin'] ['free','premium','admin']
reissueDestination Specifies the action to be taken when a new permit is issued using the permits agent. Defaults to a javascript-enabled page reload. Otherwise it redirects to the specified location. 'reload' 'dashboard.html'

FAQ and Troubleshooting

Can I use this on a production website to create a members-only area or somehow restrict access to content?
Absolutely not. Do not in any situation use permit.js as a means of actually securing content. The plugin is meant to be used for prototyping purposes only. The plugin uses a combination of javascript cookies and CSS to hide and show content. That's not at all secure and any code kiddy can easily "break-in".

I'm seeing a brief "flash of unstyled content" (FOUC) when I load pages with permit.js.
That's because we're not using any server-side code to produce the pages. The plugin works by hiding or showing content based on the permit you've issued, which results in a brief flash of content before un-permitted content gets hidden. You can minimize this effect by adding a .permit{ display:none} to your CSS.

It's not working when I try to run it locally.
I figured this one out the hard way. Some browsers won't create cookies when using a file:// URI; see this StackOverflow post. Firefox seems to work fine, while Chrome does not. In addition, some of the plugin's settings (e.g., revokeDestination: 'http://'+window.location.hostname) will not behave properly when using the file:// URI. I recommend using either a local server environment (e.g, via WAMP, MAMP, Vagrant) or a remote server to avoid browser issues like these.
Can I issue multiple permits at the same time?
In most cases, what you're probably trying to do can be done by applying multiple permit classes to the same element (e.g, .permit-free and .permit-premium). However, I can imagine a case where you might want to try very complex state combinations like free+online/offline and premium+online/offline. That's not possible...yet.

How can I stay abreast of updates to this plugin?
Watch or star the project's GitHub repo.

How can I get support?
Submit an issue on the official repo. In general, I offer no warranties and can't guarantee any support. If you'd like to hire me to support this plugin or for any of my other skills, please contact me.

To Do

  • Add support for multiple, simultaneous permits

Credits and License

Tarek Anandan, Washington DC, IA, UX, UI Specialist

Permit.js was developed by Tarek Anandan, a freelance information architect, UX specialist, and website developer based in Washington, DC.