Skip to main content

UI Assets Overrides

All the assets served to the UI of Hanami can be overridden. For this, one would need to add to their customer.yml file something like this:

local:
assets:
folder: /opt/hanami/ext/override

Like this, files in the /opt/hanami/ext/override folder will be put in the folder serving UI assets. This could override any file in there even index.html, but we recommend to not blindly override any random file. Instead, we procure here a list of usual overrides that serves dedicates purposes.

i18n files

By default, Hanami loads 2 files when rendering the application in a given language. For example when the application is in English, it loads assets/i18n/en.json and assets/i18n/en.customer.json. Those files are holding most of the labels used in the application, structured in deep string maps that serves as keywords to map to labels. For example part of en.json looks like this:

{
"global": {
"cancel": "Cancel",
"close": "Close",
"collection": "Collection",
"copy_uri": "Copy URI",
"created": "Created",
"delete": "Delete"
},
"some_other_key": {
"that_can_go": {
"super_deep": "foo",
"something": "else"
}
}
}

Which means that, when the interface is trying to find a label for the key some_other_key.that_can_go.super_deep, it will print the label foo. And for some_other_key.that_can_go.something, it will print else.

Now considering en.customer.json. By default, it is served as an empty json {} and so will not have any impact. But let's say that we configured the override by using the opt/hanami/ext folder, then one could add there /opt/hanami/ext/assets/i18n/en.customer.json that would look like this:

{
"some_other_key": {
"that_can_go": {
"super_deep": "bar"
}
}
}

With this, when the interface will try and display a label for some_other_key.that_can_go.super_deep, it will print the label bar. And since we are doing a deep merge of the 2 maps, some_other_key.that_can_go.something will still be printed as else.

Customer specific keywords

If you need to add new keywords to the translation map, we advise to put them under a dedicated customer to be sure to not accidentally override keywords used elsewhere in the application. Then a typical en.customer.json file would look like this:

{
"customer": {
"my_custom_key": "Hello World"
}
}

This is especially useful when configuring other Hanami features that make use of translation labels, like workflow actions or footer links labels (see below).

UI Config file

An other file that is loaded on start is assets/config.json, and by default it is an empty json {}. Put properties can be added to it to configure some features.

When overriding assets/config.json, one could set some properties as below:

{
"header": {
"app_title": "customer.header.app_title",
"app_subtitle": "customer.header.app_subtitle",
"navMode": "bar",
"logo": {
"src": "assets/img/logo.png",
"alt": "customer.header.logo_alt",
"width": 81,
"height": 45
},
"links": [
{
"labelKey": "customer.footer.data_catalogue",
"url": "http://ep-catalog-dev-app.sysadmin.garden:8080"
}
]
}
}

The header can have a few properties set:

  • app_title: The title od the application, if you desire to override the default "Hanami". Please note that we are using keywords here, and so related translations should be provided in the i18n files as explained above.
  • app_subtitle adding a second line to the title, styled differently
  • navMode: specify the way the navigation bar behaves in the header. There are multiple possible values:
    • bar: display the navigation items directly in the header
    • burger: display the navigation items in a "burger menu" that can be opened from the left of the application logo
    • hybrid: An in-between solution where bar is used on the home page, and burger on most others. This configuration is not considered a11y friendly at the moment, so we advise against it for now.
  • logo: specify which logo to use instead of the default one. All properties here are needed:
    • src: url to the image to be loaded
    • alt: descriptive text to add to the image, especially useful for users making use of screen readers.
    • width: width the image should take, in pixels
    • height: height the image should take, in pixels
  • links: list of link to be added to the header, giving them a labelKey and a url to reach.

Similarly to the header, the footer can be configured in a similar fashion, having also links and a logo parameters:

{
"footer": {
"logo": {
"src": "assets/img/footer-logo.png",
"alt": "customer.footer.logo_alt",
"width": 236,
"height": 35
},
"links": [
{
"labelKey": "customer.footer.google",
"url": "https://google.com"
},
{
"labelKey": "customer.footer.send_feedback",
"url": "mailto:feedback@domain.com"
}
]
}
}

Styles

Finally, one can configure the injection of custom css files, like so:

{
"styles": {
"files": ["assets/styles/customer.css"]
}
}

You can then put any styling that you want there and customize Hanami to your heart's content. For now, we advise to limit this customization only through overriding css variables, for example like so:

:root {
--font-family-main: "Helvetica", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
--color-primary: #0d6efd;
--color-primary-dark: #0d5286;
--color-primary-intense: #0d5286;
--color-secondary: #6b31a5;
--color-secondary-intense: #360c50;
}

Here is the list of variables that we advise to first override if the need arises:

:root {
/* Primary colors, used in most places */
--color-primary: var(--color-blue-intense);
--color-primary-dark: var(--color-blue-dark);
--color-primary-light: var(--color-blue-light);
--color-primary-bg: var(--color-blue-bg);
--color-primary-hover: var(--color-blue-hover);
--color-primary-disabled: var(--color-blue-disabled);
/* border colors, depending on the desired intensity */
--color-border-soft: var(--color-gray-10);
--color-border-hard: var(--color-gray-50);
/* A secondary palette of colors, used as an accent color to draw attention to some parts of the page */
--color-secondary: var(--color-violet);
--color-secondary-bg: var(--color-violet-bg);
--color-secondary-intense: var(--color-violet-intense);
--color-secondary-light: var(--color-violet-light);
--color-link: var(--color-primary);
/* color of fonts used, high is usually for titles, medium is for more discreet texts. Light is really rarely used */
--color-font-high: var(--color-dark);
--color-font-medium: var(--color-gray-70);
--color-font-light: #686868;
/* Color used for error state, like inlined errors in forms, or error prompts */
--color-error: var(--color-red);
/* Color used for warning state, mostly ever used in rare warning prompts prompts */
--color-warning: var(--color-orange-intense);
/* Colors used for success state, mostly for success toasts after an async operation succeeds (like a creation/save) */
--color-success: var(--color-green);
--color-success-bg: var(--color-green-bg);
/* Fonts to be used in the application */
--font-family-main: "Inter", sans-serif;
--font-family-secondary: "Inter", sans-serif;
}

Other styling could be added fo course, but then we advise to use components tag names to somewhat limit the scope of the customization. For example one could add something like this:

hanami-page-title .hanami-page-title-content {
color: var(--color-primary) !important;
font-weight: 400 !important;
font-family: var(--font-family-secondary) !important;
}

It is to be noted that styling outside of css variables could break on new Hanami releases, so custom styling should ideally be kept to a minimal set of change.