We have three types of components on Open Library:
- CSS Components: Components which only require a little bit of CSS. These could have a separate HTML template file in
openlibrary/templates
if it makes sense to have one, and will usually have a separate .less file instatic/css/components
. Note the .less file must then be imported from the corresponding page's .less file, E.g.static/css/page-user.less
. - JavaScript/JQuery components: These are components which require a small amount of functionality, or are legacy implementations. E.g. the
multi-input-autocomplete
. These will have a JS file inopenlibrary/plugins/openlibrary/js
, and an import line inopenlibrary/plugins/openlibrary/js/index.js
. - Vue components: For new, more interactive components, we prefer to use Vue.js. These components will have a
.vue
file inopenlibrary/components
. For more info on Vue, read the README in that directory. E.g: LibraryExplorer.vue
All these components make use of BEM class notation to define the component parts, css, and selectors. Each component should also begin with ol-
; this makes it easy for us to search for components in the codebase.
For example: The ol-searchbox
component defines a search box with a search button icon on the right. We use this in various places throughout the site.
It has an html template file in openlibrary/templates/ol-searchbox.html
:
$def with (q)
<div class="ol-searchbox">
<input class="ol-searchbox__input" name="q" placeholder="$_('Search')" value="$q">
<div>
<input class="searchbox__btn-icon" type="submit" title="$_('Search')">
</div>
</div>
And it has a less file in openlibrary/static/css/components/ol-searchbox.less
:
.ol-searchbox {
display: flex;
align-items: center;
.ol-searchbox__input {
...
}
.ol-searchbox__btn-icon {
...
}
}
And an import in e.g. openlibrary/static/css/page-user.less
:
@import "components/ol-searchbox.less";
If this component needed to have some JavaScript functionality, we would add a JS file in openlibrary/plugins/openlibrary/js/ol-searchbox.js
:
export class OLSearchBox {
constructor($container) {
/** @type {JQuery} */
this.$container = $container;
this.$input = this.$container.find('.ol-searchbox__input');
}
static init() {
$('.ol-searchbox').each((i, el) => {
new OLSearchBox($(el));
});
}
}
and then to include it in the main JS file, we would add an import line in openlibrary/plugins/openlibrary/js/index.js
:
if (document.querySelector('.ol-searchbox')) {
import(/* webpackChunkName: "ol-searchbox" */ './ol-searchbox.js')
.then((module) => module.OLSearchBox.init());
}