@j2-health/design-system
v0.6.3
Published
J2 Health shared React component library
Readme
Design System
⚠️ This repository is public, and holds UI components only. No business logic, no customer data, and no details of the private applications that consume it — a component may accept domain data as props, but must not know what that data means. Everything committed here is permanently world-readable, including git history, so a mistake cannot be undone by deleting the file later. See CLAUDE.md for the full rules.
Contributing
Installation
Make sure to install our pre-commit hooks. They are also verified by CI, but if
you want to be notified early of linting or type errors, you have to install
pre-commit and run its install step. To do this, run the following:
$ PIP_REQUIRE_VIRTUALENV=false pip install pre-commit
$ pre-commit installUsage
Storybook
In order to run the storybook, make sure to install node modules with
npm install, and run the following command:
$ npm startIn-app
There are two ways to consume the design system in a React application.
As an npm package (preferred)
The library is published to npm as @j2-health/design-system:
$ npm install @j2-health/design-systemThe package ships a prebuilt bundle plus type declarations, and expects the
consuming app to provide the peer dependencies listed in package.json (react,
antd, formik, highcharts, tailwindcss, ...).
Tailwind 3.4 and Tailwind 4 are both supported. The package keeps its JavaScript
preset so existing Tailwind 3 consumers do not need to migrate with the design
system. Tailwind 4 consumers load the same preset explicitly with @config.
Wire it up in three places:
Components — import from the package root:
import { Button, AppConfigProvider } from '@j2-health/design-system'Styles — import the compiled component styles once (e.g. in your app entry), and pull the base stylesheet into your own CSS pipeline:
// app entry import '@j2-health/design-system/style.css'With Tailwind 3, import the legacy stylesheet as the first statement in your root stylesheet:
@import '@j2-health/design-system/stylesheets/index.css';This file is your Tailwind 3 entry point. It supplies
@tailwind base,@tailwind components, and@tailwind utilitiesalong with the design tokens and base element styles, so remove those directives from your own stylesheet — keeping both emits every Tailwind layer twice.With Tailwind 4, install the separate PostCSS plugin:
npm install --save-dev @tailwindcss/postcssReplace
tailwindcss: {}with'@tailwindcss/postcss': {}in your PostCSS config, then use the Tailwind 4 stylesheet entry and load your JavaScript config explicitly:@import '@j2-health/design-system/stylesheets/tailwind.css'; @config '../../tailwind.config.ts';Adjust the
@configpath relative to the stylesheet containing it. Tailwind 4 no longer discovers JavaScript config files automatically. The Tailwind 4 entry scans the package's compiled components and emits each Tailwind layer once.Tailwind — use the preset and scan the package's compiled output so utility classes used inside components are generated by your build. This config works with Tailwind 3 and can be loaded by Tailwind 4 through the
@configdirective above. Tailwind 4 scans the package from its stylesheet; the package glob remains necessary for Tailwind 3:// tailwind.config.ts import { tailwindPreset } from '@j2-health/design-system/tailwind' export default { presets: [tailwindPreset], content: [ './src/**/*.tsx', './node_modules/@j2-health/design-system/dist/**/*.{js,cjs,css}', ], }
As a git submodule (legacy)
Include this repo as a git submodule and compile its raw TypeScript source with
your own toolchain (vite alias + tsconfig paths + tailwind content globs
pointing into the submodule). The npm entry point for this mode is index.ts at
the repo root; submodule consumers should alias design-system to that file
explicitly, since the package.json exports map points at dist/, which only
exists in the published package.
Migrating to 0.4.0 (Ant Design 6)
Version 0.4.0 requires antd ^6.6.3 and @ant-design/icons ^6.3.4. Upgrade both with the design system; Ant Design 5 is no longer supported. React 18.3.1 and React 19 remain supported, and Tailwind stays on v3. Ant Design 6 requires modern browsers with CSS-variable support.
npm install @j2-health/design-system@^0.4.0 antd@^6.6.3 @ant-design/icons@^6.3.4formik-antd is no longer a dependency: its published peer range excludes Ant
Design 6. The design system's Form, Form.Item, Input, InputNumber, and
Select now bind directly to Formik. Keep these components inside a <Formik>
provider. Nested field names, validation, touched state, submission, reset, and
field callbacks continue to use Formik.
If your application imports formik-antd directly, migrate those imports before
uninstalling it. Use the design-system exports for the components above; other
controls need an explicit Formik binding. Form.Item validation should use
Formik's validate or validationSchema, rather than antd's separate form
store and rules API.
Review direct antd imports and custom .ant-* CSS using the
Ant Design 6 migration guide.
Several internal DOM classes changed. For types, derive step items from
NonNullable<StepsProps['items']>[number] instead of the removed StepProps
export. The design-system Tag retains its outlined default and trailing
spacing; raw antd tags follow the new v6 defaults.
Local development against a consuming app
To work on a component and see it live in an app that depends on this package,
point the app's bundler at this checkout's source rather than linking the built
package. Consuming apps support this through a DESIGN_SYSTEM_LOCAL environment
variable:
DESIGN_SYSTEM_LOCAL=/path/to/design-system npm run devDo not use npm link or npm install ../design-system. This package
declares peer dependencies that are also devDependencies, because Storybook and
the test suite need them to run. A linked install resolves those imports from
this checkout's own node_modules rather than the app's, so the app ends up
with two copies of React and two copies of antd.
Two copies of React raise Invalid hook call, which is at least obvious. Two
copies of antd fail silently: AppConfigProvider supplies the theme through
antd's ConfigProvider, a React context singleton, so a component resolved from
the second copy reads an empty context and renders unthemed with no error and no
warning. Because it only reproduces under a linked install, it looks like a bug
in this library that disappears the moment you publish.
Consuming apps must also set resolve.dedupe for react, react-dom, and
antd, since a local checkout has its own node_modules.
Publishing to npm
The package is published publicly (the source is public anyway) by .github/workflows/publish-workflow.yml.
There is no publish token. npm authenticates the release through trusted publishing (OIDC): npm is configured to trust this repository and this workflow file by name, and GitHub mints a short-lived identity token for the job. Two consequences worth knowing before you change anything here:
- Renaming or moving
publish-workflow.ymlbreaks publishing. The trusted publisher is matched on the exact filename, case-sensitive. Update it on npmjs.com in the same change. - Do not lower
.node-versionbelow 24.5.0. Trusted publishing needs npm >= 11.5.1, which is exactly what Node 24.5.0 ships. The workflow asserts this rather than letting it surface later as an unexplained 401.
To release a new version, bump version in package.json in a pull request —
on its own, or in the PR carrying the change you want to release — and merge it.
That is the whole procedure: the merge to main triggers the publish workflow,
which checks that version changed and is not already on npm, then publishes it
and creates the matching vX.Y.Z tag. A merge that touches package.json
without changing version (a dependency bump, say) publishes nothing.
If an automatic release needs re-running, dispatch the workflow against main —
maintainers only, since it needs write access to this repository:
$ gh workflow run publish-workflow.yml --ref mainOr, in the UI, Actions → Publish to npm → Run workflow with main selected.
Pick the ref carefully: the publish job is skipped rather than failed on any
other ref, so a dispatch from a feature branch reports success without
publishing.
You do not normally tag by hand — the tag job's own comments cover the one
case that needs it, where publishing succeeds and tagging fails.
npm version is not the tool here, despite being the obvious one: it writes the
bump as a local commit, and main requires a pull request, so that commit has
nowhere to push to.
Pushing a v* tag also triggers a release. Tag the remote main commit
explicitly: a bare git tag tags your current HEAD, and the workflow accepts
any tag ref, so a tag on an unmerged branch would publish that branch. Push the
tag explicitly too — git push --follow-tags silently skips lightweight tags
and would report success without publishing:
$ git fetch origin main
$ git tag -a v0.3.0 -m v0.3.0 origin/main
$ git push origin v0.3.0The workflow packs the tarball and builds a scratch consumer against it, runs
lint, tests and type-check, builds the library, and publishes; on a tag push it
also verifies the tag matches package.json. Provenance is generated
automatically by trusted publishing, so --provenance is not passed.
