Customising Tangram
When to customise Tangram
Sometimes it’s healthy and/or necessary to deviate from a design system. This is particularly the case if the design system doesn’t have what you need.
We're here to help!
Join the conversation at #tangram
Creating something custom?
If you create something custom when a suitable component or pattern is available, you are likely to hear the following questions from your Design Lead or the Tangram team:
- Have you explored using existing Tangram components and patterns? Could they been extended to meet your needs?
- What does your proposed changes achieve that existing components or patterns don’t provide?
- What is the use case that prompted the proposed change?
- Have your proposed changes been user tested?
- Is there a precedence for this outside of Trade Me?
How to override Tangram CSS
Summary
There will be times when you need to override Tangram styles to customise the user interface.
- Overrides in your product must be covered by tests.
- Read Tangram documentation first in case there is already an available API option.
- Only use CSS classes for overriding Tangram styles to keep CSS specificity simple.
- Be aware that class names, styles and HTML structure of Tangram component templates may change with patch versions of Tangram.
- Do not use
or inline styles.!important - Ensure your overrides are scoped appropriately and not globally. Use the default view encapsulation settings and be careful when using
.::ng-deep
Overriding responsibly
CSS class names, styles or HTML structure of Tangram component templates are not part of the public API. Therefore, these things may change in any version release, including minor and patch releases.
If you have overridden Tangram styles, this may break your overrides. Therefore, the functionality of your overrides must be covered by appropriate tests. The Tangram squad will run tests in FrEnd, where they exist. If your Trade Me product is using Tangram and you’d like us to run your tests in a similar way, please get in touch with us to discuss this further.
By overriding Tangram component styles, you are responsible for the maintenance responsibility that comes with this decision. For this reason you may choose to update to each version manually instead of automatically update to patch versions when installing packages.
FrEnd specifics
If Tangram squads get failing tests in FrEnd when updating to a new Tangram Web UI package version, we will aim to fix these during the update and let the relevant squads know. If there are too many issues to fix with reasonable turnaround, we will discuss this with your team and make a plan for moving forward.
If tests pass, the Tangram squad won’t investigate any further.
Tangram classes vs your custom classes
When you have direct access to Tangram component HTML tags in your template (i.e. the component selectors and content slots that are part of the public API), adding your own class specific to your component may be the best option for readability and reducing the risk of side effects. This is likely most relevant when adding styles rather than overriding previously set styles from Tangram. There will be times when you need to target the internal template of a Tangram component, and in these cases you will have no option but to use the Tangram class.
.tm-your-component__element .tm-your-component__accordion {
// your styles
}Example of using your own class
.tm-your-component__element .o-accordion__item-header {
// your styles
}Example of using a Tangram class
Scope / View encapsulation
It is important that you consider what other styles your override may adversely affect. If using Angular’s default emulated view encapsulation this is less of a risk, however if needing to use ::ng-deep
.tm-your-component__element ::ng-deep .o-accordion__item-header {
// your styles
} You are breaking out of using view encapsulation for anything after the ::ng-deep
Media queries do not provide encapsulation in this way, so the following code would cause side effects.
@media (min-width: $tg-md-min) {
.o-accordion__item-header {
// global styles here! Will affect other accordions
background-color: $tg-silver-fern-10;
}
.o-accordion__item.s-is-active .o-accordion__item-header {
background-color: inherit;
}
}In this example of accidental global styles view encapsulation has been turned off and these styles will affect any accordions on the page while these styles are present in the document head.
Keeping CSS specificity simple, low and intuitive
To keep CSS specificity as simple as possible, stick to using only CSS classes e.g. .o-accordion__item-header
For this reason we recommend using the class .o-accordiontg-accordion
.tm-your-component__element .o-accordion {
// your styles
} You wouldn’t need ::ng-deeptg-accordion
Using element selectors for components
You may decide to keep specificity as low as possible and use the element selectors when you are able to. If so, please ensure your team is willing to understand how this affects specificity and when to use the element vs the class selector, as you will likely need to use both depending on the context. This is a specificity win but a loss of consistency and potentially readability and long term maintenance.
.tm-your-component__element tg-accordion {
// your styles
}If you choose to use element selectors, it may be harder for some members of the team to calculate the specificity of your selectors.
Inline styles
Inline styles will take precedence over any styles in external stylesheets. They should be avoided. If using inline styles use extreme caution and only use them in special cases (e.g. where you may be dynamically generating CSS on the fly).
!important
Do not use !important
CSS, HTML and Tangram semver
As mentioned above, HTML and CSS for Tangram components are not considered part of the public API and as such are subject to change between any Tangram version including patches. See above for more info on test setup expectations.
Customising modal
When a modal is triggered the modal content is moved to the top of the DOM, and the host element and class are lost. To allow overrides, the host class of the modal is transferred to the dialog element. You will need to prefix your class selector with ::ngDeep
<tg-modal
*ngIf=”showmodal”
class=”tm-your-modal-override-class”>
...
</tg-modal>::ng-deep .tm-your-modal-override-class {
// your custom dialog styles
} Note the use of ::ng-deep