JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 69
  • Score
    100M100P100Q8314F
  • License Apache-2.0

A base component to build inline-editable fields in the Atlassian Design Guidelines style

Package Exports

  • ak-field-base

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (ak-field-base) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

Commitizen friendly semantic-release Bug tracker Support forum

FieldBase

This component contains all the common behaviour and styles for fields

FieldBase provides an Atlassian Design Guidelines compatible implementation for:

  • Labels: spacing, margins, accessibility and click-to-focus functionality
  • Fields: sizing, borders, colors, wrapping behaviour, hover/focus states
  • Inline edit pattern: view switching, edit/confirm/cancel buttons, focus handling
  • Validation: styles, waiting states (built in validation coming soon!)
  • Keyboard navigation: view switching, confirm/cancel behaviour with associated focus styles

FieldBase's will work by themselves but are really meant to be extended into a full field component.

Try it out

Interact with a live demo of the ak-field-base component.

Installation

npm install ak-field-base

Using the component

FieldBase makes no assumptions about libraries or frameworks and can be extended any way you like; Skatejs, React or even Vanilla JS.

Creating your views

FieldBase works using two 'views' for your component editmode and viewmode. To set these up, simply pass them as children to your FieldBase with the appropriate slot attribute.

<ak-field-base label="My awesome field" id="myCustomField">
  <div slot="viewmode">
    <span id="viewModeValue">Your text here</span>
  </div>
  <div slot="editmode">
    <input type="text" id="inputField" value="Your text here" />
  </div>
</ak-field-base>

Note: It is very important to pass in the label prop even if you are hiding it using the hideLabel prop as the label is used to make your field accessible for screen readers.

At this point you will already have a component that can switch between views, handle keyboard navigation and set aside an appropriate amount of space.

However, this isn't particularly useful because our changes aren't saved!

Updating views

To keep our two views in sync, we'll need to set up some event handlers to tell us when a user is switching views.

The two events for this are exitViewingView and exitEditingView respectively.

We'll simply listen for the exitEditingView event and if a user clicked confirm, we'll update our viewmode. If they click cancel we'll take their last value and put that back into the input field so that the next time they enter editmode it has the correct value.

// import the custom event from the FieldBase package
import { events } from 'ak-field-base';

const fieldBase = document.getElementById('myCustomField');
const inputField = document.getElementById('inputField');
const viewModeSpan = document.getElementById('viewModeValue');

// We'll need to keep track of the value of our field
let fieldValue = inputField.value;

// now set up our event listener
fieldBase.addEventListener(events.exitEditingView, (e) => {
  // we can check if the change was caused by hitting cancel or not
  if (e.detail.cancelButtonPressed) {
    // we'll reset the value to the last one before the cancel
    inputField.value = fieldValue;
  } else {
    // we'll update our state and reflect it into the viewmode
    fieldValue = inputField.value;
    viewModeSpan.innerHTML = fieldValue;
  }
})

Styling content

You'll almost definitely want to apply some styles to your views so that they blend in with the Atlassian Design Guidelines theme.

In our example above, you would want to:

  • Remove default focus styles from the input
  • Remove borders and background-color from the input
  • Reflect the input's focus state onto fieldBase (so that we get the correct focus styles in editmode)

To fix the styles we can either set them through javascript/regular css or just use inline styles.

<ak-field-base label="My awesome field" id="myCustomField">
  <div slot="viewmode">
    <span id="viewModeValue">Your text here</span>
  </div>
  <div slot="editmode">
    <input type="text" id="inputField" value="Your text here" style="background: transparent; border: 0; outline: 0; width: 100%;" />
  </div>
</ak-field-base>
inputField.style.background = 'transparent';
inputField.style.border = '0';
inputField.style.outline = 'none';
inputField.style.width = '100%';

To fix the focus styling we can set up event listeners on the input that can set the focused prop on FieldBase.

inputField.addEventListener('focus', () => {
  fieldBase.focused = true;
});
inputField.addEventListener('blur', () => {
  fieldBase.focused = false;
});

Validation

Performing validation is as easy listening for the exitEditingView event and responding appropriately.

If the validation can be performed client-side, simply check the value, if it is invalid cancel the event and set the invalid prop on fieldBase.

fieldBase.addEventListener(events.exitEditingView, (e) => {
  if (!e.detail.cancelButtonPressed) {
    if (inputField.value.length % 2 !== 0) {
      // error! the field only accepts strings that have an even number of characters!
      e.preventDefault();
      fieldBase.invalid = true;
    }
  }
});

To perform async validation it is recommended that you use the waiting prop whilst you wait.

fieldBase.addEventListener(events.exitEditingView, (e) => {
  if (!e.detail.cancelButtonPressed) {
    // we'll cancel the event so that we don't go to viewmode yet
    e.preventDefault();
    fieldBase.waiting = true;
    // now we'll call some long running validation function
    validateValueOnServer(inputField.value).then(isValid => {
      if (isValid) {
        // the value was valid, remove the waiting, editing and invalid props
        fieldBase.waiting = false;
        fieldBase.editing = false;
        fieldBase.invalid = false;
        // and update our state
        fieldValue = inputField.value;
      } else {
        // the value wasn't valid, we'll mark fieldBase as invalid and let the user handle that
        fieldBase.waiting = false;
        fieldBase.invalid = true;
      }
    });
  }
})

FieldBase

Kind: global class
Emits: exitViewingView, exitEditingView

new FieldBase()

Create instances of the component programmatically, or using markup.

HTML Example

<ak-field-base label="Email" />

JS Example

import FieldBase from 'ak-field-base';

const field = new FieldBase();
field.label = 'Email';
document.body.appendChild(field);

fieldBase.label : string

The label to be rendered above the form field.

This prop is still required, even if the hideLabel prop is set as the label is also used to make the field accessible for screen readers.

Kind: instance property of FieldBase

fieldBase.editing : boolean

Whether the editing mode or viewing mode should be shown.

Defaults to false.

Kind: instance property of FieldBase
HTML Example

<ak-field-base editing></ak-field-base>

JS Example

field.editing = true;

fieldBase.focused : boolean

Whether the field should show it's focus ring.

This would usually be controlled by a component extending FieldBase and setting this when needed.

Defaults to false.

Kind: instance property of FieldBase
HTML Example

<ak-field-base focused></ak-field-base>

JS Example

field.focused = true;

fieldBase.hideLabel : boolean

Whether the field should show a label above it.

If set to true no label will be shown and no space will be reserved for it.

Note: You must still provide a label for the component regardless of this prop. The label is also used to make the field accessible to screen readers.

Defaults to false.

Kind: instance property of FieldBase
HTML Example

<ak-field-base label="First Name" hideLabel></ak-field-base>

JS Example

field.label = 'First Name';
field.hideLabel = true;

fieldBase.waiting : boolean

Whether or not to display a loading spinner next to the field.

This is usually used when you need to do some sort of async validation. Note that whilst the editing spinner is visible a user will not be able to click the confirm or cancel buttons from edit mode.

The spinner is only shown when the editing prop is true and will be ignored otherwise.

Kind: instance property of FieldBase
HTML Example

<ak-field-base editing waiting></ak-field-base>

JS Example

field.editing = true;
field.waiting = true;

fieldBase.invalid : boolean

Whether or not a field should show a validation error.

This is shown to the user through a red border currently but will also include error messages in a future release.

This prop is ignored if editing is not set to true.

Kind: instance property of FieldBase
HTML Example

<ak-field-base editing invalid></ak-field-base>

JS Example

field.invalid = true;

"exitViewingView"

This event gets emitted when a field is about to switch away from it's viewmode view.

You might choose to use this event to update your editmode content to be in sync with your viewmode, fetch data for your editmode or even cancel the event to prevent the change completely.

Kind: event emitted by FieldBase
JS Example

import { events } from 'ak-field-base';

field.addEventListener(events.exitViewingView, (e) => {
  // perform your tasks here
  // e.preventDefault(); will prevent the switch
});

"exitEditingView"

This event gets emitted when a field is about to switch away from it's editmode view.

Here you could choose to update your viewmode content to match the users input or reset the value shown in the editmode if the user hit cancel for example.

You might also choose to perform validation of the users value, this might involve cancelling the event to prevent the switch.

You can check if the user clicked the cancel button through the e.detail.cancelButtonPressed value.

Kind: event emitted by FieldBase
JS Example

import { events } from 'ak-field-base';

field.addEventListener(events.exitEditingView, (e) => {
  if (e.detail.cancelButtonPressed) {
    // the user hit cancel
  } else {
   // the user hit confirm: perform validation, update view mode, etc
   // e.preventDefault(); will cancel the switch and keep us in editmode
  }
});

Support and feedback

We're here to help!

Let us know what you think of our components and docs, your feedback is really important for us.

Community support

Ask a question in our forum.

Check if someone has already asked the same question before.

Create a support ticket

Are you in trouble? Let us know!