Forge LTS (12) to Forge New (13+)

✨ Read our Release Notes to be the first to hear about the latest and greatest! ✨

Starting with Forge 13.0.0, Forge has started deleting deprecated components, colors and props. These changes are much riskier than any changes Forge has made since version 3.0.0, so Forge is now Releasing Forge LTS (version 12) and Forge New (version 13+) in parallel. See the Forge Versions Guide for more details.

Many of the documented breaking changes in this section were possible to address in Forge 12, but are now required in Forge New.

Migration Scripts

Forge is piloting using migration scripts to ease the burden of upgrading Forge. These scripts do not cover all use-cases, but may be a helpful resource in conjunction with Typescript and the rest of this documentation. If these scripts prove useful, then let the Forge team know!

To use, run:

npx @athena/forge-codemod@latest

Components

Component Consolidation: Menu

Menu was refactored along with SegmentedButton, removing the MenuTrigger component. Instead, use a Button for the trigger prop. The Button will automatically re-style to use the segmented variant.

Component Consolidation: SegmentedButton

SegmentedButton is a generic component, where the generic parameter affects the type of the value and onChange props. If behavior="radio", then valueand the event.target.value parameter passed to onChange can be strings. Otherwise they are string[].

Key SegmentedButton API/Feature notes: Behavior: the behavior prop accepts one of the following values: button, checkbox, or radio. The value assigned determines the interaction modality of the component as well as ARIA roles i.e., how it "behaves". Former instances of CheckboxButton or RadioButton should be reimplemented as SegmentedButtons with "checkbox" and "radio" behavior values, respectively.

Children: as opposed to the consolidated components which supported props like buttons e.g., ComboButton, whereby a consumer could supply a list of JSX Elements for the component to render, SegmentedButton only supports rendering Button or Menu components supplied as children (a Button can be wrapped in a Tooltip). Additionally, if the SegmentedButton's behavior is not defined as button then all child Button components must have defined value props; and, Menu child components are only supported in the context of a SegmentedButton with button behavior.

Alignment: the alignment prop accepts one of the following values: connected, separated, or stacked and determines how how SegmentedButton's children components are positioned relative to each other.

Split-Primary: To get split-primary styling, there are no specific props to set other than alignment="connected" behavior="button", which are the defaults. Instead, split-primary styling is automatically applied when the first child is a <Button> and the second child is a <Menu trigger={<Button />}. If the menu trigger Button has any text, then split primary styling is not applied.

Component Consolidation: List

The List component is designed to render collections i.e., sets of ListItems, with versatility, accommodating both plain and interactive lists through the "variant" prop. When "variant" is set to "selection", the component allows for the selection of list items. For non-interactive lists. when "variant" is set to "simple", List servers to display items without the capability of selection.

What's changed compared to legacy List/SelectionList

variant: Specifies the type of list to render, affecting its functionality and appearance. If assigned the value of “simple”, List will render a static collection of list items with no interactive capability. If assigned the value of “selection”, List will render a set of interactive items, each of which includes a checkbox.

layout: Controls the layout between a List’s items. By default, a List has a “medium” value. If assigned to “compact” the padding between items is reduced by 50% rendering a condensed presentation.

children: To promote composition, List no longer accepts an “options” prop and simply renders the Children it is supplied. List should exclusively render sets of ListItems.

ListItem (component):

  • uniqueKey: Is a required prop. The string-value assigned must be a unique identifier to each ListItem within a List as it is used internally by the List component to differentiate items and manage selections.
  • children: A ListItem flexibly renders its provided content. A ListItem enforces a basic layout for the content it is supplied. Forge recommends a ListItem’s children be limited to simple text or a basic combination of an Icon, or Avatar, component followed by simple text.

value: Reported via List’s onChange handler, the List component’s “value” is an array of strings which correspond to each selected item’s “uniqueKey”

showDividers: Previously “dividers”, if set to true, List will render dividers between each option

@athena/forge-icons color

Recoloring an icon imported from @athena/forge-icons in Typescript has become simpler. The variant prop has been removed, and semanticColor now accepts strongly-typed strings instead of objects. This eliminates the need to make each @athena/forge-icon component generic, making it simpler to recolor an icon across different semantic categories.

Component Consolidation: Modal

The Modal component is the functional consolidation of legacy Modal and Lightbox components. The legacy components are still available in the Forge LTS version, but have been removed in the Forge New release.

What's changed compared to legacy Modal/Lightbox

contentStyle

  • Default: "simple"
  • Modal content can have three styles: "Simple", "Complex", and "Complex with Left Panel". The left panel from the legacy Lightbox component is only allowed when the content style is set to "complex".
  • Both "simple" and "complex" content styles also have preset width, height, and alignment to make it look like a legacy Modal or Lightbox.

autoFocusTarget

  • Default: "none"
  • Options for where to set focus to automatically on Modal open, options including close icon, header buttons, primary button, secondary buttons or none. The choice of option depends on the Modal's usage.

footerSecondaryButtons and footerTertiaryButtons

  • Modal now accepts "footerSecondaryButtons" and "footerTertiaryButtons" as an array of buttons, allowing multiple secondary and tertiary buttons.

includeButtonRow

  • By default, "includeButtonRow" is set to true, and a primary button will be displayed in the footer section.

Component Consolidation: Select

The Select component is the functional consolidation of MultiSelect, SingleSelect, Typeahead, and the formerly titled “Select” component. The legacy components remain available in Forge LTS, but have been removed in Forge New release.

New and Notable

allowUserCreatedOptions

  • Default: False
  • This feature/prop allows users to enter a value that is not already listed among the predefined options. If enabled, users can create and select the new option.

isValidNewOption

  • This function determines if a user-entered value can be accepted as a new option.
  • By default, the implementation will simply validate against duplication but can be overwritten and customized for the user’s use case. For example, additional constraints like character limits, or types, could be applied to the validation of a new option.

size

  • Default: “Large”
  • Select can be rendered in three distinct sizes “Small”, “Medium” and “Large”. Small and medium are the equivalents of “super-compact” and “compact” layouts, respectively.

isMulti

  • Default: False
  • When enabled, allows a user to select multiple values

options

  • For the purpose of Tag styling, the consolidated component supports more complex option types for Select’s whose “isMulti” property is enabled. The style properties “color” and “textVariant”, when supplied, will be applied to those options when selected.
  • If supplied to an instance of Select whose “isMulti” property is false, those values will simply go unprocessed (as plain text strings render for selected options in such instances, rather than Tags).

Icon

  • Default: Undefined
  • Select now allows users to provide an Icon of their choosing to be displayed within Select’s input if desired.

Component Consolidation: Tag

The Tag component was added in Forge 12.4.0. Tag is the functional consolidation of RemovableTag and StatusTag. The legacy components remain available in Forge 12, but have been removed in Forge New. Forge encourages migration to the Tag component and strictly discourages new usage of those legacy components.

What's new with Tag
  • isRemovable (required)
    • Accepts a boolean value. When assigned to true, the component will be removable; it will render a Close icon and execute the callback function supplied to its onRemove prop. Otherwise, the Tag will be purely presentational.
  • textStyle (optional)
    • Accepts a string value of either "default" or "impact". When the prop is assigned the value of "impact", specific styling will be applied to the Tag's text—the text will be capitalized, bold, and subtle padding will be applied between the text's characters. Otherwise, the Tag receives no special treatment.
What's Changed compared to Status/Removable Tag
  • color
    • Now accepts the following string values: "alert-new", "alert-positive", "alert-attention", "alert-critical", "blue", "yellow", "purple", "orchid", "pistachio", "default-gray".
  • size
    • Now accepts an additional setting, "large".
  • secondary and background
    • No longer supported props.

Table

The Table component is difficult to work with, and relies on an outdated third party dependency. Realizing that the only way to fix the Table component was to reimplement it, Collector has implemented the DataTable component. It is available in Forge as of Forge 12.2.0.

The Table component has been deleted in Forge 13.0.0.

Icon

As of Forge 4.0.0, The Icon component has been deprecated in favor of icons imported from @athena/forge-icons, documented in Guidelines/Icons. This not only applies to direct uses of the Icon component, but also to Forge components that reference an Icon by name via props:

  • Button
  • Input
  • Typeahead

Each of these components have icon and iconSet props. Currently, icon accepts either a string or a ForgeIconComponent, while iconSet exists to allow custom icons not present in the Icon component. A ForgeIconComponent represents any component imported from @athena/forge-icons. In the future, icon will no longer accept a string, and iconSet will be deleted. If a custom icon is desired that isn't present in @athena/forge-icons, either contribute that icon to Forge, or use withForgeIconProps to help conform your custom icon component to be compatible with Forge.

Recoloring Icons If an icon is not interactive and does not require different styles based on hover, focus, or active states, using JavaScript props is the simplest method for changing its color. Icons come with preset color themes:

  • 'default': For non-interactive icons on light backgrounds
  • 'interactive': For interactive icons on light backgrounds
  • 'disabled': For disabled icons on light backgrounds
  • 'inverted': For icons on dark backgrounds

Any of these 4 variants can be chosen using the 'semanticColor' prop:

<AddAppointmentLarge semanticColor="disabled" />

Alternatively, you can set the color using a semantic color (a single string representing a category and name), like this:

<AddAppointmentLarge semanticColor="alert-attention" />

Props

There are multiple instances of a component having two props that do the same thing. In addition to the icon and iconSet props discussed above, the following props will be deleted as they already have fully-functioning replacements:

componentpropreplacement
InputinputRefref
Multiselectgroup.isDisabledgroup.disabled
Multiselectgroup.textgroup.label
RadioinputRefref
@athena/forge-iconsdisabledvariant="disabled"
@athena/forge-iconsinteractivevariant="interactive"

Colors

There are a number of secondary colors that are going to be removed from Forge. Unlike Typescript changes, a missed map-get will not trigger a build failure. If your application is reliant on a color or shade that is going to be deleted, then the map-get will silently fail with no color returned. The colors being renamed are:

deprecated namereplacement
bluejungle
tealjungle
peacockjungle
greenpistachio
orangecoral
rubyorchid

If peacock-100 is being used to indicate a status or alert meaning new replace with map-get(forge-abstracts.$color-alert, new), if peacock is being used as secondary design color, we recommend using jungle-100 as a replacement

Secondary color values are also being consolidated from having 5 shades to 4

valuerecommended replacement
*-secondary-10unchanged
*-secondary-25*-secondary-10 or *-secondary-40
*-secondary-50*-secondary-40
*-secondary-75*-secondary-70
*-secondary-100unchanged

If your app is doing data visualization, then 4 shades will likely not be enough. The dataviz color palette can be used instead, as it has shades for every 10% increment.

React Version

Forge started using react v18.2.0 as a devDependency as of Forge v8.0.1. While Forge currently supports React versions greater than 16.9.0, there is a risk that Forge may introduce a change that relies on a React 18 feature.

To reduce scope creep, it's recommended to upgrade Forge and React independency.

When upgrading React, it's important to keep in mind that the following dependencies should be upgraded in parallel:

  • @types/react
  • @types/react-dom
  • react
  • react-dom

If your app uses Enzyme, then you likely have one of the following libraries, based on your version of React:

  • enzyme-adapter-react-16
  • @wojtekmaj/enzyme-adapter-react-17

There is no good React 18 enzyme adapter, as the React community has moved away from enzyme in favor of testing-library. Thus, in order to upgrade to React 18, you must replace enzyme with testing-library.

Tests

Testing library has replaced enzyme in the react community based on the following guiding principle:

The more your tests resemble the way your software is used, the more confidence they can give you.

Enzyme encourages tests to be written against implementation details. For example, it encourages testing that the prop of a child component is a certain value, and it encourages snapshot testing. Implementation details can change dramatically, but leave the resulting rendered content relatively unchanged. Meanwhile, developers may not consider aria attributes, which are essential to non-sighted users. Testing library addresses this by encouraging querying DOM nodes by Role and text over implementation details such as data-testid or class.

Converting tests from enzyme to testing-library is generally not complex, but is difficult to automate. However, your tests will generally be better as a result. It's also essential when upgrading to React 18, as enzyme is not supported anymore.

Forge 4 to 12

Forge 3 was the latest major version of Forge from July 2020 until February 2023. During this time, great effort was made to keep Forge as stable as possible, making additive changes and bugfixes only. However, starting in version 3.14.2 in January 2022, Forge had started to convert its components to be implemented in Typescript. While we kept the runtime API backwards-compatible, it was impossible to make the typescript types for props more accurate without causing builds to fail that relied on the outdated types. These hidden build-breaking changes decreased confidence that a minor version bump was truly backwards compatible. It wasn’t practical for Forge to make no releases for an additional year, so the decision was made to release a new major version any time the typescript types for a component are made more restrictive, and to document these breaking changes in the changelog. Thus, after two and a half years of Forge 3, Forge has released a new major version of Forge on average every 2 months.

While the number of changes from Forge 3 to 12 may seem large, we’ve generally tried to keep the breaking changes minor, and detectable through Typescript. The release of Forge 12.0.0 has ended the Typescript conversion work, and Forge 12 has been promoted to be Forge's first Long Term Support (LTS) version. Forge 12 will continue to receive new non-breaking features and bugfixes until mid-year 2025. In the meantime, Forge 13 and beyond will continue to be released in parallel as Forge New. At that point, the latest version of Forge New will be promoted to be the next Forge LTS, and Forge 12 will no longer receive updates. See the Forge Versions Guide for more details.

Dependency changes

One common problem when upgrading any node library, is that you often can’t upgrade a single dependency at a time. A library and its peer dependencies often need to be upgraded in tandem. Where possible, Forge tries to document this in the versions of its peer dependencies. In particular, the following libraries should be upgraded to their latest versions in conjunction with @athena/forge, if applicable:

  • @athena/clinicals-athenanet-proxy
  • @athena/forge-icons
  • @athena/forge-shared
  • @athena/nimbus-app-launcher-sdk
  • @athena/react-scripts
  • typescript

If upgrading to the latest version of any of these libraries proves problematic, the minimum supported version of some libraries such as typescript or @athena/react-scripts are documented in @athena/forge/package.json. Please refer to those versions to find a compromise between what your app and @athena/forge supports.

Breaking Changes

Any known breaking changes are documented in Forge’s changelog. Please refer to that page to determine what has broken since you last upgraded @athena/forge. Most of the changes have been making typescript types more accurate, and thus restrictive. Your build should fail on any of these changes, but it should also be straightforward to update. This is often as simple as removing an unnecessary type assertion, or changing the name of a type.

These changes are not documented in full here because the list of breaking changes is expected to grow until the typescript conversion is 100% complete. Also, since most of the breaking changes affect typescript types only, your tooling will be a more real-time feedback loop than any written documentation. This document will be updated with consolidated breaking changes once the first LTS version is released. In the meantime, below are the known breaking changes that affect runtime code. These are called out specifically in case your project does not use Typescript, or contains a large number of type assertions.

12.0.0 (2024-02-12)

This version of Forge contains MultiField's conversion to TypeScript and with it some implementation details are worth noting for ease of upgrading.

MultiField is now a generic Typescript component that effectively operates within two modalities: "Strict Mode" and "Flexible Mode"

Strict Mode

  • MultiField's Typescript definition allows up to 5 generic type parameters. These positional types correspond to the item at the respective index of the fields array
  • For Example, <MultiField<SelectProps, InputProps, CheckBoxProps> fields={fields} ... /> would enforce typing as follows: fields[0] would be subject to SelectProps; fields[1] would be subject to InputProps; and fields[2] would be subject to CheckBoxProps, and so on for up to five possible items. Six and more fields are still supported, but they will have weaker Typescript checks.

Flexible Mode

  • Simply do not provide any prop signatures and strict typing will not be explicitly enforced. However, even in the absence of positional arguments, MultiField will infer the type of a field from the value supplied to its inputAs prop. So, even in Flexible Mode, type safety will still be provided where possible.

In sum, we do not expect migration to be overly onerous. If the props provided to a field are consistent with the props accepted by that field’s inputAs prop, your application should not complain. However, in instances of invalid props, refactoring will be required. Forge does recommend Strict Mode usage of MultiField by supplying positional prop type arguments. However, if that is not feasible, users can still enjoy prop safety so long as MultiField can infer types from a given field’s inputAs prop.

11.0.0 (2023-12-14)

FormField was converted to Typescript, providing strict type checks for its props. This is implemented as a generic Typescript component, where the generic type represents the props that are supported by the inputAs component. FormField is able to infer this type from the inputAs prop most of the time, but it's often better to provide the type explicitly.

For example, <FormField inputAs={DateInput} onChange={(e) => setDate(e.target.value)} ... /> should work, but there may be an incomprehensible Typescript error related to the onChange prop. This will work much better if you provide the DateInputProps type: <FormField<DateInputProps> inputAs={DateInput} onChange={(e) => setDate(e.target.value)} ... />. The former example fails because it needs to use the type of onChange in conjunction with inputAs in order to infer a mutually-compatible type. This inference can't be done because no types have been provided to onChange. The latter example works because the type for onChange is already known, and is simply applied to the inline function definition.

10.0.0 (2023-11-29)

  • Callback functions in Tree supply event before the affected node ID(s):
    • onNodeSelect
    • onNodeToggle
    • data[number].onSelect
    • data[number].onToggle

4.1.0 (2023-03-01)

  • NumericRangeInput and DateRangeInput runtime API refactored UXDS-7470

node-sass deprecation

Forge no longer supports node-sass as of v3.18.0, as it's been deprecated for years. Use the sass library instead, collegially referred to as Dart Sass.

While technically a Forge v3 change, version 3.18.0 was sufficiently late in Forge 3's lifetime that many projects may not have upgraded to it before upgrading major versions.

To update your app, it's recommended to make the following changes to your package.json:

libraryaction
node-sassreplace with sass
sass-loaderupgrade to latest

That should be all that is necessary, as Dart Sass syntax is generally backwards-compatible with node-sass, but it's worth mentioning changes in how sass files are imported.

A typical use-case for using Forge's scss files would be:

@import "~@athena/forge/sass/forge-abstracts";
.my-class {
font-weight: map-get($font-weights, bold);
}

There are a few problems with this pattern:

  • node-sass used ~ to signify that the import is from a third party library. Dart sass does not have this requirement. While the tilde is still supported, its use is discouraged.
  • @import pollutes the global namespace with all tokens that it imports. This can make it difficult to trace where a variable is defined, complicating the sass dependency tree.

The preferred way to rewrite the above code with Dart Sass is:

@use "@athena/forge/sass/forge-abstracts";
.my-class {
font-weight: map-get(forge-abstracts.$font-weights, bold);
}

Forge 3

Updating your dependencies

Update Forge version

Update your package.json to the accept the latest version of Forge. We recommend deleting your node_modules before installing forge@3.X.X for the first time.

package.json

"dependencies": {
  "@athena/forge": "^3.0.0"
}

Update React version

The minimum required version of React was increased from react@16.4.1 to react@16.9.0.

Remove forge-types

Forge 3 natively supports TypeScript, which means you can remove your @athena/forge-types dev dependency if your app supports Typescript.

You must remove the forge entry from your project tsconfig.json.

tsconfig.json

"paths": {
  "@athena/forge": ["./node_modules/@athena/forge-types"] // REMOVE THIS LINE
}

(Optional) Add forge-redux-form if your project uses Redux

Note: forge-redux-form components will not be supported in Forge 4.

forge-redux-form is a "bridge" package, meaning it is provided to allow teams to upgrade to Forge 3 without migrating off of Forge's ReduxForm set of components.

We do not recommend using this package for any new projects.

If your project uses the Forge components ReduxForm, ReduxFormField, or ReduxMultiField, consider refactoring to remove them. If not, you will need to add the forge-redux-form dependency.

Forge's set of ReduxForm components has been moved outside the core Forge package, along with the dependencies redux, react-redux, redux-form, and validate.js.

package.json

"dependencies": {
  "@athena/forge-redux-form": "^1.0.0"
}

(Optional) Remove Forge 2 release candidate (RC) components

If your project uses the Forge 2 RC component packages MultiselectAsync, ProgressIndicator, Toast, or ToggleSwitch, you can remove those dependencies.

All of these Forge 2 RC components have been added to the core Forge 3 package, except MultiselectAsync. That component's functionality has been merged with core component Multiselect. See Replace MultiselectAsync (below) for more upgrade information.

package.json

"dependencies": {
  "@athena/forge-multiselect-async": "^1.0.0", // REMOVE THIS LINE
  "@athena/forge-progress-indicator": "^1.0.0", // REMOVE THIS LINE
  "@athena/forge-toast": "^1.0.0", // REMOVE THIS LINE
  "@athena/forge-toggle-switch": "^1.0.0", // REMOVE THIS LINE
}

You should also remove the CSS files and update the import paths for those 4 components.

App.jsx

/* EXAMPLE UPDATES FOR TOGGLESWITCH */
import "@athena/forge-toggle-switch/static/css/extension.css"; // REMOVE THIS LINE
import ToggleSwitch from "@athena/forge-toggle-switch/build/components/toggle-switch/toggle-switch"; // REMOVE THIS LINE
import ToggleSwitch from "@athena/forge/ToggleSwitch"; // ADD THIS LINE

(Optional) Request updates to Forge 2 Community components

Community components are packages that are not maintained by the core Forge team, which means that we cannot update the Forge dependency for these components.

Contact the maintainers of these packages and ask that they update the dependencies to accept Forge version 3 or create a new Forge 3 version of their package.

See the Forge 2 Community page for the list of community components.

(Optional) Add other dependencies

moment removal

Forge no longer ships with the `moment`` package.

If your project uses the `moment`` package, install it as a direct dependency.

Consider using the smaller date-fns package instead if you only use Moment sparingly.

react-day-picker removal

Forge has replaced our dependency on react-day-picker with the more popular react-datepicker.

If your project directly uses react-day-picker, add this as a dependency directly or refactor to use react-datepicker instead.

Major version upgrades

Forge dependency versions for these packages have been incremented at least 1 major version:

  • dom-helpers
  • react-overlays
  • react-select
  • react-transition-group

If your project has a direct dependency on any of these, update your dependency versions to match Forge’s versions for the smallest possible package size. If you are using features of these packages not mentioned in Forge’s API, we recommend testing.

packageversion change
dom-helpers3.4.0 → ^5.1.0
react-overlays0.8.3 → ^1.2.0
react-select2.4.2 → ^3.0.4
react-transition-group2.7.1 → ^4.3.0

Handling breaking changes

Core

All import paths have changed

Thanks to our new build process, our published package now has a flatter directory structure.

  • Update your Forge CSS import to "@athena/forge/dist/forge.css"
    • Please note: If your css file is under a different directory, replace with @import "~@athena/forge/dist/forge.css"; (no forward slash after the ~)
  • The forge.js file and font files are now in the dist directory (e.g., @athena/forge/dist/forge.js)
  • Global sass can now be found in the sass directory in the root of the package. All component-specific sass can be found within component directories.
  • All utilities formerly in our js directory have now moved to the utils directory.

Use single component packages

If you are not using the Nimbus CDN, you can update any single component imports to pull directly from the Forge root directory (example below):

App.jsx

// Use single component imports for optimized package sizes:
import Button from "@athena/forge/Button";
import FormField from "@athena/forge/FormField";
// These style imports have not changed, but they result in a larger package size
import { Button, FormField } from "@athena/forge";

TypeScript is now natively supported

If you use TypeScript, you can now remove your @athena/forge-types dependency.

Remember to also remove this entry from your project tsconfig.json file:

"paths" : {
  "@athena/forge" : [ "./node_modules/@athena/forge-types" ]
}

Build process refactors - local reinstall and rebuild needed

Forge 3 contains significant refactors to our build process. If you are developing Forge locally and are switching between Forge 2 and Forge 3, you will need to reinstall and rebuild.

Styles

node-sass deprecation

Forge no longer supports node-sass as of v3.18.0, as it's been deprecated for years. Use the sass library instead, collegially referred to as Dart Sass.

To update your app, it's recommended to make the following changes to your package.json:

libraryaction
node-sassreplace with sass
sass-loaderupgrade to latest

That should be all that is necessary, as Dart Sass syntax is generally backwards-compatible with node-sass, but it's worth mentioning changes in how sass files are imported.

A typical use-case for using Forge's scss files would be:

@import "~@athena/forge/sass/forge-abstracts";
.my-class {
font-weight: map-get($font-weights, bold);
}

There are a few problems with this pattern:

  • node-sass used ~ to signify that the import is from a third party library. Dart sass does not have this requirement. While the tilde is still supported, its use is discouraged.
  • @import pollutes the global namespace with all tokens that it imports. This can make it difficult to trace where a variable is defined, complicating the sass dependency tree.

The preferred way to rewrite the above code with Dart Sass is:

@use "@athena/forge/sass/forge-abstracts";
.my-class {
font-weight: map-get(forge-abstracts.$font-weights, bold);
}

Path changes for Forge CSS and Sass

  • If you consume forge.css directly, update your Forge CSS import to "@athena/forge/dist/forge.css"
  • If you compile your own CSS from Sass, update the paths to any used Sass to "~@athena/forge/sass/"

Changes to utilities and primitive values

  • The font size primitive xsmall has changed to 12px (old value was 10px).
  • The spacing constant xlarge, used for margin and padding, has changed to 40px (old value was 48px).
  • The color primitive green-light has been removed.
  • The typography utility class .fe_u_color--attention has been removed for accessibility reasons. The yellow text did not have high enough contrast on most backgrounds.

If you use Forge’s CSS class or Sass utilities, make sure these changes don't negatively affect your styling.

inputWidth prop has been removed

The inputWidth prop, which was deprecated in Forge 2.2.0, has now been removed.

Use a CSS class to set custom input widths instead.

Link style change - :link pseudo-selector

Forge now styles the :link pseudo-selector in our CSS for base <a> (link) styles.

Check that this does not conflict with your styling.

CSS specificity changes (you should run a full visual regression test)

The CSS specificity of the average Forge CSS selector is now much lower.

This is a good thing! This makes it easier for you to write custom CSS that overwrites Forge styles.

However, it is possible that other CSS files (e.g., athenanet.css) now overwrite Forge’s styles.

  • Run a full visual regression test to check if your design is affected.
  • If you find other styles are “leaking” into Forge styles, increase the specificity of your Forge CSS.

V2 Component Deprecations (now removed in Forge 3)

Replace IconButton

The IconButton component has been removed.

The "tertiary" variant of the Button component has been updated to have the same style and functionality as IconButton. See the Button component's guidance for demos and example code.

Replace MultiselectAsync The MultiselectAsync component has been removed. See details above on updating your code to remove it.

Its functionality has been merged into the Multiselect component, which is part of the main Forge package. Use that component instead.

  • To use Multiselect asynchronously:
    • Remove all imports related to '@athena/forge-multiselect-async' and replace with a direct import of Multiselect (@athena/forge/Multiselect) from the main Forge package.
    • Use the initialAsyncOptions prop instead of defaultOptions
      • initialAsyncOptions accepts an array of strings or an array of objects (with keys value, text and disabled).
      • This is different from defaultOptions from the MultiselectAsync API, which also accepted an enum mapping values to booleans specifying whether or not they were preselected.
    • Use the loadAsyncOptions prop instead of loadOptions.
  • To use Multiselect synchronously:
    • You can use options as you normally would. Do not use the initialAsyncOptions or loadAsyncOptions props.
  • If you were using react-select props, classes, or functionality not listed in the Forge Multiselect API:
    • We've upgraded react-select from version 2 to 3, so read react-select's upgrade guide and retest your functionality and styling.
    • Check our list of swallowed react-select props at the bottom of the props table to make sure your prop can still be used.
  • Other changes:
    • inputWidth (deprecated in Forge 2) has now been removed. Instead, we recommend using className to add a custom class which you can use to style the width with CSS.
    • id is no longer required. You can use it to add an id to the root level of the component.
    • inputId is a new prop that can be used when you want to add an id attribute to the underlying <input> element.
    • loadingMessage and noOptionsMessage props can now take a function in addition to a string.
    • There are many common react event handler functions and react-select that are no longer listed in Forge's Multiselect API, but that doesn't mean they can't be used.
      • Check the bottom of the props table (the ...rest row) to see what props we are swallowing. Check React Component and react-select documentation to learn about passthrough props that can be used.

Component API Changes

Changes to the id prop

Components no longer generate their own unique id props. Teams must provide their own values for components that require the id prop.

This change was made to improve accessibility and reduce our dependence on the third-party lodash library (which was used to generated unique ids).

id prop is now required by:

  • Checkbox
    • Also, id is sent to the underlying <input> instead of the root <span>
  • FormField
    • id is also used to populate the name attribute if it's not provided
  • MultiField
    • id is required for each field object passed to the fields prop
    • name keys for each field object in the fields prop will be populated using the value of the id key, if name is not provided
  • RadioGroup
    • id is also used to populate the name attribute if it's not provided. Note that these props will be generated from the id prop of RadioGroup if the options prop is set to an array (instead of leaving the options prop blank and providing child Radio components).
    • id also required for the supporting component Radio. If you are specifying options using the options prop, the RadioGroup id is used to generate unique Radio id values with the format "[id]-option-[number]".
  • ToggleSwitch
    • Description objects now require id
  • Tooltip

DateInput - new underlying 3rd party library, API changes

DateInput is now built on react-datepicker.

  • These DateInput props are still in use:
    • className
    • defaultValue (uncontrolled) - now only takes Javascript Dates
    • disabled
    • error
    • hideRequiredStyles
    • id
    • onBlur
    • onChange
    • placeholder
    • required
    • value (controlled) - now only takes Javascript Date
  • These DateInput props have been replaced:
  • htmlref is replaced by customInputRef
  • disabledDays has been removed. Instead, use one of these methods to disable specific dates:
    • Provide excludeDates an array of Date objects. All other dates are enabled.
    • Provide includeDates an array of Date objects. All other dates are disabled.
    • Provide filterDate a function. This function should accept a Date object - argument and return a bool (true for enabled, false for disabled).
    • Use the minDate and/or maxDate props to set an upper or lower range.
  • All other props from previous versions of DateInput have been removed.
  • Many common props and event handler functions for react and react-datepicker are no longer listed in Forge's DateInput API, but some may still be usable.
    • Check the bottom of the API props table (the ...rest row) to see what props we are swallowing.
    • Check React Component and react-datepicker documentation to learn about - passthrough props that can be used.
  • "tertiary" Buttons are now rendered for the navigation of calendar months instead of IconButtons.

Other component API changes

Banner

  • A "tertiary" Button is now rendered for the close button instead of an IconButton.
  • BannerItem (a supporting component) now passes props to the root <div> element instead of swallowing them.

Button

  • The `"tertiary" variant`` has been restyled to look and act like the IconButton component, which has now been removed.
  • sizing has been renamed size to align with other component APIs. It accepts "tiny", "small", "medium" (default), or "large".
  • Undocumented alert color classes have been removed.

Card

A "tertiary" Button is now rendered for the close button instead of an IconButton.

Form

  • nested now defaults to true.
  • compact has been changed to layout to align with other component APIs. Accepted values are now "medium" (default) and "compact".

FormField

  • inputAs no longer accepts MultiField as a value. Instead, use the MultiField component directly (it now supports side labels and all FormField functionality).
  • compact has been changed to layout to align with other component APIs. Accepted values are now "medium" and "compact". Setting this FormField prop inside a Form will override the Form layout value.
  • onHintTextChange and onErrorChange props have been removed. They were related to internal state changes for DateInput.
  • In FormFieldLayout (a supporting component), compact has been changed to layout to align with other component APIs. Accepted values are now "medium" and "compact".

Lightbox

  • headerText is now a required prop and will be used as a screen reader label for the dialog unless the aria-label prop is provided.
  • A "tertiary" Button is now rendered for the close button instead of an IconButton.

Modal

  • headerText is now a required prop, for accessibility reasons.
  • A "tertiary" Button is now rendered for the close button instead of an IconButton.

MultiField

  • compact has been changed to layout to align with other component APIs. Accepted values are now "medium" and "compact". Setting this MultiField prop inside a Form will override the Form layout value.
  • onHintTextChange and onErrorChange props have been removed from the top level of MultiField. They have also been removed as supported keys of the fields prop. These were related to internal state changes for DateInput.

Multiselect

Multiselect now supports asynchronous retrieval of the dropdown option list. Previously, you needed to use the separate MultiselectAsync component for this.

See Replace MultiselectAsync above for details about changes, including:

  • Multiselect now uses react-select v3 (upgraded from v2).
  • The Async component is rendered at the root instead of Select.
  • Many props have been added, changed, and removed.

Paginator

  • pageInputId is now required if displayMode is set to "withPageJump".

ProgressIndicator

  • The size default value "default" has been renamed "medium". size now accepts "medium" or "small".

ReadOnlyInput

  • The id prop has been removed. You can still pass an id attribute to the root <div> through ...rest.

RemovableTag

  • The default for the size prop has changed from "default" to "medium". Accepted values are now "small" and "medium".

SelectionList

  • id is now passed to the root <fieldset> element.
  • If you are specifying items using the options prop, the SelectionList id (if provided) will be used to generate unique SelectionListItem id values with the format "[id]-[optionValue]". If no id is provided to SelectionList, the option's value key will be used as the id, so provided values must be unique.
  • In the supporting component SelectionListItem, uniqueKey is now used as the id for the included Checkbox component. It's used to generate an id attribute with the format "[uniqueKey]-description" for the item description.

Table

  • The default for the layout prop has changed from "default" to "medium". Accepted values are now "compact" and "medium".

Tabs

  • The Tabs component can now operate in controlled or uncontrolled mode.
    • For controlled mode, use the selectedIndex prop to select which TabPane is shown.
    • For uncontrolled mode, you can use the defaultSelectedIndex to select which TabPane is shown initially.

Toast

A "tertiary" Button is now rendered for the close button instead of an IconButton.

ToggleSwitch

  • The descriptions prop now requires a value for the key id.
  • The default for the size prop has changed from "default" to "medium". Accepted values are now "medium" and "large".
  • ToggleSwitch now passes props to the native <button> element instead of the root <div>.

Forge 2

Forge 2.0.0 branches from version 1.8.0. This guide covers the upgrade process to Forge 2 from previous versions of Forge. Newer version of Forge available

Upgrade Process

  1. Increase Forge to version 2.0.0.
  2. Upgrade React and its dependencies to 16.4.
  3. Fix known breaking changes (listed below).
  4. All core extensions as of August 2018 have been included in Forge 2.0. You should swap these core extensions with the Forge equivalent:
  5. Check out what's new in Forge 2.0.0 (highlights listed below)!
    • New components! New extensions!
    • Accessibility features and guidance
    • New guidance about using the critical/patient safety red color, about designing forms and about interruption design
    • Tree shaking and future-proofing

Using Forge 1.x and 2.0 Together

The Forge team doesn't know of any examples of mixing Forge 1 and 2 in the same application and this is not recommended.

The Hospitals team has done something along these lines using our CSS namespacing strategy between different minor versions of Forge 1. Mainly this involves adding a $base-prefix variable to the theme file and have all forge styles under an `fe_f_all.my_base_prefix`` selector. Theming has been used rarely by teams so far but check out the prototyping environment setup notes or the Forge-App repo for how to set up for theming.

Known Breaking Changes

Forge System Changes

.fe_f_inherits styling is now included in .fe_f_all

  • The .fe_f_inherits class is a type of CSS reset that sets inherited properties like cursor or font-weight to Forge’s consistent baseline. By doing this, .fe_f_inherits keeps Forge styling consistent across athenahealth products.
    • If you've been using .fe_f_inherits: You may now remove the .fe_f_inherits class.
    • If your code does not use .fe_f_inherits: Consider testing styling if you’re setting inheritable properties in your CSS or relying on such rules from your product’s CSS.

The $green-light color variable has been deprecated

  • This light green color is now a part of our secondary color palette. Use map-get($color-secondary, green-100) or $green-100 to access it in code.

Components

Accordion

  • The Accordion component no longer has a padded prop. The Accordion itself will no longer have any padding-related prop. If you want to add padding to an Accordion, add a Layout Utility class.
  • AccordionItem now comes with padding by default and its default font size has been reduced. Some other style tweaks have been made to Accordion as well. The padding can be turned off via the new padded prop.

Card

  • The subheadingText prop has been renamed headingDescriptionText.

Heading

  • The subheading prop has been renamed headingDescription.

Radios

  • Radios without a RadioGroup have a styling change. display is now inline-block to match checkboxes. If you’ve used Radio components without RadioGroup and have added additional styling to them, consider testing.

ForgeIcons / Icon

  • ForgeIcons has been renamed to Icon.

Form

  • Some FormField props have been moved to the Form component. This makes it simpler to keep layout configurations consistent across a form. The props that have moved to Form are:
    • compact
    • labelAlwaysAbove
    • labelWidth
    • nested

FormField

  • Some props have been removed. As mentioned above, you should now set the following props in your Form component and remove them from FormField:
    • compact
    • labelAlwaysAbove
    • labelWidth
    • nested
  • The inputWidth prop no longer accepts the string large. The fe_c-form-field__input–large class has also been removed from the HTML API. Instead, pass a valid CSS width (such as a px or % value) or leave this blank to use the default width.

Loader

  • The DOM structure has changed. We added a new dependency called react-block-ui which has slightly altered the DOM structure.

Modal

  • Modal now has padded prop, which defaults to true. If the content you are putting inside of a Modal should stretch to the edges of the Modal, set padded to false.

Multiselect

  • Multiselect no longer has the props aria-describedby and openMenuOnClick. This is due to open issues in react-select that make these props not work.

Table

  • The tall option for the layout prop has been removed. Table's layout prop now has the options default and compact.

Tabs

  • Tabs default padded prop changed to true. If your Tab components rely on the default padded prop, you will need to update it.
  • The Tabs component no longer has any padding around the wrapper. If the layout you're trying to achieve still requires this padding, add a Layout Utility class.

TextInput

  • TextInput has been replaced by Input. You will need to replace all instances of TextInput with Input.

Typeahead

  • Typeahead has two new props - getSuggestionAnnouncement and suggestionsAnnouncement. If you’re using Typeahead as a controlled component, use suggestionsAnnouncement to provide a screen reader with text to announce about available suggestions. If you want to use Typeahead uncontrolled, you can overwrite the default screen reader text generation with getSuggestionAnnouncement.

New Things - Highlights

Components

New Components

All Forge 1.x Core Extensions are now a part of Forge 2.0!

These include:

We've also made some new components. Brand new components include:

Core Extensions

MultiselectAsync - This variation on Multiselect includes a loading state and allows you to load options asynchronously using a Promise. Since merged into Multiselect in Forge 3. Toast - Great for all of your non-critical notification needs and screen reader accessible. ToggleSwitch - This selector lets users choose between 2 opposing states, such as "on" and "off", with instant changes. Fully accessible!

DateInput

If a valid range of dates does not include the current year the DateInput calendar will open to the January 1st of the closest valid year.

Accessibility

Focus Styles

Our focus styles now meet WCAG 2.0 AA contrast standards.

Attention color

We modified our attention color to improve contrast.

Gray Palette

We modified our gray color palette to show up better on low contrast displays like projectors.

Miscellaneous Improvements

We have improved the accessibility of almost all components!

Guidance

Use of Red - Critical vs. Patient Safety

Red was previously reserved for patient safety. Now Forge's red color can be used to indicate anything critical in nature.

Form Design

Have a question about forms? Take a look at our new Form Design guidance on the Foundations page.

Accessibility

Forge 2.0 includes many improvements to the accessibility of our components. Learn the basics, view our accessibility testing plan, and find resources and more on our new Accessibility Guidelines page.

Interruption Design

We’ve added a new Foundations page with guidelines on Interruption Design. Get advice on alerting your users about information in a way that fits the workflow and minimizes alert fatigue.

Tree Shaking

You can now import individual components to reduce your bundle size.

Future-proofing

UNSAFE Methods

We have removed all UNSAFE React methods for future version compatibility.

babel-polyfill

babel-polyfill is no longer needed as we have removed all uses of Object.assign.