Skip to content

What you should know before getting started

Before you get started, there are some technical decisions you should know about - as in every project.

Table of Contents


About technology

The library exists of React components. The newer components are written as functional components, with React hooks. This was added to React version 16.8 and has become the new standard of React.

Files in the library were first written in JavaScript using PropTypes to define component types. For newer components we adopt using TypeScript, substituting the use of PropTypes.

Components are styled using nested CSS class selectors with SASS (SCSS) and BEM (Block Element Modifier).

Eufemia is a Mono Repository

The Eufemia repository is a monorepo consisting of the following workspaces:

  • dnb-design-system-portal: Source code of the portal website - this website.
  • dnb-eufemia: Source code of the npm package - where all the components are located.

dnb-eufemia

The only folders you should need to know about to add new features are:

  • src/components: The folder containing all the components, structured in component folders.
  • src/extensions: The folder containing all extensions, also structured in component folders.

dnb-design-system-portal

The documentation in markdown (MDX) is located at src/docs and the portal will automatically create pages and menu items based on that current structure.

All you need to do to add a new page is to create a new markdown (.mdx) file within one of the folders. All documentation for components and elements are located at src/docs/uilib, which corresponds to the URL eufemia.dnb.no/uilib.

Configuration files

  • ncurc.json is used to ignore certain dependencies during a dependency update made by npm-check-updates.
  • .eslintrc is a file with configurations to ESLint, which is a tool for identifying and reporting on patterns found in ECMAScript/Javascript code, with the goal of making code more consistent and avoiding bugs.
  • .prettierrc is a file with configurations to Prettier, which is a codeformatter for multiple languages.
  • .stylelintrc is a file with configurations to stylelint, which is a linter for styling (SCSS/CSS).
  • babel.config.js configures Babel, a JavaScript compiler.
  • jest.config.js configures Jest, the JavaScript Testing Framework for this project.
  • jest.config.screenshots.js configures jest-image-snapshot, which is related to the screenshot testing (visual assertion).
  • tsconfig.json is a file with configurations to TypeScript.

About Types

The two main purposes of delivering TypeScript types are:

  • Inline property documentation
  • Property validation and type safety

As of now, some components are written in TypeScript (.tsx) and some in JavaScript and type definition files (.d.ts).

Legacy type handling

For JavaScript based components, the documentation for properties (properties.mdx) is kept as a Markdown Table, they get extracted, parsed, and inserted in the type definition files.

You can still sync/update the documentation of these files (d.ts), by running: yarn @dnb/eufemia build:types:docs or yarn build.

NB: After you have synced/updated the files, you will see that some newlines were removed. Thats a negative side-effect we have no solution at the moment.

Sharing PropTypes between components (legacy)

You can share PropTypes between files. You can either export them explicitly (named export):

Named Export

// Make sure you include `*PropType` in the variable name. This also effects references inside a single file.
export const componentPropTypes = {
...otherPropTypes,
children: PropTypes.node,
property: PropTypes.string,
}

and import them in other components by using the spread operator:

import { componentPropTypes } from './component'
const Other = () => {}
Other.propTypes = {
...componentPropTypes,
otherProperty: PropTypes.string,
}

Default Export

or as a static reference on the component itself (default export):

const Component = () => {}
Component.propTypes = {
children: PropTypes.node,
property: PropTypes.string,
}
export default Component

and import them in other components by using the spread operator:

import Component from './component'
const Other = () => {}
Other.propTypes = {
...Component.propTypes,
otherProperty: PropTypes.string,
}

There are a couple of components doing so. You may have a look at:

  • Input and InputMasked
  • Icon and IconPrimary
  • Also the SpacingHelper shares spacingPropTypes with almost every component

NB: In order to activate the type generation, a component needs to import the prop-types dependency.

Shared Properties docs (legacy)

If you have one /properties.md file, but e.g. two components share most or all of the properties. Like a component and a provider for that component (Accordion and AccordionProvider) – then you can define in the markdown table header name both of the components: You can then provide a second table with a more specific table for a second component.

#### Properties
| Accordion and AccordionProvider Properties | Description |
| ------------------------------------------ | --------------------------------------------------------------------- |
| `id` | _(optional)_ docs. |
| [Space](/uilib/layout/space/properties) | _(optional)_ spacing properties like `top` or `bottom` are supported. |
| AccordionProvider Properties | Description |
| ---------------------------- | ------------------------------ |
| `expanded_id` | _(optional)_ expanded_id docs. |

About component structure

Eufemia has a couple of common parts, so every component behaves consistent:

  • Locale support.
  • Provider support for centralized property forwarding.
  • Spacing support.
  • Skeleton support.
  • FormLabel / FormStatus support if it's a form component.
  • Automatic id generation and linking of HTML elements to enhance accessibility.
  • Handling of aria-describedby with combineDescribedBy etc.

How to add support for every one of these are explained in Additional support - Getting started.

Component folder

Every component and extension should have a similar structure, as described here.

As an example, we show the folder structure of component Breadcrumb. You can also check out the source on Github.

Folder structure with tests, style, typescript files and index files
Folder structure of component Breadcrumb
  1. /__tests__: Contains the tests (Breadcrumb.test.tsx) and screenshot tests (Breadcrumb.screenshot.test.tsx) for the component. All screenshots will be placed within the folder __snapshots__.
  2. /style: Contains the styling of the component. The file _breadcrumb.scss defines all styling using BEM. dnb-breadcrumb.scss contains the component style exports.
  3. Breadcrumb.tsx and BreadcrumbItem.tsx: The React components for the Breadcrumb are defined and exported from these files.
  4. index.js: Contains component exports.
  5. style.js: Contains component style exports.

Modifications

  • Adding theming files under a folder style/themes will unlock the possibility of having different themes in the future. Check out the source for theming in Button.

Development environments

There are a couple of environments for different purposes.

Storybook development

Storybook is used for quick examples and component development. They do not need to be perfect.

Stories are placed inside a /stories directory and contain .stories in the filename: /components/button/stories/Button.stories.tsx

Run Storybook locally by running

yarn dev

in the root folder. Then you can view the Storybook website by visiting localhost:8002.

Add new pages to the storybook by adding a new directory /stories and a new file under ComponentName.stories.tsx and following the similar structure of the other files.

Eufemia portal

The portal is currently handled by Gatsby, a framework for building pre-rendered SSR websites.

Run the Portal locally:

$ yarn start

This will start the Portal. You can view the portal website by visiting localhost:8000.

Content changes to both Markdown (MDX) files and styles (SCSS) and code changes will be reflected immediately.

For a faster startup-time, you can decide what pages you need by using the environment variable filter e.g.:

$ filter=button yarn start
# - or –
$ filter=button,/input/ yarn start # with comma
$ filter="button /input/" yarn start # with space (needs to be quoted)

And visit e.g. this page: http://localhost:8000/uilib/components/button/

Local build

In case you have to create a local static build of the portal website (for various reasons), you can do so by:

# In the `dnb-design-system-portal` directory, run:
$ yarn build

The build will be exported to the /public directory. You can now also run a local static server to view it at the given port localhost:8000:

# In the `dnb-design-system-portal` directory, run:
$ yarn serve

What happens in the build steps

During the build, a lot of various things will happen. First, a prebuild before the build and afterward a postbuild.

During prebuild

$ yarn build
  • Assets are getting generated
  • All index and lib files are getting generated
  • All the lib code gets compiled (ECMAScript 6 and ECMAScript 5.1)
  • All SASS styles are validated and compiled (to support IE)
  • All bundles get minified
  • Icons are getting converted

To use the local build, you can either run the portal, or use yarn link to link the package with a totally different project.

During postbuild

$ yarn workspace @dnb/eufemia postbuild:ci
  • Assets are getting generated
  • All the lib code gets compiled (ECMAScript 6 and ECMAScript 5.1)
  • UMD/ESM/ES/CJS bundles are getting generated
  • TypeScript definitions are getting generated