Extending Rivet
Guidelines for extending Rivet to cover unique content and interactions
Rivet aims to be a flexible tool that enables people to design interfaces for a wide variety of digital platforms at IU. However, your project might include unique content or interactions that Rivet’s built-in layouts or components don’t cover.
The guidelines on this page are intended to help you extend Rivet in a way that is consistent with its design conventions. Following these guidelines can also make it easier for other developers to understand and potentially adopt your code.
Creating new components using utilities #
Rivet provides a large number of utilities: individual CSS classes that can be used to set element styles such as margins, padding, color, border, fonts, and more.
You can use utility classes to add Rivet styles to non-component markup in order to create new interface elements that are specific to your site.
Adding utility classes to existing component markup #
Aside from spacing and width, you should avoid using utilities to change the appearance of built-in components when possible.
If you do choose to add utility classes to built-in component markup, wrap those utility classes in brackets. This helps others reading your code more easily identify how a component’s appearance has been adjusted.
<div class="rvt-card [ rvt-p-all-xxl rvt-border-all ]">
Writing custom CSS #
You should favor using utility classes over writing custom CSS whenever possible.
However, in situations where custom CSS is required, keep the following guidelines in mind:
- Don’t override Rivet CSS classes directly—create new CSS classes
- Reference the values listed on Rivet’s design tokens page
- Prefix your new component CSS class names with
rvt-c-
to distinguish them from built-in Rivet classes - Use the block-element-modifier (BEM) naming convention for your CSS class names
<div class="rvt-c-my-custom-component">
<h2 class="rvt-c-my-custom-component__title">Title</h2>
</div>
.rvt-c-my-custom-component {
/* ... */
}
.rvt-c-my-custom-component__title {
/* ... */
}
- Don’t hard-code margins into the CSS for the root element of your custom component. Doing so can cause spacing or alignment issues when your custom component is used alongside other Rivet components, which by default do not have margins on their root elements. Instead, use Rivet’s spacing utility classes to add outer margins to specific instances of your custom component as needed. (You can still add margins to the CSS for child elements within your component.)
/* Don't do this */
.rvt-c-my-custom-component {
margin: 2rem 0;
}
/* This is okay */
.rvt-c-my-custom-component__title {
margin-bottom: 1rem;
}
<!-- Do this -->
<div class="rvt-c-my-custom-component [ rvt-m-tb-lg ]">
<!-- custom component markup... -->
</div>
Writing custom JavaScript #
If a project-specific component you’ve created has interactive functionality powered by JavaScript, follow the guidelines below:
- Use JavaScript Standard Style when formatting your code
- Do not target CSS classes with JavaScript—define data attributes for your component markup and target those attributes instead
- Prefix all custom component data attributes with
data-rvt-c-
to distinguish them from built-in Rivet data attributes
<div class="rvt-c-my-custom-component" data-rvt-c-my-custom-component>
<h2 class="rvt-c-my-custom-component__title">Title</h2>
</div>
- Attach component methods to the root DOM element of your component’s instances rather than passing instances to a method
/* Do this */
myCustomComponent.open();
/* Don't do this */
MyCustomComponent.open(myCustomComponent);
- Opt for custom events over callbacks and try to emit custom events when the state of your component changes
- Prefix all custom event names with
rvtc
, such asrvtcMyCustomComponentOpened
- Dispatch the event to the emitting component’s root DOM element so that it can be referenced using the
target
property - Pass additional context needed about the custom event as properties of the
detail
object
document.addEventListener('rvtcMyCustomComponentOpened', function(event) {
// The event.target property stores a reference to the root DOM element of the
// component that emitted the event
console.log(event.target);
// The event.detail object contains additional context about the event
console.log(event.detail);
});