On this page
Dev Setup
Get set up using Nebula in your app.
Nebula is a React component library built on styled-components. This page takes you from an empty app to a rendered component, then covers each piece of setup in detail.
Requirements
- React 16.8, 17 or 18. Nebula's declared peer range stops at 18, so React 19 isn't supported yet.
- styled-components v5 (^5.2.0). v6 isn't supported, and a plain yarn add styled-components installs v6, so ask for v5 explicitly (see peer dependencies).
- A bundler that can import a CSS file, for the CSS reset.
- A personal npm account in the private kaluza-platform organisation. See Get access.
TypeScript types are included in the package, so there is nothing extra to install for them.
Installation
Get access
@kaluza-platform/nebula is a private package on npm. You need a personal npm account in the kaluza-platform organisation (you join it with the /npm Slack command) and a read-only token available as NPM_TOKEN.
Kaluza's guide, npm publish / install private kaluza-platform npm registry, covers all of it: onboarding, configuring npm or Yarn, and setting up CI. Follow it before installing, and check with npm whoami (or yarn npm whoami) that you're logged in.
Install the package
yarn add @kaluza-platform/nebula
Or if you prefer:
npm install --save @kaluza-platform/nebula
Install the peer dependencies
Nebula expects your app to provide these. npm 7 and later installs them for you; Yarn doesn't, so add them yourself. react and react-dom are your app's own.
"peerDependencies": {
"@internationalized/date": "^3.8.1",
"@react-aria/button": "^3.13.1",
"@react-aria/calendar": "^3.8.1",
"@react-aria/datepicker": "^3.14.3",
"@react-aria/dialog": "^3.5.25",
"@react-aria/focus": "^3.20.3",
"@react-aria/i18n": "^3.12.9",
"@react-aria/overlays": "^3.27.1",
"@react-aria/tooltip": "^3.8.7",
"@react-aria/utils": "^3.29.0",
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0",
"react-stately": "^3.38.0",
"styled-components": "^5.2.0"
}
yarn add @internationalized/date @react-aria/button @react-aria/calendar @react-aria/datepicker @react-aria/dialog @react-aria/focus @react-aria/i18n @react-aria/overlays @react-aria/tooltip @react-aria/utils react-stately styled-components@^5.2.0
styled-components is pinned to v5 there because a plain yarn add styled-components installs v6, which Nebula doesn't support.
Set up your app
Nebula needs three things around your app: the reset stylesheet, a theme, and an overlay provider. Import the stylesheet once, in your app's entry file:
import '@kaluza-platform/nebula/dist/reset.css';
Then wrap your app in the two providers:
import { OverlayProvider } from '@react-aria/overlays';
import { ThemeProvider } from 'styled-components';
import { createTheme, PrimaryCTAButton } from '@kaluza-platform/nebula';
const theme = createTheme({});
export const App = () => (
<OverlayProvider>
<ThemeProvider theme={theme}>
<PrimaryCTAButton onClick={() => alert('Yippee!')}>
I ❤ Design Systems
</PrimaryCTAButton>
</ThemeProvider>
</OverlayProvider>
);
That is a working setup. The sections below explain each part, and the troubleshooting list at the end covers what it looks like when one is missing.
CSS reset
The reset is required, not optional polish. Nebula sizes everything in rem on the assumption that 1rem is 10px, and the reset is what makes that true: it sets html { font-size: 62.5% }. Without it 1rem is the browser's 16px, and every component renders about 60% larger than designed.
It also applies a CSS reset so elements start from the same defaults on every browser.
import '@kaluza-platform/nebula/dist/reset.css';
How you import it depends on your bundler. Webpack needs a css-loader to import CSS. Vite handles CSS imports with no setup. In Next.js, import it in your root layout (app/layout.tsx) with the App Router, or in pages/_app.tsx with the Pages Router, which is the only place that router allows global CSS.
The reset gives body a default font of Open Sans or Arial. Nebula's components set their own fonts from the theme, so set the font for the rest of your page in your own CSS (usually Inter, see Fonts).
Fonts
Nebula's theme uses two font families:
- Aspekta, an open source font, for display text such as headings (theme.fonts.display, falling back to Inter and then sans-serif).
- Inter, available as a Google font, for body text (theme.fonts.body, falling back to sans-serif).
Nebula uses four weights: normal (400), medium (500), semi bold (600) and bold (700). Both fonts support them, so load all four.
Nebula doesn't load the fonts for you. Add them to your app from the links above; until you do, text falls back to the system sans-serif font.
Theming
Nebula uses styled-components, so your app needs a ThemeProvider at its root, with a theme from createTheme. Called with an empty object it gives you the default theme. The package also exports that as theme, ready to use.
import { ThemeProvider } from 'styled-components';
import { createTheme } from '@kaluza-platform/nebula';
const theme = createTheme({});
<ThemeProvider theme={theme}>
<MyApp />
</ThemeProvider>;
To change colours, spacing and so on, and to turn on the transitional configuration flags (markRequiredFormFields, accessibleBadge, disableAutocomplete), see Theming.
OverlayProvider
Components that render overlays, such as the Modal and the popovers of the date and month pickers, use React Aria's overlay hooks, which expect an OverlayProvider above them. Without one, some of them throw Modal is not contained within a provider. Add one at the root rather than working out which components need it.
import { OverlayProvider } from '@react-aria/overlays';
const MyApp = () => <OverlayProvider>Welcome to my app!</OverlayProvider>;
Icons
Icons work with no setup: Nebula ships a default set, and components that take an icon (Icon, the CTA buttons and links) look names up in it.
To add your own, wrap your app in an IconsProvider. Your icons are merged with the defaults, and each one is a component that receives the props for an <svg>:
import { Icon, IconsProvider } from '@kaluza-platform/nebula';
const icons = {
rocket: (props: JSX.IntrinsicElements['svg']) => (
<svg viewBox="0 0 24 24" {...props}>
<path d="M12 2 2 22h20z" />
</svg>
),
};
<IconsProvider icons={icons}>
<Icon name="rocket" />
</IconsProvider>;
Using the components
Everything is a named export of @kaluza-platform/nebula:
import { Page, PrimaryCTAButton } from '@kaluza-platform/nebula';
const Example = () => (
<Page>
<PrimaryCTAButton onClick={() => alert('Yippee!')}>
I ❤ Design Systems
</PrimaryCTAButton>
</Page>
);
Browse the components for what each one does, how to use it, and its props on the Spec tab.
Testing your app
Components need the same providers in tests as in your app. With React Testing Library, create a wrapper once and use it for every render:
import { render } from '@testing-library/react';
import { OverlayProvider } from '@react-aria/overlays';
import type { ReactElement, ReactNode } from 'react';
import { ThemeProvider } from 'styled-components';
import { theme } from '@kaluza-platform/nebula';
const Providers = ({ children }: { children: ReactNode }) => (
<OverlayProvider>
<ThemeProvider theme={theme}>{children}</ThemeProvider>
</OverlayProvider>
);
export const renderWithProviders = (ui: ReactElement) =>
render(ui, { wrapper: Providers });
Using Nebula with AI tools
The docs are also published as plain text for AI assistants. Point your tool at the index, which links to a text file per page (props, usage rules and examples included), or at the single full file:
- https://nebula.kaluza.com/llms.txt
- https://nebula.kaluza.com/llms-full.txt
Troubleshooting
- Everything looks too big. The reset stylesheet isn't loaded, so 1rem is 16px instead of 10px. See CSS reset.
- A TypeError about reading a property of undefined, from inside a Nebula component. There is no ThemeProvider above it. See Theming.
- Modal is not contained within a provider. Add an OverlayProvider at the root. See OverlayProvider.
- 404 when installing @kaluza-platform/nebula. npm answers 404 for a private package you can't read: you aren't in the organisation yet, or your token isn't being picked up. Run npm whoami and follow the guide in Get access.
- Peer dependency warnings. Install the packages listed under peer dependencies.
- Warnings about several versions of styled-components. Your app and Nebula have ended up with separate copies. Make sure there is one copy, at v5.
- Text is in the wrong font. The fonts aren't loaded. See Fonts.