BalanceReckon Design System
Foundations

Utilities

Build a great experience even faster with these useful tools and helpers.

import { formatCurrency, forwardRefWithAs, hexToRgb, plural, sentenceCase, titleCase, makeId, useId, makeIdFactory, useClickOutside, getContrastText, useKeyPress, useScrollLock, wrapHandlers, simpleHash, flattenChildren, flattenElements, useForkedRef, useDefaultInteractiveStyles, usePrevious, assert, isDefined, typedKeys, typedEntries, ternary, truncateText, os } from '@balance-web/utils';

Build a great experience even faster with these useful tools and helpers. Import hooks and functions from the utils package:

import { useForkedRef, hexToRgb, useId } from '@balance-web/utils';

Ref management

useForkedRef

Passes or assigns a value to multiple refs (typically a DOM node). Useful for dealing with components that need an explicit ref for DOM calculations but also forwards refs assigned by an app.

function Component(props, consumerRef) {
  let internalRef = useRef();
  let ref = useForkedRef(internalRef, consumerRef);

  return <div ref={ref} {...props} />;
}

forwardRefWithAs

React.forwardRef is re-exported from @balance-web/utils as forwardRefWithAs with different type definitions to work with components that have an as prop. It accepts two type arguments, DefaultElementType and Props.

import { forwardRefWithAs } from '@balance-web/utils';

type Props = { color: string } & HTMLAttributes<HTMLButtonElement>;

let Button = forwardRefWithAs<'button', Props>(
  ({ color, as: Tag = 'button', ...props }, ref) => {
    return <Tag css={{ color }} ref={ref} {...props} />;
  }
);

ID helpers

useId

Autogenerate IDs to facilitate WAI-ARIA and server rendering.

A string can be supplied as an argument to be useId in lieu of the auto-generated ID. This is handy for accepting user-provided prop IDs that need to be deterministic.

function Component(props: { id?: string }) {
  // Pass in a user-supplied ID that will be used conditionally if provided
  const id = useId(props.id);

  return (
    <>
      <label htmlFor={id}>Label</label>
      <input id={id} />
    </>
  );
}

makeId

Use the makeId helper to prefix an existing ID for compound components.

function Component(props: { id?: string }) {
  const id = useId(props.id);
  const descriptionId = makeId('description', id);
  const inputId = makeId('input', id);
  const labelId = makeId('label', id);

  return (
    <>
      <label id={labelId} htmlFor={inputId}>
        Label
      </label>
      <input id={inputId} aria-describedby={descriptionId} />
      <div id={descriptionId}>Description</div>
    </>
  );
}

makeIdFactory

Use the makeIdFactory helper to create a factory function that generates IDs with a specific structure.

By creating a factory, you also communicate to other developers the intended critical components.

import { makeIdFactory } from '@balance-web/utils';
import { getTestIdFromDataAttributes } from '@balance-web/core';

const MyComponentTestIdFactory = makeIdFactory('my-component', [
  'label',
  'input',
]);

function MyInputComponent<T extends { id: string }>(
  props: PropsWithDataAttribute<{ id?: string; items: T[] }>
) {
  const id = useId(props.id);
  const testids = MyComponentTestIdFactory.make(
    getTestIdFromDataAttributes(props.data)
  );

  return (
    <div data-testid={testids.base} id={id}>
      {props.items.map((item, index) => (
        <div key={index}>
          <label id={testids.label(item.id)} htmlFor={testids.input(item.id)}>
            {item.label}
          </label>
          <input id={testids.input(item.id)} />
        </div>
      ))}
    </div>
  );
}

Color management

hexToRgb

Use the hexToRgb helper for converting hex strings to rgb strings. Pass an optional second argument for opacity.

Loading demo…

getContrastText

Get the appropriate contrast text color (#000, or #fff) for a given background color.

Loading demo…

Event handling

useKeyPress

The useKeyPress hook makes it easy to detect when the user is pressing a specific key on their keyboard. It also provides ways to hook into the up/down handlers, when to bind the handlers, and which element to bind them to.

Loading demo…

useClickOutside

Loading demo…

wrapHandlers

Wraps a lib-defined event handler and a user-defined event handler, returning a single handler that allows a user to prevent lib-defined handlers from firing.

function Component({ onChange }) {
  const handleChange = wrapHandlers(onChange, (event) => {
    // internal handling
  });

  return <input onChange={handleChange} />;
}

Miscellaneous

useScrollLock

Prevent scroll on the <body /> for modal components.

Loading demo…

useMediaQuery

useMediaQuery is not part of this package — it lives in media-query and is covered by theme's Breakpoints section, since it's typically used alongside theme breakpoints.

Formatting

formatCurrency

Formats a number as AUD currency using Intl.NumberFormat under the hood. indicator controls the $/AUD/no prefix, precision overrides the default 2 fraction digits.

Loading demo…

String helpers

plural(n, singular, plural, includeCount?) picks the right grammatical form for a count; sentenceCase/titleCase capitalise a string; truncateText(text, maxLength?) truncates with a trailing ….

Loading demo…

Working with React children

flattenElements/flattenChildren flatten children through fragments (unlike React.Children.toArray, conditionals and fragments don't break positional keys) — flattenElements additionally filters out anything that isn't a valid element, which is useful when you only care about renderable children and want to ignore stray text/null/false.

Other exports

  • os — 'mac' or 'windows', detected once from navigator.platform. Used internally by keyboard-shortcuts to pick modifier-key symbols.
  • useDefaultInteractiveStyles — the hover/active background styles shared by clickable-but-not-a-button elements across the design system.
  • usePrevious(value, defaultValue) — returns the previous render's value.
  • simpleHash — a small, fast, insecure string hash; do not use it for anything security-sensitive.
  • ternary(condition, ifTruthy, ifFalsy) — a functional if/else, useful inside a JSX expression where a plain ternary reads awkwardly.
  • assert, isDefined, typedKeys, typedEntries — re-exported from emery, a small TypeScript-ergonomics library.

On this page