# Optics Design System
> Optics is a pure-CSS design system by RoleModel Software (npm: `@rolemodel/optics`, v2.4.0). It provides design tokens (CSS custom properties prefixed `--op-`), base styles, utilities, and BEM-style components (`.btn`, `.card`, ...) that are customized per project via token overrides.
Every page below is plain markdown. Component pages include the actual HTML markup for each variant, the component's CSS variable API, and customization patterns. The full documentation in one file: [llms-full.txt](https://docs.optics.rolemodel.design/llms-full.txt). All design tokens as JSON: https://unpkg.com/@rolemodel/optics/dist/tokens/tokens.json
## Introduction
- [Introduction](https://docs.optics.rolemodel.design/llms/introduction.md): Optics embodies the RoleModel ethos of deep collaboration, uniting our team's diverse expertise with the shared goal of crafting excellent design solutions a...
## Overview
- [Overview/Addons](https://docs.optics.rolemodel.design/llms/overview-addons.md): Optics provides a few addons for integrating Third-Party tools with your application.
- [Overview/Base Reset](https://docs.optics.rolemodel.design/llms/overview-base-reset.md): All browsers ship with some default styles. These styles are inconsistent across browsers and can cause issues when building a UI. To ensure consistency acro...
- [Overview/File Organization](https://docs.optics.rolemodel.design/llms/overview-file-organization.md): As you use Optics, you will likely want to organize your Optics configuration into multiple files.
- [Overview/Scale Overriding](https://docs.optics.rolemodel.design/llms/overview-scale-overriding.md): There are multiple scales in Optics. Unit Scales exist to allow adjusting font and spacing values. Color Scales exist to provide semantically named color var...
- [Overview/Selective Imports](https://docs.optics.rolemodel.design/llms/overview-selective-imports.md): By default, when you import the design system, it will include the basics. CSS reset, All Tokens, Base styles, Utilities, and all Components.
- [Overview/Themes](https://docs.optics.rolemodel.design/llms/overview-themes.md): Optics defines a default theme along with it's dark mode. If you import the design system, it will be used automatically.
- [Overview/Tokens](https://docs.optics.rolemodel.design/llms/overview-tokens.md): Tokens are defined in `src/core/tokens`
## Tokens
- [Tokens/Animation](https://docs.optics.rolemodel.design/llms/tokens-animation.md): Animation and Transition tokens can be used for element transitions or animations.
- [Tokens/Border/Border Radius](https://docs.optics.rolemodel.design/llms/tokens-border-border-radius.md): Border radius tokens can be used to round corners on various elements.
- [Tokens/Border/Border Stroke](https://docs.optics.rolemodel.design/llms/tokens-border-border-stroke.md): Border tokens can be used as box shadows to add borders to various elements. Box Shadows are used in order to provide border styling without affecting the si...
- [Tokens/Border/Border Width](https://docs.optics.rolemodel.design/llms/tokens-border-border-width.md): Border width tokens can be used to define a border width or a box shadow width.
- [Tokens/Breakpoint](https://docs.optics.rolemodel.design/llms/tokens-breakpoint.md): Breakpoint tokens are used to define common device sizes for use within media queries or max widths.
- [Tokens/Color/Basic Color](https://docs.optics.rolemodel.design/llms/tokens-color-basic-color.md): Basic color tokens can be used to define exact colors.
- [Tokens/Color/Border Color](https://docs.optics.rolemodel.design/llms/tokens-color-border-color.md): Border color tokens can be used to define the color of borders and box shadows.
- [Tokens/Color/Color Scale](https://docs.optics.rolemodel.design/llms/tokens-color-color-scale.md): Optics has five main color scales that provide all the color your application may need. These Consist of the `Primary` scale, the `Neutral` scale, and four A...
- [Tokens/Color/Color with Alpha](https://docs.optics.rolemodel.design/llms/tokens-color-color-with-alpha.md): There may be a case where you need to use the alpha channel in a color. This can be useful for creating more opaque or transparent looks built directly into ...
- [Tokens/Encoded Image](https://docs.optics.rolemodel.design/llms/tokens-encoded-image.md): Encoded Image tokens are primarily used to create the dropdown arrow on `` elements using the `.form-control` class.
- [Tokens/Input/Input Focus](https://docs.optics.rolemodel.design/llms/tokens-input-input-focus.md): Input Focus tokens are used to define a button or form controls focus state.
- [Tokens/Input/Input Height](https://docs.optics.rolemodel.design/llms/tokens-input-input-height.md): Input Height tokens are used to define a button or form controls height.
- [Tokens/Opacity](https://docs.optics.rolemodel.design/llms/tokens-opacity.md): Opacity tokens can be used to create a faded or disabled effect on any element.
- [Tokens/Shadow](https://docs.optics.rolemodel.design/llms/tokens-shadow.md): Shadow tokens can be used to create an elevation effect on any element. There are also [Card classes](components-card.md#shadow) to create an elevated card e...
- [Tokens/Sizing](https://docs.optics.rolemodel.design/llms/tokens-sizing.md): The Size token enables creating scalable widths (inline-size) and heights (block-size) for your application. It is meant to be used in a `calc` expression wi...
- [Tokens/Spacing](https://docs.optics.rolemodel.design/llms/tokens-spacing.md): The Spacing Size tokens enable creating scalable spaces for your application. They can be used for margin, padding, gap, and anything else that is intended f...
- [Tokens/Typography/Font Family](https://docs.optics.rolemodel.design/llms/tokens-typography-font-family.md): Font Family tokens can be used to change the font used when displaying text.
- [Tokens/Typography/Font Size](https://docs.optics.rolemodel.design/llms/tokens-typography-font-size.md): Font Size tokens can be used to change the size of text.
- [Tokens/Typography/Font Weight](https://docs.optics.rolemodel.design/llms/tokens-typography-font-weight.md): Font Weight tokens can be used to change the font weight of text.
- [Tokens/Typography/Letter Spacing](https://docs.optics.rolemodel.design/llms/tokens-typography-letter-spacing.md): Letter Spacing tokens can be used to change the space between letters of text.
- [Tokens/Typography/Line Height](https://docs.optics.rolemodel.design/llms/tokens-typography-line-height.md): Line height tokens can be used to change the line height of text.
- [Tokens/Z-Index](https://docs.optics.rolemodel.design/llms/tokens-z-index.md): Z-Index tokens can be used to define the page z-index of an element.
## Utilities
- [Utilities/Advanced/Cluster](https://docs.optics.rolemodel.design/llms/utilities-advanced-cluster.md): The cluster utility provides a simple way to create a wrapping, group of spaced items. It works with all of the gap and other flex utilities. It is effective...
- [Utilities/Advanced/Flank](https://docs.optics.rolemodel.design/llms/utilities-advanced-flank.md): The flank utility provides a simple way to create a horizontal row with an item flanked by another large item. It works with all of the gap and other flex ut...
- [Utilities/Advanced/Frame](https://docs.optics.rolemodel.design/llms/utilities-advanced-frame.md): The frame utility provides a simple way to constrain content to a consistent aspect ratio. It centers its content and clips any overflow, so whatever it wrap...
- [Utilities/Advanced/Grid](https://docs.optics.rolemodel.design/llms/utilities-advanced-grid.md): The grid utility provides a simple way to create a dynamic grid layout. It is primarily intended for simple layouts with a minimum column size, or evenly div...
- [Utilities/Advanced/Split](https://docs.optics.rolemodel.design/llms/utilities-advanced-split.md): The split utility provides a simple way to push two items apart from each other. It is effectively equivalent to using `.flex .flex-wrap .items-center .justi...
- [Utilities/Advanced/Stack](https://docs.optics.rolemodel.design/llms/utilities-advanced-stack.md): The stack utility provides a simple way to create a vertical stack of spaced items. It works with all of the gap and other flex utilities. It is effectively ...
- [Utilities/Container](https://docs.optics.rolemodel.design/llms/utilities-container.md): Container utility classes are used to create a centered content area for your application.
- [Utilities/Flex](https://docs.optics.rolemodel.design/llms/utilities-flex.md): Flex utility classes are used to quickly lay out a page using the flex engine.
- [Utilities/Gap](https://docs.optics.rolemodel.design/llms/utilities-gap.md): Gap utility classes can be used to set the spacing between items within a flex or grid container.
- [Utilities/Introduction](https://docs.optics.rolemodel.design/llms/utilities-introduction.md): Utility classes are CSS classes scoped to a simple style property like flex or gap or a collection of related properties. They can be combined together to qu...
- [Utilities/Item Width](https://docs.optics.rolemodel.design/llms/utilities-item-width.md): Item Width utility classes can be used to set an element's width relative to its parent.
- [Utilities/Margin](https://docs.optics.rolemodel.design/llms/utilities-margin.md): Margin utility classes are used to add margin to an element.
- [Utilities/Text Alignment](https://docs.optics.rolemodel.design/llms/utilities-text-alignment.md): Text Alignment utility classes can be used to align text in an element.
- [Utilities/Visibility](https://docs.optics.rolemodel.design/llms/utilities-visibility.md): Use the '.sr-only' class to hide accessibility text that is needed for screenreaders but needs to be hidden from regular users. [Read more here.](https://sno...
## Components
- [Components/Accordion](https://docs.optics.rolemodel.design/llms/components-accordion.md): Accordion classes are built on the `details` and `summary` html elements. They provide consistent and composable styling for disclosure widgets.
- [Components/Alert](https://docs.optics.rolemodel.design/llms/components-alert.md): Alert classes can be used to create a highlighted message or callout in your application. These could be as banners for global application messages, or an er...
- [Components/Avatar](https://docs.optics.rolemodel.design/llms/components-avatar.md): Avatar classes can be used on `a` or `div` html elements with an `img` within it. They provide consistent and composable styling for application avatars or p...
- [Components/Badge](https://docs.optics.rolemodel.design/llms/components-badge.md): The Badge component is similar to the Tag component, however it has a different semantic purpose. Badge is intended to be used for notification and informati...
- [Components/Breadcrumbs](https://docs.optics.rolemodel.design/llms/components-breadcrumbs.md): The breadcrumbs component is used to show the user's current location in a hierarchy of pages.
- [Components/Button](https://docs.optics.rolemodel.design/llms/components-button.md): Button classes can be used on `button` or `a` html elements. They provide consistent and composable styling that should address most applications basic needs.
- [Components/ButtonGroup](https://docs.optics.rolemodel.design/llms/components-buttongroup.md): Button Group is similar to the Segmented Control component, however it has a different semantic purpose. Button Group is intended to be used for grouping rel...
- [Components/Card](https://docs.optics.rolemodel.design/llms/components-card.md): Card classes can be used to denote bordered sections of an application. They provide simple styles to create sections or "cards" for your interface. They can...
- [Components/Confirm Dialog](https://docs.optics.rolemodel.design/llms/components-confirm-dialog.md): The Confirm Dialog classes can be used for styling a custom alert or confirm dialog. This can be used alongside [Turbo Confirm](https://github.com/RoleModel/...
- [Components/Content Header](https://docs.optics.rolemodel.design/llms/components-content-header.md): Content Header classes can be used to denote a page or content section header of an application. They provide simple styles to provide context and actions fo...
- [Components/Divider](https://docs.optics.rolemodel.design/llms/components-divider.md): Divider classes can be used to create horizontal or vertical visual divides between content.
- [Components/Form](https://docs.optics.rolemodel.design/llms/components-form.md): Form classes can be used on a variety of `inputs` or `select` HTML elements. They provide consistent and composable styling that should address most applicat...
- [Components/Icon](https://docs.optics.rolemodel.design/llms/components-icon.md): Icon classes are built on top of [Google's Material Symbols Icon Font](https://fonts.google.com/icons). They provide a way to integrate iconography into your...
- [Components/Modal](https://docs.optics.rolemodel.design/llms/components-modal.md): The Modal classes can be used for styling a custom modal. This can be used alongside the Rails configuration and Javascript implemented by [RoleModel Rails M...
- [Components/Navbar](https://docs.optics.rolemodel.design/llms/components-navbar.md): Navbar classes provide simple styling for a navigation header.
- [Components/Pagination](https://docs.optics.rolemodel.design/llms/components-pagination.md): Pagination is used to navigate through a series of pages, typically when dealing with tabular data. A few classes are used in combination with the button com...
- [Components/Segmented Control](https://docs.optics.rolemodel.design/llms/components-segmented-control.md): Segmented Control classes can be used to create a stylized radio select group.
- [Components/Sidebar](https://docs.optics.rolemodel.design/llms/components-sidebar.md): Sidebar classes provide simple styling for a navigation sidebar drawer, compact, or rail.
- [Components/SidePanel](https://docs.optics.rolemodel.design/llms/components-sidepanel.md): Side Panel classes provide simple styling for a panel of sections with a scrollable body.
- [Components/Spinner](https://docs.optics.rolemodel.design/llms/components-spinner.md): Spinners are CSS loading indicators that should be shown when retrieving data or performing slow computations.
- [Components/Switch](https://docs.optics.rolemodel.design/llms/components-switch.md): Switch classes can be used to create a stylized checkbox or boolean input.
- [Components/Tab](https://docs.optics.rolemodel.design/llms/components-tab.md): Tab classes provide simple styling for a tab group navigation.
- [Components/Table](https://docs.optics.rolemodel.design/llms/components-table.md): Table classes provide simple styling for tables and their content.
- [Components/Tag](https://docs.optics.rolemodel.design/llms/components-tag.md): The tag component can be applied to an element with a button within it. The Tag component is similar to the Badge component, however it has a different seman...
- [Components/Text Pair](https://docs.optics.rolemodel.design/llms/components-text-pair.md): The Text Pair component is used to display a title and subtitle together. It can also be used to group other elements within it, though should generally be r...
- [Components/Tooltip](https://docs.optics.rolemodel.design/llms/components-tooltip.md): Tooltips are build using data attributes on any element. Setting these will show text on hover.
## Recipes
- [Recipes/Aligned Header](https://docs.optics.rolemodel.design/llms/recipes-aligned-header.md): There are cases when you want to vertically center something on a line of text that wraps. Like a badge or edit button at the end of a text header. Achieving...
- [Recipes/Custom Sidebar](https://docs.optics.rolemodel.design/llms/recipes-custom-sidebar.md): Your app may want to customize the sidebar to change the look and feel. Here are a few examples to help you get started:
- [Recipes/Layout](https://docs.optics.rolemodel.design/llms/recipes-layout.md): Optics provides two patterns for application layout. The basic (legacy) version is maintained for backwards compatibility, but all new projects should use th...
---
# Optics
A RoleModel Design System.
v{packageData.version}
[](https://github.com/RoleModel/optics)
[](https://github.com/RoleModel/optics/blob/main/LICENSE)
[](https://www.npmjs.com/package/@rolemodel/optics)
[](https://github.com/RoleModel/optics/actions/workflows/linting.yml)
Optics embodies the RoleModel ethos of deep collaboration, uniting our team's diverse expertise with the shared
goal of crafting excellent design solutions and our commitment to Character, Collaboration, and Craftsmanship.
Learn About The Vision Behind Optics
open_in_new
Optics is a CSS package that provides base styles and components that can be integrated and customized in a variety of projects.
## Installation
### NPM
```sh
npm install @rolemodel/optics
```
### Yarn
```sh
yarn add @rolemodel/optics
```
## Getting Started
### Importing with a compiler
You can add this import to the top of your root level `css` file.
```css
@import '@rolemodel/optics'; /* Using webpack to compile */
/* Or */
@import '@rolemodel/optics/dist/css/optics'; /* Using a different compiler */
/* Or */
@import '@rolemodel/optics/dist/css/optics+no_icons'; /* Don't load the default icons library */
/* Or */
@import '@rolemodel/optics/dist/css/optics.min.css'; /* If you want a single file with all the styles in it. */
/* Or */
@import '@rolemodel/optics/dist/css/optics+phosphor_icons.css'; /* Using a different icon pack */
/* Or */
@import '@rolemodel/optics/dist/css/optics+phosphor_icons.min.css'; /* If you want a single file with all the styles in it and a different icon pack. */
```
### Importing without a compiler
To use Optics without compilation, use a CDN like [jsDelivr](https://www.jsdelivr.com/) or [unpkg](https://unpkg.com/).
Add a link in your HTML head or an `@import` to the top of your root level `css` file.
```html
```
```css
@import 'https://cdn.jsdelivr.net/npm/@rolemodel/optics@[desired version]/dist/css/optics.min.css';
```
Note: You can use this method to use Optics with [CodePen](https://codepen.io/). In a CodePen project, go to `Settings > CSS`, find the section for adding external stylesheets, and add the CDN link as a resource.
## Browser Support
Optics aims to follow [Baseline](https://web.dev/baseline) for browser support.
While **Widely available** — interoperable across all major browsers for 30 months is the goal, we currently sit at **Newly available** — interoperable across all major browsers for 24 months (as of July 2026).
Chrome
Edge
Firefox
Safari
iOS Safari
123
123
128
17.5
17.5
---
# Addons
[Source Code](https://github.com/RoleModel/optics/blob/main/src/addons)
Optics provides a few addons for integrating Third-Party tools with your application.
## Icon Fonts
### Material Symbols Outlined
Optics ships with a simplified version of [Material Symbols Outlined](https://fonts.google.com/icons?icon.style=Outlined). It only includes the font weight variable aspect of the icon library which means you won't be able to utilize the fill, or emphasis properties.
This is a trade-off for a smaller file size which reduces page load "flash-in" where icons are blank until the font has loaded.
This flash has been mitigated some by using the `font-display: block;` property on the font face to hide the underlying text until loaded as well as a fixed size to prevent layout shift.
If your app does want to use the full Material Symbols Outlined library, you can import the full library by using the addon shown below.
This will increase the page load time but will allow you to use the full capabilities of the icon library.
### Additional Icon libraries
Optics supports alternative icon libraries. It currently supports
- [Phosphor](https://phosphoricons.com/)
- [Tabler](https://tabler.io/icons)
- [Feather](https://feathericons.com/)
- [Lucide](https://lucide.dev/icons/)
These can be imported alongside the base design system to provide additional icon options. They can also be integrated with the base design system instead of as an addon if you don't want to use the default Material Symbols Outlined icons. This will reduce the page load time by not loading the Material Symbols Outlined icons.
Note: This alternate import approach (optics+icon_library) supports the minified versions as well. Just add `.min.css` to the end of the file name.
For more information on how to use these icons, see the [Icon Component](components-icon.md).
```css
/* Full Material Symbols Outlined Package */
@import '@rolemodel/optics';
@import '@rolemodel/optics/dist/css/addons/fonts/material_symbols_outlined_variable';
/* Or */
@import '@rolemodel/optics/dist/css/optics+material_symbols_outlined_variable';
/* Phosphor Icons */
@import '@rolemodel/optics';
@import '@rolemodel/optics/dist/css/addons/fonts/phosphor_icons';
/* Or */
@import '@rolemodel/optics/dist/css/optics+phosphor_icons';
/* Tabler Icons */
@import '@rolemodel/optics';
@import '@rolemodel/optics/dist/css/addons/fonts/tabler_icons';
/* Or */
@import '@@rolemodel/optics/dist/css/optics+tabler_icons';
/* Feather Icons */
@import '@rolemodel/optics';
@import '@rolemodel/optics/dist/css/addons/fonts/feather_icons';
/* Or */
@import '@rolemodel/optics/dist/css/optics+feather_icons';
/* Lucide Icons (a fork of feather with more icons) */
@import '@rolemodel/optics';
@import '@rolemodel/optics/dist/css/addons/fonts/lucide_icons';
/* Or */
@import '@rolemodel/optics/dist/css/optics+lucide_icons';
```
## Tom Select
[Tom Select](https://tom-select.js.org/) is a dynamic, framework agnostic, and lightweight (~16kb gzipped) `` UI control. With autocomplete and native-feeling keyboard navigation, it's useful for tagging, contact lists, country selectors, and so on.
If your application uses Tom Select, you can import the styles from Tom Select along with the Design Systems tokens applied to it by placing this after importing the base design system.
```css
@import '@rolemodel/optics';
@import 'tom-select/dist/css/tom-select';
@import '@rolemodel/optics/dist/css/addons/tom-select';
```
## Rails Panel
Panel provide styles that are intended to accompany the rails configuration and javascript implemented by [RoleModel Rails Panel](https://github.com/RoleModel/rolemodel_rails/tree/master/lib/generators/rolemodel/modals) Similar to the Modal Component
If your application uses this implementation, you can import the styles via:
```css
@import '@rolemodel/optics';
@import '@rolemodel/optics/dist/css/addons/panel';
```
---
# Base Reset
All browsers ship with some default styles. These styles are inconsistent across browsers and can cause issues when building a UI. To ensure consistency across browsers, we use [Modern CSS Reset](https://github.com/Andy-set-studio/modern-css-reset) to remove all default styles.
You can read more about the why behind it here [A Modern CSS Reset](https://andy-bell.co.uk/a-modern-css-reset/)
---
# File Organization
As you use Optics, you will likely want to organize your Optics configuration into multiple files.
## Folder Structure
The recommended folder structure is to have a `main or application` file that is the root file. This file should import all of the other files in the folder.
- `/stylesheets`
- `application.css`
- `/core`
- `/theme`
- `{name}-theme-core.css`
- `{name}-theme-light.css`
- `{name}-theme-dark.css`
- `base.css`
- `layout.css`
- `utilities.css`
- `/vendors`
- `{vendor-name}-overrides.css`
- `/components`
- `/optics-overrides`
- `{component-name}.css`
- `{component-name}.css`
- `/general`
- `{general-name}.css`
## Import Structure
Using the above folder structure, the application file should import all of the other files. Comments can be used to describe the purpose of each section of files.
```css
/* Optics */
@import '@rolemodel/optics';
/* Vendors */
@import 'something-from-node-modules/something';
/* Font Customization */
@import 'core/fonts/text_fonts';
@import 'core/fonts/icon_fonts';
/* Theme Customization */
@import 'core/theme/{name}-theme-core';
@import 'core/theme/{name}-theme-light';
@import 'core/theme/{name}-theme-dark';
/* Core Customization */
@import 'core/base';
@import 'core/layout';
@import 'core/utilities';
/* Vendor Customization */
@import 'vendors/{vendor-name}-overrides';
/* Optics Component Customization */
@import 'components/optics-overrides/{component-name}';
/* Component */
@import 'components/{component-name}';
/* General Styles */
@import 'general/{general-name}';
```
---
# Scale Overriding
There are multiple scales in Optics. Unit Scales exist to allow adjusting font and spacing values. Color Scales exist to provide semantically named color variables with corresponding "on" values that strive to maintain contrast when used on an element with the matching color.
## Unit Scale Overriding
A Unit Scale is defined for both font sizes and spacing variables. All values are multiplied by their respective units which default as `1rem` (equivalent to `10px`)
If you want to change the font or spacing scale globally, or within the context of a specific component, you can set the `--op-space-scale-unit` in the `:root`.
```css
:root {
--op-space-scale-unit: 0.5rem;
}
```
```css
:root {
--op-font-scale-unit: 0.5rem;
}
```
```css
:root {
--op-size-unit: 0.2rem;
}
```
## Color Scale Overriding
There are multiple reasons your application may need to override the provided color scales. You may set a primary color that doesn't work well with the default semantic color scale provided. Your design may want to stray from the present plus or minus stops.
Regardless of the reason, you can customize and override each scale like the following example:
```css
:root {
--op-color-primary-h: 164;
--op-color-primary-s: 100%;
--op-color-primary-l: 50%;
/* Main Scale */
--op-color-primary-plus-two: light-dark(
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 64%),
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 32%)
);
--op-color-primary-plus-one: light-dark(
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 45%),
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 35%)
);
/* On Scale */
--op-color-primary-on-plus-two: light-dark(
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 16%),
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 80%)
);
--op-color-primary-on-plus-two-alt: light-dark(
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 6%),
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 92%)
);
--op-color-primary-on-plus-one: light-dark(
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 100%),
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 80%)
);
--op-color-primary-on-plus-one-alt: light-dark(
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 95%),
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 98%)
);
}
```
You can override as many or as few variables or scales as your application needs.
---
# Selective Imports
By default, when you import the design system, it will include the basics. CSS reset, All Tokens, Base styles, Utilities, and all Components.
```css
@import '@rolemodel/optics';
/* or */
@import '@rolemodel/optics/dist/css/optics';
```
If your application doesn't need all styles provided, you can import only the files you need like this:
```css
/* Third party Vendors */
@import 'modern-css-reset/dist/reset';
/* Fonts */
@import 'core/fonts';
/* Tokens */
@import 'core/tokens';
/* Base styles and utilities */
@import 'core/base';
@import 'core/layout';
@import 'core/utilities';
/* Just the button and card Components */
@import 'components/button';
@import 'components/card';
```
Or this:
```css
/* Third party Vendors */
@import 'modern-css-reset/dist/reset';
/* No Material Icons */
@import 'core/fonts/text_fonts';
/* Tokens */
@import 'core/tokens';
/* Base styles and utilities */
@import 'core/base';
@import 'core/layout';
@import 'core/utilities';
/* Components */
@import 'components';
```
## Dependencies
Some components rely on other components for their usage. Each document page describes these dependencies. Additionally, here is a visualization of all dependencies:
---
# Themes
Optics defines a default theme along with it's dark mode.
If you import the design system, it will be used automatically.
## Dark Mode
By default, Dark mode will automatically apply when your system is set to dark mode.
You can control the theme mode manually by setting a data attribute on the root html element to either `light` or `dark`.
This will ignore the system preference and use specified theme mode (I.E. your application doesn't need a dark mode).
```html
...
```
The theme mode can also be controlled within an individual component, rather than at the app level. This can be done by using the following attribute:
```css
.my-component {
color-scheme: only light;
/*
Options:
color-scheme: light dark;
color-scheme: only light;
color-scheme: only dark;
*/
background-color: var(--op-color-primary-plus-one);
color: var(--op-color-primary-on-plus-one);
}
```
See the [Color Scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/color-scheme) and [light-dark()](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/light-dark) for more information.
## Theming
If you want to customize your application, you can provide your own theme files that serve as overrides to the existing tokens.
An example implementation your main css file would look like:
```css
@import '@rolemodel/optics';
@import 'stylesheets/theme/my_app_theme';
```
Your custom theme can change any tokens, including colors, radius, fonts, even redefine the luminosity and semantic scales. It generally will look like:
```css
@import url('https://fonts.googleapis.com/css2?family=Coming+Soon&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Grandstander:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
:root {
/* Colors */
--op-color-primary-h: my-new-value;
--op-color-primary-s: my-new-value;
--op-color-primary-l: my-new-value;
/* Color Scale */
--op-color-primary-plus-two: light-dark(
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 64%),
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 32%)
);
/* Fonts */
--op-font-family: 'Coming Soon', sans-serif;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme-mode='light']) {
--op-font-family: 'Grandstander', sans-serif;
}
}
:root[data-theme-mode='dark'] {
--op-font-family: 'Grandstander', sans-serif;
}
```
## Dynamic Themes
Your application can have multiple predefined themes which can be switched between by setting a data attribute on the root html element.
The theme can be created in a similar way to default theme overriding with the exception of a rule on when it is applied.
This theme would always be included in your application, but only activate when setting the data attribute.
```html
...
```
```css
@import url('https://fonts.googleapis.com/css2?family=Coming+Soon&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Grandstander:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap');
:root[data-theme='example'] {
/* Colors */
--op-color-primary-h: my-new-value;
--op-color-primary-s: my-new-value;
--op-color-primary-l: my-new-value;
/* Color Scale */
--op-color-primary-plus-two: light-dark(
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 64%),
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 32%)
);
/* Fonts */
--op-font-family: 'Coming Soon', sans-serif;
}
@media (prefers-color-scheme: dark) {
:root[data-theme='example']:not([data-theme-mode='light']) {
/* Fonts */
--op-font-family: 'Grandstander', sans-serif;
}
}
:root[data-theme='example'][data-theme-mode='dark'] {
/* Fonts */
--op-font-family: 'Grandstander', sans-serif;
}
```
Dynamic themes also support both light and dark mode and can be manually controlled with data attributes.
```html
...
```
---
# Tokens
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens)
Tokens are defined in `src/core/tokens`
- All core tokens are defined in `src/core/tokens/base_tokens.css`
- Color scale tokens are defined in `src/core/tokens/scale_color_tokens.css`
There are also a few component specific tokens that are defined in their respective component file, but those are not intended to be global or used outside of that file.
There is a JSON file in `docs/token_structure.json` that lists all the current tokens in one place and shows how the names indicate organization.
## Token Naming Structure
All tokens follow a standard naming structure.
This structure should be followed for any new tokens added to provide consistency.
`--prefix-category-sub-category-variant-qualifier-variant: value`
--
prefix
-
category
-
sub category (optional)
-
variant qualifier (optional)
-
variant
:
value
### Examples
--
op
-
color
-
primary
-
on
-
plus-one
:
value
--
op
-
font-size
-
large
:
value
--
op
-
shadow
-
x
-
small
:
value
--
op
-
border
-
bottom
:
value
### Explanation
#### prefix - is a namespace prefix to indicate the source of the token.
- `op` - All tokens in Optics are prefixed with `op`
- `ya` - Your App. Any tokens that your app is adding can be prefixed to prevent collisions with Optics tokens or other Third Party tokens.
#### category - indicates the category of the token
- `color` - color token
- `font` - font token
- `space` - space token
- `border` - border token
- `shadow` - shadow token
- etc.
#### sub category - indicates a sub category of the token
- `size` - indicates a token that is a size, in our case a sub category of font
- `weight` - indicates a token that is a font weight, in our case a sub category of font
- etc.
#### variant qualifier - indicates a qualification of the variant
- `3x` - three times extra
- `2x` - two times extra
- `x` - active
- etc.
#### variant - indicates a specific variant of the token
- `small` - indicates a small variant of the token
- `medium` - indicates a medium variant of the token
- `large` - indicates a large variant of the token
- etc.
### Component Specific Token Naming Structure
Sometimes a component will have a token that is specific to that component. In these cases, a slightly different pattern is used.
The Component name becomes the category and in some cases, the sub category.
`--prefix-component-name-sub-name-variant-qualifier-variant: value`
--
prefix
-
component name
-
sub name (optional)
-
variant qualifier (optional)
-
variant
:
value
Additionally, components may implement a "public" and "private" API of tokens. These are internal to the component and intended to provide an easy to use interface for customizing the component.
The "Private" API is not meant to be set by the user, but rather is used internally by the component.
These tokens follow a structure like `--__prefix-component-name-sub-name-variant-qualifier-variant: value`
The "Public" API is meant to be set as a way to customize the component.
These tokens follow a structure like `--_prefix-component-name-sub-name-variant-qualifier-variant: value`
---
# Animation
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
Animation and Transition tokens can be used for element transitions or animations.
## Playground
```html
input (120ms) Hover Me!
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `speed` | `"input (120ms)"` | `accordion (120ms)`, `accordion_content (300ms)`, `input (120ms)`, `sidebar (200ms)`, `modal (300ms)`, `panel (400ms)` | |
## Usage
These tokens can be applied as a transition.
```css
transition: var(--op-transition-input);
/* or */
animation: var(--op-animation-flash);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-transition-accordion` | `rotate 120ms ease-in` |
| `--op-transition-accordion-content` | `height 300ms ease, content-visibility 300ms ease allow-discrete` |
| `--op-transition-input` | `all 120ms ease-in` |
| `--op-transition-sidebar` | `all 200ms ease-in-out` |
| `--op-transition-modal-time` | `300ms` |
| `--op-transition-modal` | `all var(--op-transition-modal-time) ease-in` |
| `--op-transition-panel` | `right 400ms ease-in` |
| `--op-transition-tooltip` | `all 300ms ease-in 300ms` |
| Token | Value |
| --- | --- |
| `--op-animation-flash` | `rm-slide-in-out-flash 5s normal forwards` |
---
# Border Radius
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
Border radius tokens can be used to round corners on various elements.
## Usage
These tokens can be applied with or without an actual border on the element.
```css
border-radius: var(--op-radius-small);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-radius-small` | `2px` |
| `--op-radius-medium` | `4px` |
| `--op-radius-large` | `8px` |
| `--op-radius-x-large` | `12px` |
| `--op-radius-2x-large` | `16px` |
| `--op-radius-circle` | `50%` |
| `--op-radius-pill` | `9999px` |
---
# Border Stroke
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
Border tokens can be used as box shadows to add borders to various elements. Box Shadows are used in order to provide border styling without affecting the sizing of elements.
These can be composed with other box shadows such as [Shadow](tokens-shadow.md) to stack effects.
## Usage
These tokens can be applied as a box shadow with any color you wish.
```css
box-shadow: var(--op-border-all) var(--op-color-border);
/* or */
box-shadow: var(--op-border-left) var(--op-color-primary-base);
```
## Inset
`inset` can be prefixed to invert a border.
```css
box-shadow: inset var(--op-border-all) var(--op-color-border);
/* or */
box-shadow: inset var(--op-border-left) var(--op-color-primary-base);
```
Due to how box shadows are implemented, insetting can cause seemingly strange behavior.
Insetting a left border will move it to the right, and insetting a top border will move it to the bottom. The same applies for right and bottom.
Insetting the x and y borders is currently **not supported**. You can achieve this manually, but it requires defining the box shadow yourself.
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-border-none` | `0 0 0 0` |
| `--op-border-all` | `0 0 0 var(--op-border-width)` |
| `--op-border-top` | `0 calc(-1 * var(--op-border-width)) 0 0` |
| `--op-border-right` | `var(--op-border-width) 0 0 0` |
| `--op-border-bottom` | `0 var(--op-border-width) 0 0` |
| `--op-border-left` | `calc(-1 * var(--op-border-width)) 0 0 0` |
| `--op-border-y` | `var(--op-border-top) var(--op-color-border), var(--op-border-bottom) var(--op-color-border)` |
| `--op-border-x` | `var(--op-border-left) var(--op-color-border), var(--op-border-right) var(--op-color-border)` |
---
# Border Width
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
Border width tokens can be used to define a border width or a box shadow width.
## Usage
These tokens can be applied with a border or box shadow.
```css
border-width: 0 0 0 var(--op-border-width);
/* or */
box-shadow: 0 0 0 var(--op-border-width);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-border-width` | `1px` |
| `--op-border-width-large` | `2px` |
| `--op-border-width-x-large` | `4px` |
---
# Breakpoint
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
Breakpoint tokens are used to define common device sizes for use within media queries or max widths.
They are implemented in two ways. First as CSS custom properties (css variables) and second as guided pixel assignments.
The CSS variables can be used like any of the other tokens for things requiring calculations or max widths.
The guided pixel assignments can be used for media queries.
Custom properties (css variables) currently cannot be used in a media query since they get defined in an element scope (`:root` in our case).
Media queries exist at the document level and therefore cannot access custom properties.
[CSS ENV Variables](https://drafts.csswg.org/css-env-1/) aims at addressing this by allowing variables at the global document level.
For common breakpoints, define the variables in the `:root` as a comment block. When using them, use the pixel value, but include a comment above with the named breakpoint. This makes it searchable and provide a bit of intention to what the value means.
## Usage
These token values can be applied in a media query to create responsive behavior.
```css
.small-area {
max-inline-size: var(--op-breakpoint-small);
}
:root {
/*
Breakpoints
These breakpoint values will be used as a guide for media queries.
Annotate the uses with a comment above referring to the variable being referenced.
--op-breakpoint-medium: 1024px;
...
*/
}
/* --op-breakpoint-medium */
@media (width > 1024px) {
background-color: var(--op-color-primary-base);
color: var(--op-color-primary-on-base);
}
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-breakpoint-x-small` | `512px` |
| `--op-breakpoint-small` | `768px` |
| `--op-breakpoint-medium` | `1024px` |
| `--op-breakpoint-large` | `1280px` |
| `--op-breakpoint-x-large` | `1440px` |
---
# Basic Color
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
Basic color tokens can be used to define exact colors.
The background colors use the color scale and will adjust in dark mode.
## Usage
These tokens can be applied to anything that supports color.
```css
body {
background-color: var(--op-color-background);
color: var(--op-color-on-background);
}
/* or */
color: var(--op-color-white);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-color-white` | `hsl(0deg 100% 100%)` |
| `--op-color-black` | `hsl(0deg 0% 0%)` |
---
# Border Color
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
Border color tokens can be used to define the color of borders and box shadows.
## Usage
These tokens can be applied with a border or box shadow.
```css
border-color: var(--op-color-border);
/* or */
box-shadow: var(--op-border-top) var(--op-color-border);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-color-border` | `var(--op-color-neutral-plus-five)` |
---
# Color Scales
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/scale_color_tokens.css)
Optics has five main color scales that provide all the color your application may need. These Consist of the `Primary` scale, the `Neutral` scale, and four Alert Color Scales, `Warning`, `Danger`, `Info`, and `Notice`.
Each scale is a set of semantically named variables that use the same hue and saturation, but change the luminosity.
We borrow from the photography concept of [Aperture f-stops](https://www.adobe.com/creativecloud/photography/discover/f-stop.html).
`Plus` indicates the addition of luminosity or getting brighter. `Minus` indicates the removal of luminosity or getting darker.
We start with a base color and include a plus one through eight and max (full luminosity a.k.a white), as well as minus one through eight and max (zero luminosity a.k.a black).
Along with this set of 19 (base, plus 1-8, plus max, minus 1-8, minus max) semantic `stops`, there are corresponding `on` colors for each.
These `on` colors are aimed to provide contrast respecting text colors for text on a background of that color. There are also `alt` colors to provide an additional text color option to add variety and more color options.
Here is an example of what these variables look like:
```css
--op-color-primary-plus-four: light-dark(
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 84%),
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 24%)
);
--op-color-primary-on-plus-four: light-dark(
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 24%),
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 84%)
);
--op-color-primary-on-plus-four-alt: light-dark(
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 4%),
hsl(var(--op-color-primary-h) var(--op-color-primary-s) 44%)
);
```
An element using the `var(--op-color-primary-plus-four)` for the background color could use `var(--op-color-primary-on-plus-four)` or `var(--op-color-primary-on-plus-four-alt)` for the text color.
`var(--op-color-primary-original)` is included for occasions when you need to stay true to your brand color.
## Playground
```html
Background: Primary Base
Text: Primary On Base
Alt: Primary On Base Alt
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `scale` | `"primary"` | `primary`, `neutral`, `alerts-warning`, `alerts-danger`, `alerts-info`, `alerts-notice` | |
| `step` | `"base"` | `plus-max`, `plus-eight`, `plus-seven`, `plus-six`, `plus-five`, `plus-four`, `plus-three`, `plus-two`, `plus-one`, `base`, `minus-one`, `minus-two`, `minus-three`, `minus-four`, `minus-five`, `minus-six`, `minus-seven`, `minus-eight`, `minus-max` | |
## Dark Mode
Each scale supports a [Dark Mode](overview-themes.md#dark-mode)
## Reference
You can use the Light / Dark toggle control in the top left corner to show these colors in each mode.
### Base Colors
_Full scale definitions: [scale_color_tokens.css](https://github.com/RoleModel/optics/blob/main/src/core/tokens/scale_color_tokens.css)_
### Scales
_Full scale definitions: [scale_color_tokens.css](https://github.com/RoleModel/optics/blob/main/src/core/tokens/scale_color_tokens.css)_
## Overriding Color Scales
See [Color Scale Overriding](overview-scale-overriding.md#color-scale-overriding) for guidance on overriding each color scale.
## Custom Scale
Your application may need a new scale. To add one, use the following template. Keep in mind, you will also need to add dark mode values for each variable as well. See [Theming](overview-themes.md#theming)
```css
:root {
/* {name}-color */
--op-color-{name}-h: new-value-h;
--op-color-{name}-s: new-value-s;
--op-color-{name}-l: new-value-l;
/* {name}-semantic-scale */
--op-color-{name}-original: hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) var(--op-color-{name}-l));
/* Main Scale */
--op-color-{name}-plus-max: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 100%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 10%)
);
--op-color-{name}-plus-eight: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 98%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 18%)
);
--op-color-{name}-plus-seven: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 96%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 16%)
);
--op-color-{name}-plus-six: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 94%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 14%)
);
--op-color-{name}-plus-five: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 90%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 10%)
);
--op-color-{name}-plus-four: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 84%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 14%)
);
--op-color-{name}-plus-three: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 70%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 10%)
);
--op-color-{name}-plus-two: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 64%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 14%)
);
--op-color-{name}-plus-one: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 45%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 15%)
);
--op-color-{name}-base: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 40%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 10%)
);
--op-color-{name}-minus-one: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 36%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 16%)
);
--op-color-{name}-minus-two: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 32%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 12%)
);
--op-color-{name}-minus-three: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 28%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 8%)
);
--op-color-{name}-minus-four: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 24%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 4%)
);
--op-color-{name}-minus-five: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 20%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 5%)
);
--op-color-{name}-minus-six: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 16%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 6%)
);
--op-color-{name}-minus-seven: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 8%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 88%)
);
--op-color-{name}-minus-eight: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 4%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 84%)
);
--op-color-{name}-minus-max: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 0%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 80%)
);
/* On Scale */
--op-color-{name}-on-plus-max: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 0%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 100%)
);
--op-color-{name}-on-plus-max-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 20%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 80%)
);
--op-color-{name}-on-plus-eight: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 4%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 40%)
);
--op-color-{name}-on-plus-eight-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 24%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 84%)
);
--op-color-{name}-on-plus-seven: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 8%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 88%)
);
--op-color-{name}-on-plus-seven-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 28%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 88%)
);
--op-color-{name}-on-plus-six: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 16%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 76%)
);
--op-color-{name}-on-plus-six-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 26%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 96%)
);
--op-color-{name}-on-plus-five: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 20%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 60%)
);
--op-color-{name}-on-plus-five-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 40%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 90%)
);
--op-color-{name}-on-plus-four: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 24%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 94%)
);
--op-color-{name}-on-plus-four-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 4%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 74%)
);
--op-color-{name}-on-plus-three: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 20%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 70%)
);
--op-color-{name}-on-plus-three-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 10%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 90%)
);
--op-color-{name}-on-plus-two: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 16%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 46%)
);
--op-color-{name}-on-plus-two-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 6%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 76%)
);
--op-color-{name}-on-plus-one: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 100%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 0%)
);
--op-color-{name}-on-plus-one-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 95%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 5%)
);
--op-color-{name}-on-base: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 100%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 10%)
);
--op-color-{name}-on-base-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 88%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 8%)
);
--op-color-{name}-on-minus-one: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 94%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 4%)
);
--op-color-{name}-on-minus-one-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 82%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 2%)
);
--op-color-{name}-on-minus-two: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 90%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 10%)
);
--op-color-{name}-on-minus-two-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 78%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 8%)
);
--op-color-{name}-on-minus-three: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 86%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 6%)
);
--op-color-{name}-on-minus-three-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 74%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 4%)
);
--op-color-{name}-on-minus-four: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 84%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 4%)
);
--op-color-{name}-on-minus-four-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 72%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 2%)
);
--op-color-{name}-on-minus-five: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 88%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 8%)
);
--op-color-{name}-on-minus-five-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 78%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 8%)
);
--op-color-{name}-on-minus-six: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 94%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 4%)
);
--op-color-{name}-on-minus-six-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 82%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 2%)
);
--op-color-{name}-on-minus-seven: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 96%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 6%)
);
--op-color-{name}-on-minus-seven-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 84%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 4%)
);
--op-color-{name}-on-minus-eight: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 98%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 8%)
);
--op-color-{name}-on-minus-eight-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 86%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 6%)
);
--op-color-{name}-on-minus-max: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 100%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 10%)
);
--op-color-{name}-on-minus-max-alt: light-dark(
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 88%),
hsl(var(--op-color-{name}-h) var(--op-color-{name}-s) 8%)
);
}
```
---
# Color With Alpha
> **Caution:** Using alpha will impact Accessibility and if misused can also impact performance. Use these suggestions with caution and verify the resulting colors pass Accessibility standards!
There may be a case where you need to use the alpha channel in a color. This can be useful for creating more opaque or transparent looks built directly into a color instead of using the opacity property.
Since colors are based on a scale and provided as tokens, the alpha channel cannot be used directly. There are a few ways to take advantage of it though!
## Alpha Tokens
One option for adding alpha support is to define alpha tokens that can sit alongside the color scale steps. This allows for use across your system in a way that matches the system.
```css
/*
Note the 40% luminoisty matches the --op-color-primary-base luminosity
Note the 100% luminoisty matches the --op-color-primary-on-base luminosity
Note the 88% luminoisty matches the --op-color-primary-on-base-alt luminosity
*/
--op-color-primary-base-alpha-40: hsl(var(--op-color-primary-h) var(--op-color-primary-s) 40% / 40%);
--op-color-primary-on-base-alpha-40: hsl(var(--op-color-primary-h) var(--op-color-primary-s) 100% / 40%);
--op-color-primary-on-base-alt-alpha-40: hsl(var(--op-color-primary-h) var(--op-color-primary-s) 88% / 40%);
```
The downside of this approach is that it can be difficult to manage and can lead to a lot of tokens. It also requires a lot of manual work to create the tokens and keep them in sync with the color scale.
## Color Mix
> **Benefits of this approach:** 1. It can be used at the component level for specific use cases, or globally if you want it available at a higher level.
> 2. It is tied directly to the color scale and will update if the scale if overridden. It does not duplicate luminosity values.
Another option is to use the `color-mix` (see [color-mix()](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/color-mix)) to create a new color with the alpha channel. This allows for more dynamic use of the alpha channel and can be used to create a new color on the fly or at the component level.
```css
%my-component-global {
--_op-my-component-opacity-disabled: calc(var(--op-opacity-disabled) * 100%); /* converts 0.4 to 40% */
--op-my-component-background-color: color-mix(
in srgv,
var(--op-color-primary-base) var(--_op-thing-opacity-disabled),
var(--op-color-primary-plus-max)
);
--op-my-component-color: color-mix(
in srgv,
var(--op-color-primary-on-base) var(--_op-thing-opacity-disabled),
var(--op-color-primary-plus-max)
);
--op-my-component-color-alt: color-mix(
in srgv,
var(--op-color-primary-on-base-alt) var(--_op-thing-opacity-disabled),
var(--op-color-primary-plus-max)
);
background-color: var(--op-my-component-background-color);
color: var(--op-my-component-color);
}
```
---
# Encoded Image
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
Encoded Image tokens are primarily used to create the dropdown arrow on `` elements using the `.form-control` class.
It is a data-encoded URI SVG which can be set as a background image and then positioned as needed.
```html
Option 1
```
## Usage
These tokens can be applied as a background image and the width for position.
```css
background: var(--op-encoded-images-dropdown-arrow) center right no-repeat;
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-encoded-images-dropdown-arrow-width` | `calc( 1.2 * var(--op-space-scale-unit) )` |
| `--op-encoded-images-dropdown-arrow` | `url('data:image/svg+xml` |
| `--op-encoded-images-dropdown-arrow` | `url('data:image/svg+xml` |
| `--op-encoded-images-dropdown-arrow` | `url('data:image/svg+xml` |
---
# Input Focus
Input Focus tokens are used to define a button or form controls focus state.
## Usage
These tokens can be applied to anything that uses a box shadow.
```css
box-shadow: var(--op-input-focus-primary);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-input-inner-focus` | `inset 0 0 0 var(--op-border-width-large)` |
| `--op-input-outer-focus` | `0 0 0 var(--op-border-width-x-large)` |
| `--op-input-focus-primary` | `var(--op-input-inner-focus) var(--op-color-primary-plus-two), var(--op-input-outer-focus) var(--op-color-primary-plus-five)` |
| `--op-input-focus-neutral` | `var(--op-input-inner-focus) var(--op-color-neutral-plus-two), var(--op-input-outer-focus) var(--op-color-neutral-plus-five)` |
| `--op-input-focus-danger` | `var(--op-input-inner-focus) var(--op-color-alerts-danger-plus-two), var(--op-input-outer-focus) var(--op-color-alerts-danger-plus-five)` |
| `--op-input-focus-warning` | `var(--op-input-inner-focus) var(--op-color-alerts-warning-plus-two), var(--op-input-outer-focus) var(--op-color-alerts-warning-plus-five)` |
| `--op-input-focus-info` | `var(--op-input-inner-focus) var(--op-color-alerts-info-plus-two), var(--op-input-outer-focus) var(--op-color-alerts-info-plus-five)` |
| `--op-input-focus-notice` | `var(--op-input-inner-focus) var(--op-color-alerts-notice-plus-two), var(--op-input-outer-focus) var(--op-color-alerts-notice-plus-five)` |
---
# Input Height
Input Height tokens are used to define a button or form controls height.
## Usage
These tokens can be applied to anything that requires a users input and needs a height (block-size).
```css
block-size: var(--op-input-height-large);
/* or */
max-block-size: var(--op-input-height-small);
/* or */
min-block-size: var(--op-input-height-medium);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-input-height-small` | `2.8rem` |
| `--op-input-height-medium` | `3.6rem` |
| `--op-input-height-large` | `4rem` |
| `--op-input-height-x-large` | `8.4rem` |
---
# Opacity
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
Opacity tokens can be used to create a faded or disabled effect on any element.
## Usage
These tokens can be applied as opacities.
```css
opacity: var(--op-opacity-disabled);
/* or */
opacity: var(--op-opacity-full);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-opacity-none` | `0` |
| `--op-opacity-overlay` | `0.2` |
| `--op-opacity-disabled` | `0.4` |
| `--op-opacity-half` | `0.5` |
| `--op-opacity-full` | `1` |
---
# Shadow
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
Shadow tokens can be used to create an elevation effect on any element. There are also [Card classes](components-card.md#shadow) to create an elevated card effect.
## Usage
These tokens can be applied as box shadows.
```css
box-shadow: var(--op-shadow-x-small);
/* or */
box-shadow: var(--op-shadow-x-large);
```
## Available tokens and their definitions
### Light Mode
| Token | Value |
| --- | --- |
| `--op-shadow-x-small` | `0 1px 2px hsl(0deg 0% 0% / 3%), 0 1px 3px hsl(0deg 0% 0% / 15%)` |
| `--op-shadow-small` | `0 1px 2px hsl(0deg 0% 0% / 3%), 0 2px 6px hsl(0deg 0% 0% / 15%)` |
| `--op-shadow-medium` | `0 4px 8px hsl(0deg 0% 0% / 15%), 0 1px 3px hsl(0deg 0% 0% / 3%)` |
| `--op-shadow-large` | `0 6px 10px hsl(0deg 0% 0% / 15%), 0 2px 3px hsl(0deg 0% 0% / 3%)` |
| `--op-shadow-x-large` | `0 8px 12px hsl(0deg 0% 0% / 15%), 0 4px 4px hsl(0deg 0% 0% / 3%)` |
### Dark Mode
| Token | Value |
| --- | --- |
| `--op-color-background` | `var(--op-color-neutral-plus-eight)` |
| `--op-color-on-background` | `var(--op-color-neutral-on-plus-eight)` |
| `--op-color-on-background-alt` | `var(--op-color-neutral-on-plus-eight-alt)` |
| `--op-shadow-x-small` | `0 1px 3px hsl(0deg 0% 0% / 15%), 0 1px 2px hsl(0deg 0% 0% / 30%)` |
| `--op-shadow-small` | `0 2px 6px hsl(0deg 0% 0% / 15%), 0 1px 2px hsl(0deg 0% 0% / 30%)` |
| `--op-shadow-medium` | `0 4px 8px hsl(0deg 0% 0% / 15%), 0 1px 3px hsl(0deg 0% 0% / 30%)` |
| `--op-shadow-large` | `0 6px 10px hsl(0deg 0% 0% / 15%), 0 2px 3px hsl(0deg 0% 0% / 30%)` |
| `--op-shadow-x-large` | `0 8px 12px hsl(0deg 0% 0% / 15%), 0 4px 4px hsl(0deg 0% 0% / 30%)` |
| `--op-shadow-x-small` | `0 1px 3px hsl(0deg 0% 0% / 15%), 0 1px 2px hsl(0deg 0% 0% / 30%)` |
| `--op-shadow-small` | `0 2px 6px hsl(0deg 0% 0% / 15%), 0 1px 2px hsl(0deg 0% 0% / 30%)` |
| `--op-shadow-medium` | `0 4px 8px hsl(0deg 0% 0% / 15%), 0 1px 3px hsl(0deg 0% 0% / 30%)` |
| `--op-shadow-large` | `0 6px 10px hsl(0deg 0% 0% / 15%), 0 2px 3px hsl(0deg 0% 0% / 30%)` |
| `--op-shadow-x-large` | `0 8px 12px hsl(0deg 0% 0% / 15%), 0 4px 4px hsl(0deg 0% 0% / 30%)` |
---
# Size
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
The Size token enables creating scalable widths (inline-size) and heights (block-size) for your application. It is meant to be used in a `calc` expression with whole numbers. This ensures any sizes you create will be a multiple of 4px.
## Usage
These tokens can be applied like:
```css
block-size: calc(11 * var(--op-size-unit)); /* 44px */
/* Or */
inline-size: calc(54 * var(--op-size-unit)); /* 216px */
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-size-unit` | `0.4rem` |
The size unit can be overridden if you want to change the scale or size basis. See [scale overriding](overview-scale-overriding.md#unit-scale-overriding)
---
# Spacing Size
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
The Spacing Size tokens enable creating scalable spaces for your application. They can be used for margin, padding, gap, and anything else that is intended for spacing.
## Usage
These tokens can be applied like:
```css
margin-inline-start: var(--op-space-small);
/* Or */
padding-block-start: var(--op-space-medium);
/* Or */
gap: var(--op-space-large);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-space-scale-unit` | `1rem` |
| `--op-space-3x-small` | `calc(var(--op-space-scale-unit) * 0.2)` |
| `--op-space-2x-small` | `calc(var(--op-space-scale-unit) * 0.4)` |
| `--op-space-x-small` | `calc(var(--op-space-scale-unit) * 0.8)` |
| `--op-space-small` | `calc(var(--op-space-scale-unit) * 1.2)` |
| `--op-space-medium` | `calc(var(--op-space-scale-unit) * 1.6)` |
| `--op-space-large` | `calc(var(--op-space-scale-unit) * 2)` |
| `--op-space-x-large` | `calc(var(--op-space-scale-unit) * 2.4)` |
| `--op-space-2x-large` | `calc(var(--op-space-scale-unit) * 2.8)` |
| `--op-space-3x-large` | `calc(var(--op-space-scale-unit) * 4)` |
| `--op-space-4x-large` | `calc(var(--op-space-scale-unit) * 8)` |
The scale unit is also defined and can be used for [scale overriding](overview-scale-overriding.md#unit-scale-overriding)
---
# Font Family
Font Family tokens can be used to change the font used when displaying text.
Optics loads fonts via the Google Fonts CDN. For instructions and further learning, see [Google Fonts](https://fonts.google.com/)
The default font is set to Noto Sans with an alternate option set to Noto Serif.
```css
@import 'https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wdth,wght@0,62.5..100,100..900;1,62.5..100,100..900&family=Noto+Serif:ital,wdth,wght@0,62.5..100,100..900;1,62.5..100,100..900&display=swap';
```
## Playground
```html
Font Family Demo using: Noto Sans
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `family` | `"Noto Sans"` | `Noto Sans`, `Noto Serif`, `Tilt Neon` | |
## Usage
This token can be applied like:
```css
html {
font-family: var(--op-font-family);
}
```
## Variable Fonts
Optics supports variable fonts. Variable fonts are a single font file that contains multiple variations of a font. This allows you to adjust various axes that the font makes available such as the weight, width, slant, and other properties.
Optics uses Noto Sans as a default which has three axes of variations: weight, width, and italic. You can adjust these axes using the font-weight, font-stretch, and font-style tokens.
```css
.my-selector {
font-family: var(--op-font-family); /* Defaults to "Noto Sans" */
font-optical-sizing: {auto|none};
font-weight: {100 to 900}; /* Any value will work, though it is recommended to use the existing weight tokens or define a component specific value. */
/* E.G. font-weight: var(--op-font-weight-bold); */
font-style: {normal|italic};
font-variation-settings:
"wdth" {62.5 to 100};
/* or */
font-stretch: {62.5% to 100%};
}
```
If you are using a custom font, you can adjust the axes of the font by using the font-variation-settings property. The values for the axes are specific to the font you are using. You can find the available axes and their values in the font's documentation.
For example: [Roboto Flex](https://fonts.google.com/specimen/Roboto+Flex) has the following axes.
```css
/*
{uniquifier}: Use a unique and descriptive class name
{weight}: Use a value from 100 to 1000
{grade}: Use a value from -200 to 150
{slant}: Use a value from -10 to 0
{width}: Use a value from 25 to 151
{thick stroke}: Use a value from 27 to 175
{thin stroke}: Use a value from 25 to 135
{counter width}: Use a value from 323 to 603
{uppercase height}: Use a value from 528 to 760
{lowercase height}: Use a value from 416 to 570
{ascender height}: Use a value from 649 to 854
{descender depth}: Use a value from -305 to -98
{figure height}: Use a value from 560 to 788
*/
.roboto-flex-{uniquifier} {
font-family: 'Roboto Flex', sans-serif;
font-optical-sizing: auto;
font-weight: {weight};
font-style: normal;
font-variation-settings:
'slnt' {slant},
'wdth' {width},
'GRAD' {grade},
'XOPQ' {thick stroke},
'XTRA' {counter width},
'YOPQ' {thin stroke},
'YTAS' {ascender height},
'YTDE' {descender depth},
'YTFI' {figure height},
'YTLC' {lowercase height},
'YTUC' {uppercase height};
}
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-font-family` | `'Noto Sans', sans-serif` |
| `--op-font-family-alt` | `'Noto Serif', serif` |
## Custom Font
If you want to change the font used by default, you can add a new font import to your stylesheet and apply it using the font family token.
**Note** Not all fonts have the same baseline line height. This can cause alignment issues in your text that may require you to adjust the default line height tokens. See [Adjusting Line Heights](tokens-typography-line-height.md#custom-font)
```css
@import 'https://fonts.googleapis.com/css2?family=Tilt+Neon:XROT,YROT@-45..45,-45..45&display=swap';
:root {
--op-font-family: 'Tilt Neon', sans-serif;
}
```
## Alternate or Multiple Fonts
Often an application will need multiple fonts. Your headers may use a different font than your body text. Optics provides a main token `--op-font-family` and an alt token `--op-font-family-alt`, but you can easily add your own font tokens by following the pattern.
```css
@import 'https://fonts.googleapis.com/css2?family=Roboto+Flex:opsz,slnt,wdth,wght,GRAD,XOPQ,XTRA,YOPQ,YTAS,YTDE,YTFI,YTLC,YTUC@8..144,-10..0,25..151,100..1000,-200..150,27..175,323..603,25..135,649..854,-305..-98,560..788,416..570,528..760&family=Tilt+Neon:XROT,YROT@-45..45,-45..45&display=swap';
:root {
--op-font-family: 'Tilt Neon', sans-serif;
--op-font-family-alt: 'Roboto Flex', serif;
/* Could add others as needed */
--ya-font-family-body: 'Roboto Flex', serif; /* Your App prefix. Could stick with --op if you want */
}
```
---
# Font Size
Font Size tokens can be used to change the size of text.
## Usage
These tokens can be applied like:
```css
font-size: var(--op-font-large);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-font-scale-unit` | `1rem` |
| `--op-font-2x-small` | `calc(var(--op-font-scale-unit) * 1)` |
| `--op-font-x-small` | `calc(var(--op-font-scale-unit) * 1.2)` |
| `--op-font-small` | `calc(var(--op-font-scale-unit) * 1.4)` |
| `--op-font-medium` | `calc(var(--op-font-scale-unit) * 1.6)` |
| `--op-font-large` | `calc(var(--op-font-scale-unit) * 1.8)` |
| `--op-font-x-large` | `calc(var(--op-font-scale-unit) * 2)` |
| `--op-font-2x-large` | `calc(var(--op-font-scale-unit) * 2.4)` |
| `--op-font-3x-large` | `calc(var(--op-font-scale-unit) * 2.8)` |
| `--op-font-4x-large` | `calc(var(--op-font-scale-unit) * 3.2)` |
| `--op-font-5x-large` | `calc(var(--op-font-scale-unit) * 3.6)` |
| `--op-font-6x-large` | `calc(var(--op-font-scale-unit) * 4.8)` |
The scale unit is also defined and can be used for [scale overriding](overview-scale-overriding.md#unit-scale-overriding)
---
# Font Weight
Font Weight tokens can be used to change the font weight of text.
**Note** When using a [custom font](tokens-typography-font-family.md#custom-font), some of these weights may use the closest available weight since not all fonts support all font weights.
## Usage
These tokens can be applied like:
```css
font-weight: var(--op-font-weight-bold);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-font-weight-thin` | `100` |
| `--op-font-weight-extra-light` | `200` |
| `--op-font-weight-light` | `300` |
| `--op-font-weight-normal` | `400` |
| `--op-font-weight-medium` | `500` |
| `--op-font-weight-semi-bold` | `600` |
| `--op-font-weight-bold` | `700` |
| `--op-font-weight-extra-bold` | `800` |
| `--op-font-weight-black` | `900` |
---
# Letter Spacing
Letter Spacing tokens can be used to change the space between letters of text.
## Usage
These tokens can be applied like:
```css
letter-spacing: var(--op-letter-spacing-label);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-letter-spacing-navigation` | `0.01rem` |
| `--op-letter-spacing-label` | `0.04rem` |
---
# Line Height
Line height tokens can be used to change the line height of text.
## Usage
These tokens can be applied like:
```css
line-height: var(--op-line-height-dense);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-line-height-none` | `0` |
| `--op-line-height-densest` | `1` |
| `--op-line-height-denser` | `1.15` |
| `--op-line-height-dense` | `1.3` |
| `--op-line-height-base` | `1.5` |
| `--op-line-height-loose` | `1.6` |
| `--op-line-height-looser` | `1.7` |
| `--op-line-height-loosest` | `1.8` |
## Custom Font
**Note** When using a [custom font](tokens-typography-font-family.md#custom-font)
Not all fonts have the same baseline line height. This can cause alignment issues in your text that may require you to adjust the default line height tokens. You can do that by overriding these tokens
```css
:root {
--op-line-height-looser: 3;
}
```
---
# Z-Index
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/tokens/base_tokens.css)
Z-Index tokens can be used to define the page z-index of an element.
## Usage
```css
z-index: var(--op-z-index-header);
```
## Available tokens and their definitions
| Token | Value |
| --- | --- |
| `--op-z-index-header` | `500` |
| `--op-z-index-footer` | `500` |
| `--op-z-index-sidebar` | `700` |
| `--op-z-index-dialog` | `800` |
| `--op-z-index-dialog-backdrop` | `801` |
| `--op-z-index-dialog-content` | `802` |
| `--op-z-index-dropdown` | `900` |
| `--op-z-index-alert-group` | `950` |
| `--op-z-index-tooltip` | `1000` |
---
# Cluster
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
The cluster utility provides a simple way to create a wrapping, group of spaced items. It
works with all of the gap and other flex utilities. It is effectively equivalent to using
`.flex .flex-wrap .items-center .gap-md` together. See [Utility Introduction](utilities-introduction.md#higher-order-utilities-vs-components) for more information.
See [Utility Layout](recipes-layout.md#utility) for an example of how clusters
can be used to create more readable flex layouts.
Note: This utility uses the `op` prefix to avoid potential naming conflicts with other CSS frameworks.
This is a pattern we hope to move towards for all utilities in the future.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `cluster` | `true` | | |
| `alignItems` | | `stretch`, `start`, `center`, `end`, `baseline` | |
| `gap` | | `none`, `xxs`, `xs`, `sm`, `md`, `lg`, `xl` | |
## Without
A normal `div` without the cluster utility
```html
```
## Cluster Property
`.op-cluster` Creates a flex cluster.
```html
```
## Align Items Stretch
`.items-stretch` Stretches each item across the cross axis. This is the default alignment and doesn't need to be applied unless you are overriding something set differently.
```html
```
## Align Items Start
`.items-start` places each item at the start of the cross axis.
```html
```
## Align Items Center
`.items-center` places each item at the center of the cross axis.
```html
```
## Align Items End
`.items-end` places each item at the end of the cross axis.
```html
```
## Align Items Baseline
`.items-baseline` places each item at the text baseline of the cross axis.
```html
```
---
# Flank
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
The flank utility provides a simple way to create a horizontal row with an item flanked by another large item. It
works with all of the gap and other flex utilities.
See [Utility Introduction](utilities-introduction.md#higher-order-utilities-vs-components) for more information.
See [Utility Layout](recipes-layout.md#utility) for an example of how flanks
can be used to create more readable flex layouts.
Note: This utility uses the `op` prefix to avoid potential naming conflicts with other CSS frameworks.
This is a pattern we hope to move towards for all utilities in the future.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `flank` | `true` | | |
| `end` | | | |
| `gap` | | `none`, `xxs`, `xs`, `sm`, `md`, `lg`, `xl` | |
| `example` | | | |
## Without
A normal `div` without the flank utility
```html
```
## Flank Property
`.op-flank` Creates a flex row with an item flanked by another large item.
```html
```
## Flank End
`.op-flank.op-flank--end` Flips which side of the container the item is flanked to.
```html
```
## Example Flank
`.op-flank` with an avatar and text pair to demonstrate a common use case.
```html
Jeremy Walton
RoleModel Software
```
`.op-flank.op-flank--end` to show an alternate example.
```html
Jeremy Walton
RoleModel Software
```
---
# Frame
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
The frame utility provides a simple way to constrain content to a consistent aspect ratio. It centers its content
and clips any overflow, so whatever it wraps fills a fixed shape regardless of its intrinsic dimensions.
While it's a natural fit for media like images and videos, the frame isn't limited to them — its primary job is
enforcing the aspect ratio, so it works just as well for cards, map embeds, charts, or any element that should hold
a fixed shape.
See [Utility Introduction](utilities-introduction.md#higher-order-utilities-vs-components) for more information.
See [Card Grid Layout](recipes-layout.md#card-grid) for an example of how frames
can be used to keep media at a consistent aspect ratio within a card grid.
Note: This utility uses the `op` prefix to avoid potential naming conflicts with other CSS frameworks.
This is a pattern we hope to move towards for all utilities in the future.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `frame` | `true` | | |
| `aspect` | | `square`, `landscape`, `portrait`, `4-3`, `3-4`, `3-2`, `2-3` | |
| `inlineSize` | | | |
## Without
A normal `div` without the frame utility
```html
```
## Square
`.op-frame.op-frame--square` Crops media to a 1:1 aspect ratio. This is also the default when no aspect modifier is applied.
```html
```
## Landscape
`.op-frame.op-frame--landscape` Crops media to a 16:9 aspect ratio.
```html
```
## Portrait
`.op-frame.op-frame--portrait` Crops media to a 9:16 aspect ratio.
```html
```
## 4:3
`.op-frame.op-frame--4-3` Crops media to a 4:3 aspect ratio.
```html
```
## 3:4
`.op-frame.op-frame--3-4` Crops media to a 3:4 (inverse of 4:3) aspect ratio.
```html
```
## 3:2
`.op-frame.op-frame--3-2` Crops media to a 3:2 aspect ratio.
```html
```
## 2:3
`.op-frame.op-frame--2-3` Crops media to a 2:3 (inverse of 3:2) aspect ratio.
```html
```
## Custom Inline Size
The `--_op-frame-inline-size` custom property controls the frame's `max-inline-size` (defaults to `100%`).
Set it inline to constrain the frame to a smaller width while preserving its aspect ratio.
```html
```
---
# Grid
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
The grid utility provides a simple way to create a dynamic grid layout. It is primarily intended for simple layouts with a minimum column size, or evenly divided columns from 2 to 6.
See [Utility Introduction](utilities-introduction.md#higher-order-utilities-vs-components) for more information.
Note: This utility uses the `op` prefix to avoid potential naming conflicts with other CSS frameworks.
This is a pattern we hope to move towards for all utilities in the future.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `grid` | `true` | | |
| `gap` | | `none`, `xxs`, `xs`, `sm`, `md`, `lg`, `xl` | |
| `columns` | | | |
## Without
A normal `div` without the grid utility
```html
```
## Two columns
```html
```
## Six columns
```html
```
---
# Split
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
The split utility provides a simple way to push two items apart from each other.
It is effectively equivalent to using `.flex .flex-wrap .items-center .justify-between .gap-md` together.
See [Utility Introduction](utilities-introduction.md#higher-order-utilities-vs-components) for more information.
See [Utility Layout](recipes-layout.md#utility) for an example of how splits
can be used to create more readable flex layouts.
Note: This utility uses the `op` prefix to avoid potential naming conflicts with other CSS frameworks.
This is a pattern we hope to move towards for all utilities in the future.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `split` | `true` | | |
| `alignItems` | | `stretch`, `start`, `center`, `end`, `baseline` | |
| `gap` | | `none`, `xxs`, `xs`, `sm`, `md`, `lg`, `xl` | |
## Without
A normal `div` without the split utility
```html
```
## Split Property
`.op-split` Creates a flex split.
```html
```
## Align Items Stretch
`.items-stretch` Stretches each item across the cross axis. This is the default alignment and doesn't need to be applied unless you are overriding something set differently.
```html
```
## Align Items Start
`.items-start` places each item at the start of the cross axis.
```html
```
## Align Items Center
`.items-center` places each item at the center of the cross axis.
```html
```
## Align Items End
`.items-end` places each item at the end of the cross axis.
```html
```
## Align Items Baseline
`.items-baseline` places each item at the text baseline of the cross axis.
```html
```
---
# Stack
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
The stack utility provides a simple way to create a vertical stack of spaced items. It
works with all of the gap and other flex utilities. It is effectively equivalent to using
`.flex .flex-col .gap-md` together. See [Utility Introduction](utilities-introduction.md#higher-order-utilities-vs-components) for more information.
See [Utility Layout](recipes-layout.md#utility) for an example of how stacks
can be used to create more readable flex layouts.
Note: This utility uses the `op` prefix to avoid potential naming conflicts with other CSS frameworks.
This is a pattern we hope to move towards for all utilities in the future.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `stack` | `true` | | |
| `alignItems` | | `stretch`, `start`, `center`, `end`, `baseline` | |
| `gap` | | `none`, `xxs`, `xs`, `sm`, `md`, `lg`, `xl` | |
## Without
A normal `div` without the stack utility
```html
```
## Stack Property
`.op-stack` Creates a flex stack.
```html
```
## Align Items Stretch
`.items-stretch` Stretches each item across the cross axis. This is the default alignment and doesn't need to be applied unless you are overriding something set differently.
```html
```
## Align Items Start
`.items-start` places each item at the start of the cross axis.
```html
```
## Align Items Center
`.items-center` places each item at the center of the cross axis.
```html
```
## Align Items End
`.items-end` places each item at the end of the cross axis.
```html
```
## Align Items Baseline
`.items-baseline` places each item at the text baseline of the cross axis.
```html
```
---
# Container
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
Container utility classes are used to create a centered content area for your application.
You may need to zoom the demos out depending on your screen size to see the full effect.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `size` | | ``, `sm`, `xs` | |
| `padding` | | ``, `sm`, `md` | |
## Default
`.container` Create a container area set to be the size of `--op-breakpoint-medium` with a padding of `--op-space-large`
```html
```
## Small Size
`.container--sm` Change the container size to `--op-breakpoint-small`
```html
```
## Extra Small Size
`.container--xs` Change the container size to `--op-breakpoint-x-small`
```html
```
## Small Padding
`.container--sm-padding` Change the padding of the container to use the `--op-space-small` token
```html
```
## Medium Padding
`.container--md-padding` Change the padding of the container to use the `--op-space-medium` token
```html
```
---
# Flex
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
Flex utility classes are used to quickly lay out a page using the flex engine.
[CSS Tricks: A Guide to Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) is an excellent resource in understanding how the flexbox layout engine works
[Flexbox Froggy](https://codepip.com/games/flexbox-froggy/) is another excellent resource for practicing your Flexbox knowledge
Note: the `gap-xxs` utility in these examples is not necessary for the flex utilities to work. It is here to distinguish each item.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `flex` | `true` | | |
| `flexDirection` | | `row`, `col` | |
| `flexWrap` | | `no-wrap`, `wrap` | |
| `flexGrowOne` | | | |
| `justifyContent` | | `start`, `center`, `end`, `between`, `around` | |
| `alignItems` | | `stretch`, `start`, `center`, `end`, `baseline` | |
| `alignSelf` | | `auto`, `stretch`, `start`, `center`, `end`, `baseline` | |
## Without
A normal `div` without the flex utility
```html
```
## Flex Property
`.flex` Sets the display property to flex.
```html
```
## Flex Direction Row
`.flex-row` sets the flex axis to row. This is the default direction of a flex container and doesn't need to be applied unless you are overriding something that is set to column.
```html
```
## Flex Direction Column
`.flex-col` sets the flex axis to column. This will affect all justify and align properties.
```html
```
## Flex Wrap
`.flex-wrap` Tells the flex container to wrap items if too large.
```html
```
## Flex No Wrap
`.flex-no-wrap` Forces the flex container to not wrap items if too large.
```html
```
## Flex Grow
`.flex-grow-1` can be added to an item within a flex container to force it to take up as much space as is available.
```html
```
## Justify Content Start
`.justify-start` justifies the contents to the start of the flex axis. This is the default justification of a flex container and doesn't need to be applied unless you are overriding something set differently.
```html
```
## Justify Content Center
`.justify-center` justifies the contents to the center of the flex axis.
```html
```
## Justify Content End
`.justify-end` justifies the contents to the end of the flex axis.
```html
```
## Justify Content Between
`.justify-between` justifies the contents to spread evenly across the flex axis with spacing in between each item.
```html
```
## Justify Content Around
`.justify-around` justifies the contents to spread evenly across the flex axis with spacing around each item.
```html
```
## Align Items Stretch
`.items-stretch` Stretches each flex item across the cross axis. This is the default alignment and doesn't need to be applied unless you are overriding something set differently.
```html
```
## Align Items Start
`.items-start` places each flex item at the start of the cross axis.
```html
```
## Align Items Center
`.items-center` places each flex item at the center of the cross axis.
```html
```
## Align Items End
`.items-end` places each flex item at the end of the cross axis.
```html
```
## Align Items Baseline
`.items-baseline` places each flex item at the text baseline of the cross axis.
```html
```
## Align Self Auto
`.self-auto` changes a specific flex item to inherit its alignment from the container. This is the default alignment and doesn't need to be applied unless you are overriding something set differently.
```html
```
## Align Self Stretch
`.self-stretch` Stretches a specific flex item across the cross axis.
```html
```
## Align Self Start
`.self-start` places a specific flex item at the start of the cross axis.
```html
```
## Align Self Center
`.self-center` places a specific flex item at the center of the cross axis.
```html
```
## Align Self End
`.self-end` places a specific flex item at the end of the cross axis.
```html
```
## Align Self Baseline
`.self-baseline` places a specific flex item at the text baseline of the cross axis.
```html
```
---
# Gap
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
Gap utility classes can be used to set the spacing between items within a flex or grid container.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `size` | `"md"` | `none`, `xxs`, `xs`, `sm`, `md`, `lg`, `xl` | |
## Cascade
When using a gap utility, `--op-gap` will be set to the same spacing value as gap. This can be used in styles nested to match the container gap.
```css
.special-item {
display: flex;
gap: var(--op-gap, var(--op-space-sm)); /* Include a fallback in case the wrapping gap is missing. */
}
```
```html
```
## Extra Extra Small
`.gap-xxs` This will use `--op-space-2x-small` for the item spacing.
```html
```
## Extra Small
`.gap-xs` This will use `--op-space-x-small` for the item spacing.
```html
```
## Small
`.gap-sm` This will use `--op-space-small` for the item spacing.
```html
```
## Medium
`.gap-md` This will use `--op-space-medium` for the item spacing.
```html
```
## Large
`.gap-lg` This will use `--op-space-large` for the item spacing.
```html
```
## Extra Large
`.gap-xl` This will use `--op-space-xl` for the item spacing.
```html
```
## None
`.gap-none` This useful for removing a default gap. Especially useful for the [Advanced Utilities](utilities-advanced-cluster.md) which have a default gap of `--op-space-medium`.
```html
```
---
# Utilities Introduction
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
Utility classes are CSS classes scoped to a simple style property like flex or gap or a collection of related properties.
They can be combined together to quickly scaffold out page layouts or a portion of your HTML.
Optics provides limited but high value utility classes. Utilities can often and easily lead to poorly written CSS,
inconsistent styling, or unresponsive layouts. However, there are cases where utilities can provide great value.
Optics aims to give you access to them, but also provide guidelines for how to use them most effectively.
The utilities Optics provides focus on solving quick scaffolding **(Layout and Position)** problems,
not typographical, color, or one-off fixes **(Look and Feel)**.
We limit what utilities are made available to avoid maintaining a growing library of utilities,
keep our focus on intention revealing concepts and patterns, and keep maintainability top of mind.
Color, style, and typography should be named patterns.
When using utilities, keep in mind that the intention of what style they apply may be clear,
but the intention of what the UI concept is trying to accomplish may not be.
## When to use them?
> **Helpful Rubric for use:** Utilities should be used for solving Layout and Position, not Look and Feel
Simple flex based layouts, positioning items with gaps between them, or spiking how elements on the page will
be placed are great use cases for utilities. The value they provide is speed of use and not getting bogged down by having
to think about a meaningful name for every basic layout problem.
Use before Reuse: Skipping straight to a named component may lead to spending more effort naming things before
it's necessary. Sometimes starting with utilities to get things out on the page is better.
When you notice repetition or a larger concept or idea, then refactor to a named component.
## When to move utilities to semantically named UI concept?
Utilities for layout problems is a great place to start but can suffer from a few problems as your project progresses.
If a particular layout becomes a meaningful or repeated UI concept, thought should be put into naming it so as to provide consistency
and reveal the intention behind it. Utilities do not provide an intention-revealing name for what they do and thus if repeated or copied,
their intention can be lost. Copying between pages can unintentionally cause it to diverge from the original intent over time.
When multiple breakpoints or container queries are needed this is another good opportunity to move from utilities to a named semantic concept.
This will allow for more complex layout to be managed within a named CSS class and maintain a simple semantic HTML structure.
### Helpful rules of thumb to think about moving from utilities to a named concept:
- If you are using 3 or more utilities, it might be a sign there is a larger concept at play that should be defined.
- If your layout needs to handle breakpoints or special responsive rules, utilities are going to get in the way of making this easy. You probably want to name the concept.
- If a particular collection of utilities is getting used together often, it may point to a UI pattern in your design that should be named.
### Advanced Utilities vs Components
While flex utilities are great for moving quickly or for simple layouts, they can easily become
cumbersome to manage and tend to turn into "Flex Spaghetti". In some of these cases, reaching
for named components may make sense. However, there are times when a full component is more
restrictive than you need and hurts productivity. Sometimes you need just a bit more structure
to your layout, but not a component. [Stack](utilities-advanced-stack.md), [Cluster](utilities-advanced-cluster.md), [Split](utilities-advanced-split.md), [Flank](utilities-advanced-flank.md), and [Grid](utilities-advanced-grid.md)
provide a simple way to create readable, flexible layouts without the overhead of a full component.
## A word of warning
**The more componentized your UI is, the fewer utilities should be needed.**
As mentioned above, Utilities are great for speed and spiking out concepts,
but they come with a set of warnings. They can be difficult to refactor,
especially if repeated across pages or sections,
they can be difficult to manage between screen sizes media and container breakpoints,
and they can cause HTML clutter. This is why it's important to know their strengths,
when to use them, and when to stop using them.
---
# Item Width
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
Item Width utility classes can be used to set an element's width relative to its parent.
## Playground
```html
half width
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `width` | `"half"` | `half`, `full`, `one-fifth`, `two-fifths`, `three-fifths`, `four-fifths`, `one-quarter`, `three-quarters`, `one-third`, `two-thirds` | |
## Half
`.half-width` This item will be half the width of its parent.
```html
half width
```
## Full
`.full-width` This item will be the entire width of its parent.
```html
full width
```
## One-Fifth
`.one-fifth-width` This item will be one-fifth's width of its parent.
```html
one-fifth width
```
## Two-Fifths
`.two-fifths-width` This item will be two-fifths' width of its parent.
```html
two-fifths width
```
## Three-Fifths
`.three-fifths-width` This item will be three-fifths' width of its parent.
```html
three-fifths width
```
## Four-Fifths
`.four-fifths-width` This item will be four-fifths' width of its parent.
```html
four-fifths width
```
## One-Quarter
`.one-quarter-width` This item will be one-quarter's width of its parent.
```html
one-quarter width
```
## Three-Quarters
`.three-quarters-width` This item will be three-quarters' width of its parent.
```html
three-quarters width
```
## One-Third
`.one-third-width` This item will be one-third's width of its parent.
```html
one-third width
```
## Two-Thirds
`.two-thirds-width` This item will be two-thirds' width of its parent.
```html
two-thirds width
```
---
# Margin
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
Margin utility classes are used to add margin to an element.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `margin` | `"auto"` | ``, `none`, `auto`, `xs`, `sm`, `md`, `lg`, `xl` | |
| `marginY` | | ``, `none`, `xs`, `sm`, `md`, `lg`, `xl` | |
| `marginX` | | ``, `none`, `xs`, `sm`, `md`, `lg`, `xl` | |
| `marginTop` | | ``, `none`, `xs`, `sm`, `md`, `lg`, `xl` | |
| `marginBottom` | | ``, `none`, `xs`, `sm`, `md`, `lg`, `xl` | |
| `marginLeft` | | ``, `none`, `xs`, `sm`, `md`, `lg`, `xl` | |
| `marginRight` | | ``, `none`, `xs`, `sm`, `md`, `lg`, `xl` | |
## Margin None
`.margin-none` Set margin to 0
```html
```
## Margin Auto
`.margin-auto` Set margin to auto
```html
```
## Margin Extra Small
`.margin-xs` Set margin to use the `--op-space-xs` token
```html
```
## Margin Small
`.margin-sm` Set margin to use the `--op-space-sm` token
```html
```
## Margin Medium
`.margin-md` Set margin to use the `--op-space-md` token
```html
```
## Margin Large
`.margin-lg` Set margin to use the `--op-space-lg` token
```html
```
## Margin Extra Large
`.margin-xl` Set margin to use the `--op-space-xl` token
```html
```
## Margin Y None
`.margin-y-none` Set top and bottom margin to 0
```html
```
## Margin Y Extra Small
`.margin-y-xs` Set top and bottom margin to use the `--op-space-xs` token
```html
```
## Margin Y Small
`.margin-y-sm` Set top and bottom margin to use the `--op-space-sm` token
```html
```
## Margin Y Medium
`.margin-y-md` Set top and bottom margin to use the `--op-space-md` token
```html
```
## Margin Y Large
`.margin-y-lg` Set top and bottom margin to use the `--op-space-lg` token
```html
```
## Margin Y Extra Large
`.margin-y-xl` Set top and bottom margin to use the `--op-space-xl` token
```html
```
## Margin X None
`.margin-x-none` Set left and right margin to 0
```html
```
## Margin X Extra Small
`.margin-x-xs` Set left and right margin to use the `--op-space-xs` token
```html
```
## Margin X Small
`.margin-x-sm` Set left and right margin to use the `--op-space-sm` token
```html
```
## Margin X Medium
`.margin-x-md` Set left and right margin to use the `--op-space-md` token
```html
```
## Margin X Large
`.margin-x-lg` Set left and right margin to use the `--op-space-lg` token
```html
```
## Margin X Extra Large
`.margin-x-xl` Set left and right margin to use the `--op-space-xl` token
```html
```
## Margin Top None
`.margin-top-none` Set top margin to 0
```html
```
## Margin Top Extra Small
`.margin-top-xs` Set top margin to use the `--op-space-xs` token
```html
```
## Margin Top Small
`.margin-top-sm` Set top margin to use the `--op-space-sm` token
```html
```
## Margin Top Medium
`.margin-top-md` Set top margin to use the `--op-space-md` token
```html
```
## Margin Top Large
`.margin-top-lg` Set top margin to use the `--op-space-lg` token
```html
```
## Margin Top Extra Large
`.margin-top-xl` Set top margin to use the `--op-space-xl` token
```html
```
## Margin Bottom None
`.margin-bottom-none` Set bottom margin to 0
```html
```
## Margin Bottom Extra Small
`.margin-bottom-xs` Set bottom margin to use the `--op-space-xs` token
```html
```
## Margin Bottom Small
`.margin-bottom-sm` Set bottom margin to use the `--op-space-sm` token
```html
```
## Margin Bottom Medium
`.margin-bottom-md` Set bottom margin to use the `--op-space-md` token
```html
```
## Margin Bottom Large
`.margin-bottom-lg` Set bottom margin to use the `--op-space-lg` token
```html
```
## Margin Bottom Extra Large
`.margin-bottom-xl` Set bottom margin to use the `--op-space-xl` token
```html
```
## Margin Left None
`.margin-left-none` Set left margin to 0
```html
```
## Margin Left Extra Small
`.margin-left-xs` Set left margin to use the `--op-space-xs` token
```html
```
## Margin Left Small
`.margin-left-sm` Set left margin to use the `--op-space-sm` token
```html
```
## Margin Left Medium
`.margin-left-md` Set left margin to use the `--op-space-md` token
```html
```
## Margin Left Large
`.margin-left-lg` Set left margin to use the `--op-space-lg` token
```html
```
## Margin Left Extra Large
`.margin-left-xl` Set left margin to use the `--op-space-xl` token
```html
```
## Margin Right None
`.margin-right-none` Set right margin to 0
```html
```
## Margin Right Extra Small
`.margin-right-xs` Set right margin to use the `--op-space-xs` token
```html
```
## Margin Right Small
`.margin-right-sm` Set right margin to use the `--op-space-sm` token
```html
```
## Margin Right Medium
`.margin-right-md` Set right margin to use the `--op-space-md` token
```html
```
## Margin Right Large
`.margin-right-lg` Set right margin to use the `--op-space-lg` token
```html
```
## Margin Right Extra Large
`.margin-right-xl` Set right margin to use the `--op-space-xl` token
```html
```
---
# Text Alignment
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
Text Alignment utility classes can be used to align text in an element.
## Playground
```html
left
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `alignment` | `"left"` | `left`, `center`, `right`, `justify` | |
## Left
`.text-left` The inline contents are aligned to the left edge of the line box. Left is the default for most text so this is primarily for overriding alternate behavior.
```html
left
```
## Center
`.text-center` The inline contents are centered within the line box.
```html
center
```
## Right
`.text-right` The inline contents are aligned to the right edge of the line box.
```html
right
```
## Justify
`.text-justify` The inline contents are justified. Text should be spaced to line up its left and right edges to the left and right edges of the line box, except for the last line.
```html
justify
```
---
# Visibility
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/utilities.css)
Use the '.sr-only' class to hide accessibility text that is needed for screenreaders but needs to be hidden from regular users. [Read more here.](https://snook.ca/archives/html_and_css/hiding-content-for-accessibility)
## Playground
```html
The text
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `visible` | `false` | | |
## Visible
If no class is used the text will appear as normal.
```html
The text
```
## Hidden
Using the `.sr-only` class will visually hide the text but leaves it available to screenreaders.
```html
The text
```
---
# Accordion
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/accordion.css)
Accordion classes are built on the `details` and `summary` html elements. They provide consistent and composable styling for disclosure widgets.
## Playground
```html
arrow_right
Header Label
Something small enough to escape casual notice.
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `headerLabel` | | | |
| `marker` | | | |
| `additionalHeaderContent` | | | |
| `flipHeaderAndMarker` | | | |
| `disableAnimation` | | | |
| `content` | | | |
### Selective Imports
Accordion can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
@import '@rolemodel/optics/dist/css/components/icon';
/* Component */
@import '@rolemodel/optics/dist/css/components/accordion';
```
## Features
### Exclusive [open]
Setting the `name` attribute on the `` element will make the accordion exclusive. This attribute enables multiple `` elements to be connected, with only one open at a time.
See more about the `name` attribute on the [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/details#name).
```html
...
...
...
```
## Variations
### Default
`.accordion` used on a `details` element with a `summary` element as the first child will create an accordion component.
Within the `summary`, a span with the class `accordion__label` will be used as the title of the accordion and `accordion__marker` will be used as the icon.
Other content can be placed within the summary, but the `accordion__label` and `accordion__marker` classes must be used for the accordion to work properly.
```html
arrow_right
Header Label
Something small enough to escape casual notice.
```
### Swapped Label and Marker
Positioning the marker after the label inside of the summary will result in the marker being on the right side of the accordion.
```html
Header Label
arrow_right
Something small enough to escape casual notice.
```
### Disable Animation
If you prefer the accordion to not animate, you can disable the transition on the icon and content by using this modifier `.accordion--disable-animation`.
```html
arrow_right
Header Label
Something small enough to escape casual notice.
```
### Additional Header Content
Additional content can be included within the `summary` element in any order. Anything not within the `.accordion__label` or `.accordion__marker` classes will be rendered wherever you place it in the `summary`. Note: Content placed between the label and the marker will fill the width between them. If placing a button there, you may want to wrap it in a div so the button doesn't stretch the whole space.
```html
arrow_right
Header Label
Button
Something small enough to escape casual notice.
```
## Accordion API
Styles are built on CSS variables scoped to the accordion.
Here are the variables that can be customized:
```css
--_op-accordion-summary-min-height
```
## Customizing Accordion styles
> **Important!:** These patterns represent how to customize the style of the accordion for your project.
The accordion classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all accordion behavior by overriding the `.accordion` selector and setting any properties:
```css
.accordion {
}
```
## New Accordion Variations
> **Important!:** These patterns represent how to create new variations of the accordion for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.accordion--{name} {
--_op-accordion-summary-min-height: var(--op-font-small);
}
```
---
# Alert
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/alert.css)
Alert classes can be used to create a highlighted message or callout in your application.
These could be as banners for global application messages, or an error message within a section of your app.
## Playground
```html
warning
Warning
This is a warning alert
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `warningLevel` | `"warning"` | `warning`, `danger`, `info`, `notice` | |
| `style` | | `outlined`, `muted`, `filled` | |
| `title` | `"Warning"` | | |
| `description` | `"This is a warning alert"` | | |
| `icon` | `"warning"` | | |
| `dismissible` | | | |
### Selective Imports
Alert can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
@import '@rolemodel/optics/dist/css/components/icon';
/* Component */
@import '@rolemodel/optics/dist/css/components/alert';
```
## Variations
### Warning
`.alert--warning` Provides a warning styled message.
```html
warning
Warning
This is a warning alert
```
### Danger
`.alert--danger` Provides a danger styled message.
`.alert--alert` is an alias for `.alert--danger`. Since RoleModel commonly uses [Rails](https://rubyonrails.org/) to develop projects, adding this alias allows this to be used for flash messages without having to change the default in rails. [Devise](https://github.com/heartcombo/devise) is also commonly used and cannot easily be configured away from this.
```html
error
Danger
This is a danger alert
```
### Info
`.alert--info` Provides an info styled message.
```html
error
Info
This is an info alert
```
### Notice
`.alert--notice` Provides a notice styled message.
```html
task_alt
Notice
This is a notice alert
```
### Muted
`.alert--muted` can be applied to any of the above alerts to change the coloring to a muted version of that color.
```html
volume_mute
Warning
This is a muted warning alert
```
### Filled
`.alert--filled` can be applied to any of the above alerts to change the coloring to a filled version of that color.
```html
check_box_outline_blank
Warning
This is a filled warning alert
```
### No Icon
The icon is optional.
```html
Warning
This is a warning alert with no icon
```
### No Title
The title is optional.
```html
check_box_outline_blank
This is a warning alert with no title
```
### Dismissible
If your application needs to allow dismissing these alerts, you can add a second icon/button after the messages section and add functionality via JS.
```html
check_box_outline_blank
This is a warning alert with a close icon
close
```
### As a Flash or Toast Message
The alert component can also be used as an animated notification message by adding `.alert--flash` to the top level. This supports all the alert variations and styles.
## Alert Structure
All alerts use the following structure to construct the component.
The muted or filled classes would be added at the top level.
icon, title, and the final (dismissible close) icon are all optional.
```html
error
Error
Your message
Another message if you need
close
```
## Customizing alert styles
> **Important!:** These patterns represent how to customize the style of the alert for your project.
The alert classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all alert behavior by overriding the `.alert` selector and setting any properties:
```css
.alert {
border-radius: var(--op-radius-large);
}
```
If you need to override the behavior of a particular alert style, you can open the respective class and set or change properties.
```css
/* This will only affect the warning alert, but not danger, info, or notice. */
.alert--warning {
background-color: red;
color: white;
}
```
## New Alert Variations
> **Important!:** These patterns represent how to create new variations of the alert for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.alert--{name} {
background-color:
box-shadow:
color:
.alert__title {
color:
}
&.alert--muted {
background-color:
box-shadow:
color:
.alert__title {
color:
}
}
&.alert--filled {
background-color:
box-shadow:
color:
.alert__title {
color:
}
}
}
```
```css
.alert--purple {
background-color: verylightpurple;
box-shadow: var(--op-border-all) purple;
color: purple;
.alert__title {
color: darkpurple;
}
&.alert--muted {
background-color: lightpurple;
box-shadow: none;
color: white;
.alert__title {
color: purple;
}
}
&.alert--filled {
background-color: purple;
box-shadow: none;
color: white;
.alert__title {
color: darkpurple;
}
}
}
```
---
# Avatar
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/avatar.css)
Avatar classes can be used on `a` or `div` html elements with an `img` within it. They provide consistent and composable styling for application avatars or profile pictures.
When using on an `a` element, the avatar will support a hover and focus state.
When using on a `div` element, the avatar will not support a hover or focus state.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `size` | `"large"` | `small`, `medium`, `large` | |
| `disabled` | | | |
| `imageSource` | | | |
| `useLink` | | | |
### Selective Imports
Avatar can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/avatar';
```
## Variations
### Default
`.avatar` is the default avatar class.
```html
```
### Disabled
`.avatar--disabled` will disable the avatar and give it an opacity.
```html
```
### Size
`.avatar--small`, `.avatar--medium`, `.avatar--large` (with large being the default) modify the size of any avatar by changing the width and height to be smaller or larger.
```html
```
### Without Link
The avatar classes can be used either on an `a` or `div` element that wraps an `img` element.
`a` is a good choice for avatars that may have interaction such as a link to the users profile or settings.
`div` is a good choice if it is purely to display an image or profile picture and does not need to be interactive. Note: the hover and focus outlines will not be visible when using an `div` element directly.
```html
```
## Avatar API
The size and border styles are built on CSS variables scoped to the avatar.
Here are the variables that can be customized:
```css
--_op-avatar-border-radius
--_op-avatar-inner-border-color
--_op-avatar-outer-border-color
--_op-avatar-inner-border-width
--_op-avatar-outer-border-width
--_op-avatar-disabled-opacity
--_op-avatar-size-small
--_op-avatar-size-medium
--_op-avatar-size-large
```
## Customizing Avatar styles
> **Important!:** These patterns represent how to customize the style of the avatar for your project.
The avatar classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all avatar behavior by overriding the `.avatar` selector and setting any properties:
```css
.avatar {
}
```
## New Avatar Variations
> **Important!:** These patterns represent how to create new variations of the avatar for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.avatar--{name} {
--_op-avatar-border-radius: var(--op-radius-2x-large);
}
```
---
# Badge
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/badge.css)
The Badge component is similar to the Tag component, however it has a different semantic purpose. Badge is intended to be used for notification and information where Tag is intended to be used for interaction and input. See [Tag](components-tag.md) for details on its usage.
## Playground
```html
Default
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `label` | `"Default"` | | |
| `style` | `"default"` | `default`, `primary`, `warning`, `danger`, `info`, `notice` | |
| `pill` | | | |
| `inButton` | | `no`, `right`, `left` | |
| `showPrefixIcon` | | | This is not a class. It just provides an example of using icons within a badge |
| `showSuffixIcon` | | | This is not a class. It just provides an example of using icons within a badge |
### Selective Imports
Badge can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
@import '@rolemodel/optics/dist/css/components/icon';
/* Component */
@import '@rolemodel/optics/dist/css/components/badge';
```
## Variations
### Default
`.badge` Provides a default neutral colored badge.
```html
Default
```
### Primary
`.badge--primary` Provides a primary badge. This uses the primary color defined in your theme.
```html
Primary
```
### Warning
`.badge--warning` Provides a Warning badge. This uses the warning alert color.
```html
Warning
```
### Danger
`.badge--danger` Provides a Danger badge. This uses the danger alert color.
```html
Danger
```
### Info
`.badge--info` Provides a Info badge. This uses the Info alert color.
```html
Info
```
### Notice
`.badge--notice` Provides a Notice badge. This uses the Notice alert color.
```html
Notice
```
### Pill
`.badge--pill` Modifies the shape of any other badge by adding a radius to the left and right.
```html
Pill
```
### Notification Button
`.badge--notification-right` and `.badge--notification-left` can be used inside of a button with the `.btn--with-badge` class to achieve a button notification style.
```html
Notifications
5
```
## Customizing Badge styles
> **Important!:** These patterns represent how to customize the style of the badge for your project.
The badge classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all badge behavior by overriding the `.badge` selector and setting any properties:
```css
.badge {
font-size: var(--op-font-2x-large);
}
```
If you need to override the behavior of a particular badge style, you can open the respective class and set or change properties
```css
/* This will only affect the primary badge, but not default, secondary, notice, etc. */
.badge--primary {
background-color: red;
color: white;
}
```
## New Badge Variations
> **Important!:** These patterns represent how to create new variations of the badge for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.badge--{name} {
background-color:
color:
}
```
```css
.badge--purple {
background-color: purple;
color: white;
}
```
---
# Breadcrumbs
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/breadcrumbs.css)
The breadcrumbs component is used to show the user's current location in a hierarchy of pages.
It can be applied to a `nav` element with a collection of links and separators within it.
## Playground
```html
USA
arrow_right
Mexico
arrow_right
Canada
arrow_right
England
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `size` | | `small`, `large` | |
| `separator` | | | |
### Selective Imports
Breadcrumbs can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/breadcrumbs';
```
## Variations
### Default
`.breadcrumbs` should be used on a `nav` element. Within it, links with `.breadcrumbs__link`, separators with `.breadcrumbs__separator`, and the last item span with `.breadcrumbs__text` should be used.
```html
USA
arrow_right
Mexico
arrow_right
Canada
arrow_right
England
```
### Size
`.breadcrumbs--small`, `.breadcrumbs--large` (with small being the default) modify the font size of the breadcrumb links and text.
```html
USA
arrow_right
Mexico
arrow_right
Canada
arrow_right
England
```
### Separator
`.breadcrumbs__separator` is used to separate the links in the breadcrumbs. It is a div that anything can be put within, however typically would be used with an [Icon](components-icon.md).
```html
USA
folder
Mexico
folder
Canada
folder
England
```
## Breadcrumb API
Styles are built on CSS variables scoped to the breadcrumbs.
Here are the variables that can be customized:
```css
--_op-breadcrumbs-font-size-small:
--_op-breadcrumbs-font-size-large:
```
## Customizing Breadcrumbs styles
> **Important!:** These patterns represent how to customize the style of the breadcrumbs for your project.
The breadcrumbs classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all breadcrumbs behavior by overriding the `.breadcrumbs` selector and setting any properties:
```css
.breadcrumbs {
align-items: start;
}
```
If you want to override how the size modifier behaves, you can use the API described above to change which font size each size uses.
```css
.breadcrumbs {
--_op-breadcrumbs-font-size-small: var(--op-font-4x-large);
--_op-breadcrumbs-font-size-large: var(--op-font-6x-large);
}
```
## New Breadcrumbs Variations
> **Important!:** These patterns represent how to create new variations of the Breadcrumbs for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.breadcrumbs--{name} {
background-color:
color:
}
```
---
# Button
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/button.css)
Button classes can be used on `button` or `a` html elements. They provide consistent and composable styling that should address most applications basic needs.
## Playground
```html
Primary
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `label` | `"Primary"` | | |
| `variant` | `"default"` | `default`, `primary`, `destructive`, `warning` | |
| `noBorder` | | | |
| `disabled` | | | |
| `active` | | | |
| `pill` | | | |
| `icon` | | | |
| `iconWithLabel` | | | |
| `showPrefixIcon` | | | This is not a class. It just provides an example of using icons within a button |
| `showSuffixIcon` | | | This is not a class. It just provides an example of using icons within a button |
| `size` | | `small`, `medium`, `large` | |
### Selective Imports
Button can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
@import '@rolemodel/optics/dist/css/components/icon';
/* Component */
@import '@rolemodel/optics/dist/css/components/button';
```
## Variations
### Default
`.btn` Provides a default outlined button. This would be commonly used as a cancel button in a form or a secondary action on a page.
```html
Primary
```
### Primary
`.btn--primary` Provides a filled button using the primary color in your theme. This should be used as the primary action on a screen such as the login button on an account screen or the submit button on a form.
```html
Primary
```
### Destructive
`.btn--destructive` Provides a filled button using the red danger color. This should be used as a destructive action such as delete.
Note: `.btn--delete` also works for backwards compatibility, but `.btn--destructive` is the preferred class name.
```html
Delete
```
### Active
`.btn--active` This is a modifier which can be used with all button classes. It provides an active state that adapts it's color to all the btn variations.
```html
Active
```
### No Border
`.btn--no-border` This is a modifier which can be used with all button classes except destructive and warning. It provides a button with no border, but the same sizing and adapts it's color to all the btn variations.
Note: `.btn--destructive` and `.btn--warning` do not support the `.btn--no-border` modifier. Borderless warning or destructive buttons are not considered a good pattern and can easily lead to confusion so are not available.
```html
No Border
```
### Disabled
`.btn--disabled` Should be used on `a` elements that need to be disabled. `button` elements can use the `disabled` attribute as well as this class. This makes the button opaque and prevents any onClick events from being triggered.
```html
Disabled
```
### Pill
`.btn--pill` Modifies the shape of any other buttons by adding a radius to the left and right.
```html
Pill
```
### Icon
`.btn--icon` Modifies the shape of any other button class by setting the width and height be be the same. This should only be used with an icon as the button text. You can also combine it with `.btn--no-border` for a borderless icon button, or `.btn--pill` for a round icon button.
```html
add
```
### Icon With label
`.btn--icon-with-label` Modifies the shape of any other button class by ensuring an icon used within the button will be stacked on top of the label.
```html
add Label
```
### Size
`.btn--small`, `.btn--medium`, `.btn--large` (with large being the default) modify the size of any other button class by changing the font, padding, and height to be smaller or larger.
```html
Small
```
## Mobile Buttons
All button classes, regardless of the currently applied size modifier, will automatically adjust to the large button size on mobile screens (--op-breakpoint-small ~ 768px).
This is to ensure a large enough tap area on smaller devices and screens.
See https://uxmovement.com/mobile/optimal-size-and-spacing-for-mobile-buttons/
## Button API
Size (Height, Padding, and Font) button styles are built on css variables scoped to the button.
Buttons have various states that are styled as well.
Here are the variables and states used
```css
/* Variable API */
--_op-btn-height-small
--_op-btn-height-medium
--_op-btn-height-large
--_op-btn-font-small
--_op-btn-font-medium
--_op-btn-font-large
--_op-btn-padding-small
--_op-btn-padding-medium
--_op-btn-padding-large
/* Different states */
.btn {} /* Default behavior */
.btn:not(:disabled, .btn--disabled):hover {} /* Hover behavior */
.btn.btn--no-border {} /* No Border Modifier */
.btn.btn--no-border:not(:disabled, .btn--disabled):hover {} /* Hovered No Border Modifier */
.btn.btn--active {} /* Active Modifier */
.btn.btn--active:not(:disabled, .btn--disabled):hover {} /* Hovered No Border Modifier */
```
## Customizing Button styles
> **Important!:** These patterns represent how to customize the style of the button for your project.
The button classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all button behavior by overriding the `.btn` selector and setting any properties:
```css
.btn {
border-radius: 0;
}
```
If you want to override how the size modifier behaves, you can use API described above to change which height and font each size uses.
```css
.btn {
--_op-btn-height-small: var(--op-space-2x-large);
--_op-btn-height-medium: var(--op-space-3x-large);
--_op-btn-height-large: var(--op-space-4x-large);
--_op-btn-font-small: var(--op-font-4x-large);
--_op-btn-font-medium: var(--op-font-5x-large);
--_op-btn-font-large: var(--op-font-6x-large);
--_op-btn-padding-small: var(--op-space-large);
--_op-btn-padding-medium: var(--op-space-x-large);
--_op-btn-padding-large: var(--op-space-2x-large);
}
```
If you need to override the color of a particular button style, you can open the respective class and change the `background-color`, `color`, and `box-shadow` properties to change the look.
```css
/* This will only affect the default button, but not primary, secondary, etc. */
.btn {
background-color: red;
color: white;
box-shadow: red;
}
```
## New Button Variations
> **Important!:** These patterns represent how to create new variations of the button for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.btn--{name} {
background-color:
box-shadow:
color:
/* Active State */
&.btn--active {
background-color:
box-shadow:
color:
}
/* Hover State */
&:hover {
background-color:
box-shadow:
color:
}
/* Focus State */
&:focus,
&:focus-within,
&:focus-visible {
box-shadow:
}
/* Borderless State */
&.btn--no-border {
background-color:
box-shadow:
color:
/* Borderless + Active State. */
&.btn--active {
background-color:
box-shadow:
color:
}
/* Borderless + Hover State */
&:hover {
background-color:
box-shadow:
color:
}
/* Borderless + Focus State */
&:focus,
&:focus-within,
&:focus-visible {
background-color:
box-shadow:
color:
}
}
}
```
---
# Button Group
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/button_group.css)
`.btn-group` is a class that can be added on a container around a collection of buttons. It provides grouping styles for any button conbination and variation that exists in the [Button Component](components-button.md)
Button Group is similar to the Segmented Control component, however it has a different semantic purpose. Button Group is intended to be used for grouping related actions or navigational buttons where Segmented Control is intended to be used for form option selection and submission. See [Segmented Control](components-segmented-control.md) for details on its usage.
## Playground
```html
Left Middle Right
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `variant` | `"default"` | `default`, `primary`, `destructive`, `warning` | |
| `noBorder` | | | |
| `active` | | | |
| `pill` | | | |
| `size` | | `small`, `medium`, `large` | |
| `segmentedPreview` | | | This is not a class. It just provides an example of creating a segmented control showing the currently active piece. |
### Selective Imports
Button Group can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
@import '@rolemodel/optics/dist/css/components/icon';
@import '@rolemodel/optics/dist/css/components/button';
/* Component */
@import '@rolemodel/optics/dist/css/components/button_group';
```
## Variations
### Default
```html
Left Middle Right
```
### Button Group Toolbar
`.btn-group-toolbar` can be used around a collection of `.btn-group` containers to allow connected groups that wrap. A gap utility can be used to provide spacing between the groups.
```html
```
### Primary
```html
Left Middle Right
```
### Destructive
```html
Left Middle Right
```
### Warning
```html
Left Middle Right
```
### Active
```html
Left Middle Right
```
### No Border
```html
Left Middle Right
```
### Disabled
```html
```
### Pill
```html
Left Middle Right
```
### Size
```html
Left Middle Right
```
## Button Group API
Styles are built on CSS variables scoped to the button group.
Here are the variables that can be customized:
```css
--op-btn-group-hover-z-index
--op-btn-group-active-z-index
--op-btn-group-focus-z-index
```
---
# Card
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/card.css)
Card classes can be used to denote bordered sections of an application. They provide simple styles to create sections or "cards" for your interface. They can also be used as a starting point for "row" or list styles.
## Playground
```html
Plain
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `label` | `"Plain"` | | |
| `padded` | | | |
| `condensed` | | | |
| `header` | | | |
| `body` | | | |
| `footer` | | | |
| `shadow` | | `none`, `x-small`, `small`, `medium`, `large`, `x-large` | |
### Selective Imports
Card can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/card';
```
## Variations
### Plain
`.card` Provides basic card styles.
```html
Plain
```
### Padded
`.card--padded` Provides a padded card.
```html
Padded
```
### Full
`.card__header`, `.card__body`, and `.card__footer` Provide padded sections of a card.
```html
```
### Condensed
`.card--condensed` Changes the padding for everything below it.
```html
```
### Shadow
`.card--shadow-x-small`, `.card--shadow-small`, `.card--shadow-medium`, `.card--shadow-large`, `.card--shadow-x-large` Add a shadow elevation effect to the card.
```html
Shadow
```
## Card API
Padding, Box Shadow (border), and Radius styles are built on css variables scoped to the card. They can ben overridden to customize the card.
```css
--_op-card-padding
--_op-card-box-shadow
--_op-card-radius
```
## Customizing Card styles
> **Important!:** These patterns represent how to customize the style of the card for your project.
The card classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all card behavior by overriding the `.card` selector and setting any properties:
```css
.card {
font-size: var(--op-font-2x-large);
}
```
If you need to override the behavior of a particular card modifier, you can open the respective class and set or change properties
```css
.card--modifier {
}
```
## New Card Variations
> **Important!:** These patterns represent how to create new variations of the card for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.card--{name} {
background-color:
color:
}
```
```css
.card--purple {
--_op-card-radius: var(--op-radius-large);
font-size: var(--op-font-2x-large);
.card__header {
background-color: purple;
color: white;
}
}
```
---
# Confirm Dialog
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/confirm-dialog.css)
The Confirm Dialog classes can be used for styling a custom alert or confirm dialog. This can be used alongside [Turbo Confirm](https://github.com/RoleModel/turbo-confirm) to achieve custom Confirm Dialogs using Turbo
### Selective Imports
Confirm Dialog can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/confirm-dialog';
```
## Variations
### Default
`.confirm-dialog-wrapper` Wraps the entire dialog.
`.confirm-dialog-wrapper--active` Allows the dialog to live on your page always, but only show if the class is present.
`.confirm-dialog-wrapper__backdrop` Provides the dark background to help focus on the dialog.
`.confirm-dialog` Provides the actual Dialog styling which is constructed similar to the card component.
- `.confirm-dialog__header`
- `.confirm-dialog__body`
- `.confirm-dialog__footer`
```html
Are you sure you want to delete this?
```
## Confirm Dialog API
Styles are built on CSS variables scoped to the confirm dialog.
Here are the variables that can be customized:
```css
--_op-confirm-dialog-width
```
## Customizing Confirm Dialog styles
> **Important!:** These patterns represent how to customize the style of the confirm dialog for your project.
The classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all dialogs behavior by overriding the `.confirm-dialog-wrapper` and `.confirm-dialog` selectors and setting any properties:
```css
.confirm-dialog-wrapper {
z-index: 200;
}
.confirm-dialog {
background-color: red;
}
```
## New Confirm Dialog Variations
> **Important!:** These patterns represent how to create new variations of the confirm dialog for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.confirm-dialog-wrapper--{name} {
.confirm-dialog-wrapper__backdrop {
}
&.confirm-dialog-wrapper--active {
.confirm-dialog-wrapper__backdrop {
}
}
}
.confirm-dialog--{name} {
.confirm-dialog__header,
.confirm-dialog__body,
.confirm-dialog__footer {
padding:
}
.confirm-dialog__header {
font-size:
font-weight:
}
.confirm-dialog__body {
box-shadow:
}
.confirm-dialog__footer {
display:
justify-content:
}
}
```
---
# Content Header
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/content-header.css)
Content Header classes can be used to denote a page or content section header of an application. They provide simple styles to provide context and actions for a page or section within your interface.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `title` | `"Content Header"` | | |
| `showContext` | `true` | | |
| `contextLabel` | `"Context Label"` | | |
| `showSubline` | `true` | | |
| `sublineLabel` | `"Subline Label"` | | |
| `showAside` | `true` | | |
| `asideExample` | `"actions"` | `actions`, `text` | |
### Selective Imports
Content Header can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/content-header';
```
## Variations
### Default
`.content-header` Provides basic content header styles.
`.context-header__details` provides a section for the title, context, and subline.
```html
```
### With Context
`.context-header__context` provides a context label above the title.
```html
```
### With Subline
`.context-header__subline` provides a subline below the title.
```html
```
### With Aside
`.context-header__aside` provides an aside section additional information or actions. It can hold anything you want, but is often used for page specific actions.
```html
```
### Simple
The title is really the only required part of a content header, though only really meaningful when used with actions, context, or subline.
```html
```
### GitHub Example
This example demonstrates a content header with minimal customization achieving a similar look to what might be found on a GitHub pull request page.
```html
```
## Customizing Content Header styles
> **Important!:** These patterns represent how to customize the style of the content header for your project.
The content header classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all content header behavior by overriding the `.content-header` class and setting any properties:
```css
.content-header {
padding-block: var(--op-space-3x-large);
}
```
If you need to override the behavior of the header, you can open the class and set or change properties
```css
.content-header--modifier {
padding-block: var(--op-space-2x-large);
}
```
## New Content Header Variations
> **Important!:** These patterns represent how to create new variations of the content header for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.content-header--{name} {
background-color: var(--op-color-primary-on-plus-four);
.content-header__context {
color: var(--op-color-primary-on-plus-four-alt);
}
.content-header__title {
color: var(--op-color-primary-on-plus-four);
}
.content-header__subline {
color: var(--op-color-primary-on-plus-four-alt);
}
}
```
---
# Divider
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/divider.css)
Divider classes can be used to create horizontal or vertical visual divides between content.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `vertical` | | | |
| `size` | | `small`, `medium`, `large` | |
| `spacing` | | `none`, `small`, `medium`, `large` | |
### Selective Imports
Divider can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/divider';
```
## Variations
### Default
`.divider` Provides a basic horizontal divider.
```html
```
### Vertical
`.divider.divider--vertical` Provides a basic vertical divider.
```html
```
### Size
`.divider--small`, `.divider--medium`, `.divider--large` (with small being the default) modify the size of any divider class by changing the width of the divider.
```html
```
### Spacing
`.divider--spacing-small`, `.divider--spacing-medium`, `.divider--spacing-large` (with none being the default) modify the padding around the divider.
```html
```
## Divider API
The size and spacing styles are built on CSS variables scoped to the divider.
Here are the variables that can be customized:
```css
--_op-divider-vertical-min-height
--_op-divider-height-small
--_op-divider-height-medium
--_op-divider-height-large
--_op-divider-padding-small
--_op-divider-padding-medium
--_op-divider-padding-large
```
## Customizing Divider styles
> **Important!:** These patterns represent how to customize the style of the divider for your project.
The divider classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all divider behavior by overriding the `.divider` selector and setting any properties:
```css
.divider {
}
```
If you need to override the behavior of a particular divider style, you can open the respective class and set or change properties
```css
.divider--modifier {
}
```
## New Divider Variations
> **Important!:** These patterns represent how to create new variations of the divider for your project.
Your application may need a custom divider. To add one, just follow this template:
```css
.divider--{name} {
}
```
---
# Form
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/form.css)
Form classes can be used on a variety of `inputs` or `select` HTML elements.
They provide consistent and composable styling that should address most applications basic needs.
## Playground
```html
A Label
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `label` | `"A Label"` | | |
| `type` | `"Text"` | `Text`, `Number`, `Email`, `Password`, `Tel`, `Checkbox`, `Radio`, `Color`, `Date`, `File` | |
| `size` | | `small`, `medium`, `large` | |
| `noBorder` | | | |
| `readonly` | | | |
| `disabled` | | | |
| `indeterminate` | | | |
| `inline` | | | |
| `error` | | | |
| `hint` | | | |
### Selective Imports
Form Controls can be used as standalone components, however, they do have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/form';
```
## Variations
### Label
`.form-label` Provides basic input label styles.
```html
A Label
```
### Input
`.form-control` Provides basic input styles. This can be used on `input` HTML elements. It works across a variety of types such as `text`, `number`, `password`, `email`, `phone`, `color`, `radio`, and `checkbox`.
```html
```
### Form Group
`.form-group` Composes an input and label together as a pair. It provides padding between input + label pairs in a form.
```html
A Label
```
### Form Group Inline
`.form-group--inline` can be added to a `.form-group` to display the label and input on the same line.
```html
A Label
```
### Textarea
`textarea.form-control` Provides basic text area styles. This can be used on `textarea` HTML elements.
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `readonly` | | | |
### Dropdown
`select.form-control` Provides basic `select` element styles.
```html
Option 1
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `options` | `1` | | |
| `readonly` | | | |
| `multiple` | `false` | | |
### Color
` ` Provides basic color input styles. This can be used on `input` HTML elements with a type of `color`.
```html
```
### Radio
` ` Provides basic input of type `radio` styles.
```html
A Label
```
### Checkbox
` ` Provides basic input of type `radio` styles.
```html
A Label
```
### Error Summary
`.form-error-summary` Is an error section, usually displayed above the form with a list of errors.
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `label` | `"2 errors prohibited this from being saved"` | | |
### Input Error
`.form-group.form-group--error` and `.form-error` are typically used on combination when there is a validation error on an input. They highlight the input in error along with the message provided.
```html
A Label Can't be blank
```
### Input Hint
`.form-hint` can be used inside of a `.form-group` to provide help text for an input.
```html
```
### No Border
`.form-control.form-control--no-border` can be used to create a borderless input or select. When used in a form group with `.form-control.form-group--error`, the input will get a red bottom border and highlight.
```html
A Label
```
### Size
`.form.form-control--small`, `.form.form-control--medium`, `.form.form-control--large` (with large being the default) modify the size of any element by changing the font and height to be smaller or larger.
```html
A Label
```
### Read Only
The `read-only` data attribute on any input with `.form-control` can be used to display values in a form-like way.
```html
A Label
```
### Indeterminate Checkbox
Checkboxes that use the indeterminate psuedo-class with be displayed with a `-` inside the checkmark.
See [MDN's documentation](https://developer.mozilla.org/en-US/docs/Web/CSS/:indeterminate) for further information.
```html
A Label
```
## Form API
Styles are built on CSS variables scoped to the form elements.
Here are the variables that can be customized.
```css
/* .form-control */
--_op-form-control-height-small
--_op-form-control-height-medium
--_op-form-control-height-large
--_op-form-control-font-small
--_op-form-control-font-medium
--_op-form-control-font-large
/* .form-control:not([type='radio'], [type='checkbox']) */
--_op-form-control-opacity-disabled
/* .form-control:is([type='radio'], [type='checkbox']) */
--_op-form-control-height-small
--_op-form-control-height-medium
--_op-form-control-height-large
```
## Customizing Form styles
> **Important!:** These patterns represent how to customize the style of the form for your project.
The form classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows multiple classes to share the same behavior.
`.form-control` is the class that is used to style all form controls.
`.form-control:not([type='radio'], [type='checkbox'])` is the selector that is used to style form controls based on the input like color, date, text, number, etc.
`.form-control:is([type='radio'], [type='checkbox'])` is the selector that is used to style checkboxes and radio buttons.
You can open them up like so to modify the styles:
```css
.form-control {
}
```
---
# Icon
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/icon.css)
Icon classes are built on top of [Google's Material Symbols Icon Font](https://fonts.google.com/icons). They provide a way to integrate iconography into your application in a flexible and customizable way.
Optics ships with a simplified version of [Material Symbols Outlined](https://fonts.google.com/icons?icon.style=Outlined). We only include the font weight variable aspect of the library.
This means that adjusting the size and font weight are always available, but the emphasis and fill options below are not available by default. If your app would like to use these options, you can import the full library by using the [Icon Font Addon](overview-addons.md#icon-fonts).
If you don't need the full library, but want a specific axis of the [Variable Font](tokens-typography-font-family.md#variable-fonts), You can use one of these imports alongside the Optics import.
```css
/* No fill, weight, or emphasis options, just allows for size modifiers */
@import 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined&display=block';
/* Only fill option */
@import 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:FILL@0..1&display=block';
/* Only emphasis option */
@import 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,GRAD@20..48,-50..200&display=block';
```
A combination of these could be used as well based on your applications needs. See [Google Variable Fonts](https://developers.google.com/fonts/docs/material_symbols#variable_font_with_google_fonts) for more details.
## Playground
```html
settings
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `iconPack` | `"Material Symbols Outlined"` | `Material Symbols Outlined`, `Phosphor`, `Tabler`, `Feather`, `Lucide` | |
| `name` | `"settings"` | | |
| `filled` | | | |
| `size` | | `small`, `medium`, `large`, `x-large` | |
| `weight` | | `thin`, `light`, `normal`, `semi-bold`, `bold` | |
| `emphasis` | | `low`, `normal`, `high` | |
| `duotone` | | | |
### Selective Imports
Icon can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts'; /* (specifically core/fonts/icon_fonts) */
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/icon';
```
### Additional Icon libraries
Optics supports a variety of [Additional icon libraries](overview-addons.md) that can be imported. Due to the nature of these libraries, not all of the same icon class modifiers may be available.
There are three ways these icon libraries can be used.
First is as an addon. This means that the default Material Symbols Outlined icons will still be loaded and both can be used.
```css
@import '@rolemodel/optics';
@import '@rolemodel/optics/dist/css/addons/fonts/phosphor_icons';
```
Second is to use an alternate Optics import that does not include the default Material Symbols Outlined icons, and only includes the additional icon library of your choice.
```css
@import '@rolemodel/optics/dist/css/optics+phosphor_icons';
```
Third is to remove the default Material Symbols Outlined icons and handle icons completely on your own. This will reduce the page load time by not loading any icons.
```css
@import '@rolemodel/optics/dist/css/optics+no_icons';
```
### Material Symbols Outline Variable Icons
Optics ships with a simplified version of [Material Symbols Outlined](https://fonts.google.com/icons?icon.style=Outlined). It only includes the font weight variable aspect of the icon library which means you won't be able to utilize the fill, or emphasis properties.
If your app does want to use the full Material Symbols Outlined library, you can import the full library by using the addon shown below.
This will increase the page load time but will allow you to use the full capabilities of the icon library.
```css
@import '@rolemodel/optics/dist/css/optics+material_symbols_outlined_variable';
```
```html
mood
```
The filled, size and weight modifiers can be used with Material Symbols Icons.
### Phosphor Icons
[Phosphor Icons](https://phosphoricons.com/) can be created with the `` tag and uses the `.ph` prefix with `.ph-{name}` to define a specific icon.
We currently support version 2.1.2 of [Phosphor Icons Web](https://github.com/phosphor-icons/web)
```css
@import '@rolemodel/optics';
@import '@rolemodel/optics/dist/css/addons/fonts/phosphor_icons';
/* Or */
@import '@rolemodel/optics/dist/css/optics+phosphor_icons';
```
```html
```
The filled, size and weight modifiers can be used with Phosphor Icons.
Phosphor adds `.icon--weight-thin` but does not support `.icon--weight-semi-bold`.
It also adds a dual tone variation by replacing `.ph` with `.ph-duotone`.
```html
```
Note: Phosphor Icons do not support the use of emphasis variations or the use of `.icon--filled` in combination with `.ph-duotone` or any weight variations.
### Tabler Icons
[Tabler Icons](https://tabler.io/icons) can be created with the `` tag and uses the `.ti` prefix with `.ti-{name}` to define a specific icon.
We currently support version 3.44.0 of [Tabler Icons Iconfont](https://github.com/tabler/tabler-icons#cdn)
```css
@import '@rolemodel/optics';
@import '@rolemodel/optics/dist/css/addons/fonts/tabler_icons';
/* Or */
@import '@rolemodel/optics/dist/css/optics+tabler_icons';
```
```html
```
The size modifiers can be used with Tabler Icons.
```html
```
It also supports a filled variant, however, rather than using the `.icon--filled` modifier, you can replace the `ti-{name}` class with `.ti-{name}-filled`.
```html
```
Note: Tabler Icons do not support the use of weight or emphasis variations.
### Feather Icons
[Feather Icons](https://feathericons.com/) can be created with the `` tag and uses the `.fi` prefix with `.fi-{name}` to define a specific icon.
```css
@import '@rolemodel/optics';
@import '@rolemodel/optics/dist/css/addons/fonts/feather_icons';
/* Or */
@import '@rolemodel/optics/dist/css/optics+feather_icons';
```
```html
```
The size modifiers can be used with Feather Icons.
```html
```
Note: Feather Icons do not support the use of filled, weight, or emphasis variations. The Feather Icon CDN does not include all of the Feather Icons.
If you want access to the broader range of Feather Icons, consider using Lucide Icons instead. However, if your needs are not as extensive or you are looking for a smaller icon pack, Feather Icons may be a better choice.
We currently support version 4.29.0 of [Feather Icons Iconfont](https://github.com/AT-UI/feather-font)
### Lucide Icons
Lucide Icons are a fork of Feather Icons with more icons. If you don't need all the icons that Lucide provides,
you can use the Feather Icons for a smaller icon pack instead. It is important to note that Feather Icons are less supported and not all of the listed icons are available.
[Lucide Icons](https://lucide.dev/icons/) can be created with the `` tag and uses the `.li` prefix with `.li-{name}` to define a specific icon.
We currently support version 1.21.0 of [Lucide Icons Static](https://github.com/lucide-icons/lucide/tree/main/packages/lucide-static)
```css
@import '@rolemodel/optics';
@import '@rolemodel/optics/dist/css/addons/fonts/lucide_icons';
/* Or */
@import '@rolemodel/optics/dist/css/optics+lucide_icons';
```
```html
```
The size modifiers can be used with Lucide Icons.
```html
```
Note: Lucide Icons do not support the use of filled, weight, or emphasis variations.
## Variations
### Default
To use an icon, put a `span` with the class of `.icon.material-symbols-outlined` and inner text of whatever icon you wish to use I.E. `settings` onto the page.
```html
settings
```
```html
settings
```
### Filled
`.icon--filled`, `.icon--outlined` (with outlined being the default) Provide a filled or outlined icon.
```html
settings
```
### Size
`.icon--small`, `.icon--medium`, `.icon--large`, `.icon--x-large` (with medium being the default) modify the size of any icon.
```html
settings
```
### Weight
`.icon--weight-light`, `.icon--weight-normal`, `.icon--weight-semi-bold`, `.icon--weight-bold` (with normal being the default) modify the font weight of any icon.
```html
settings
```
### Emphasis
Emphasis acts similarly to weight, but changes the thickness of the icon strokes in subtle ways.
`.icon--low-emphasis`, `.icon--normal-emphasis`, `.icon--high-emphasis` (with normal being the default) modify the emphasis of any icon.
```html
settings
```
## Icon API
Styles are built on CSS variables scoped to the icon.
Here are the variables that can be customized:
```css
/* Weight */
--_op-icon-weight-light
--_op-icon-weight-normal
--_op-icon-weight-semi-bold
--_op-icon-weight-bold
/* Fill */
--_op-icon-fill-outlined
--_op-icon-fill-filled
/* Emphasis */
--_op-icon-emphasis-low
--_op-icon-emphasis-normal
--_op-icon-emphasis-high
/* Size */
--_op-icon-font-size-small
--_op-icon-font-size-medium
--_op-icon-font-size-large
--_op-icon-font-size-x-large
--_op-icon-optical-size-small
--_op-icon-optical-size-medium
--_op-icon-optical-size-large
--_op-icon-optical-size-x-large
```
## Customizing Icon styles
> **Important!:** These patterns represent how to customize the style of the icon for your project.
The icon classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all icon behavior by overriding the `.icon` selector and setting any properties:
```css
.icon {
}
```
## New Icon Variations
> **Important!:** These patterns represent how to create new variations of the icon for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.icon {
&.icon--{name} {
--_op-icon-font-size-small: var(--op-font-small);
}
}
```
---
# Modal
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/modal.css)
The Modal classes can be used for styling a custom modal. This can be used alongside the Rails configuration and Javascript implemented by [RoleModel Rails Modal](https://github.com/RoleModel/rolemodel_rails/tree/master/lib/generators/rolemodel/modals)
## Selective Imports
Modal can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/modal';
```
## Variations
## Default
`.modal-wrapper` Wraps the entire dialog.
`.modal-wrapper--active` Allows the dialog to live on your page always, but only show if the class is present.
`.modal-wrapper__backdrop` Provides the dark background to help focus on the dialog.
`.modal` Provides the actual Dialog styling which is constructed similar to the card component.
- `.modal__header`
- `.modal__body`
- `.modal__footer`
```html
This is the contents of the modal!
```
## HTML Dialog
[\ The Dialog Element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog)
The modal styles work well using the HTML dialog element. Simply add the `modal` class to the dialog element. No need for the wrapper classes or the active class.
```html
Show Dialog
This is the contents of the modal!
```
To open a `` modally by clicking a `` you typically need an onclick handler that calls the showModal method on that ``.
```html
Show Dialog
…
```
With [invoker commands](https://developer.mozilla.org/en-US/docs/Web/API/Invoker_Commands_API), newly available in all browsers though only as of December 12, 2025, buttons can now perform actions on other elements declaratively, without the need for any JavaScript.
```html
Show Dialog
…
```
If you want to use the invoker approach in your project today and ensure backwards compatibility, you can use a polyfill.
```js
```
## Modal API
Styles are built on CSS variables scoped to the modal.
Here are the variables that can be customized:
```css
/* base tokens */
--op-transition-modal-time
--op-transition-modal
/* modal-wrapper */
--_op-modal-backdrop-active-opacity
/* modal */
--_op-modal-width
--_op-modal-max-height
```
## Customizing Modal styles
> **Important!:** These patterns represent how to customize the style of the modal for your project.
The classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all dialogs behavior by overriding the `.modal-wrapper` and `.modal` selectors and setting any properties:
```css
.modal-wrapper {
z-index: 200;
}
.modal {
background-color: red;
}
```
## New Modal Variations
> **Important!:** These patterns represent how to create new variations of the modal for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.modal-wrapper--{name} {
.modal-wrapper__backdrop {
}
&.modal-wrapper--active {
.modal-wrapper__backdrop {
}
}
}
.modal--{name} {
.modal__header,
.modal__body,
.modal__footer {
padding:
}
.modal__header {
font-size:
font-weight:
}
.modal__body {
box-shadow:
}
.modal__footer {
display:
justify-content:
}
}
```
---
# Navbar
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/navbar.css)
Navbar classes provide simple styling for a navigation header.
For instructions on how to integrate a navbar into your applications layout, see [Layout With Navbar](recipes-layout.md)
`.navbar` is the main component that everything is contained within.
Any [Button](components-button.md#default) style can be used for the links.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `style` | `"default"` | `default`, `primary` | |
| `brand` | | | |
| `justify` | | `start`, `center`, `end` | |
| `activeLink` | | `Inbox`, `Outbox`, `Favorite`, `Something` | |
### Selective Imports
Navbar can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
@import '@rolemodel/optics/dist/css/components/icon';
@import '@rolemodel/optics/dist/css/components/button';
/* Component */
@import '@rolemodel/optics/dist/css/components/navbar';
```
## Variations
### Default
`.navbar` Provides a neutral colored navbar. This uses the neutral color defined in your theme.
```html
```
### Primary
`.navbar.navbar--primary` Provides a primary colored navbar. This uses the primary color defined in your theme.
```html
```
### Brand
`.navbar__brand` can be used with an image tag inside. This can be used to display your applications branding or logo.
The brand is not required and the navbar content will adjust itself accordingly.
```html
```
### Content
`.navbar__content` defines the container that the buttons should be placed in. If you are putting navigation links within a content section, you should use the `nav` element for that section. It can be justified by using modifier classes.
`.navbar__content--justify-start`, `.navbar__content--justify-center`, `.navbar__content--justify-end` with start being the default.
```html
```
```html
```
## Navbar API
Color and hover styles are built on CSS variables scoped to the navbar.
Here are the variables that can be customized.
```css
/* Public API */
/* Normal */
--_op-navbar-background-color
--_op-navbar-text-color
--_op-navbar-border-color
/* Height */
--_op-navbar-brand-height
/* Spacing */
--_op-navbar-horizontal-spacing
--_op-navbar-content-spacing
--_op-navbar-content-item-spacing
```
## Customizing Navbar styles
> **Important!:** These patterns represent how to customize the style of the navbar for your project.
The navbar classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all navbar behavior by overriding the `.navbar` selector and setting any properties:
```css
.navbar {
--_op-navbar-background-color: pink;
--_op-navbar-text-color: blue;
}
```
If you need to override the behavior of a particular navbar style, you can open the respective class and set or change properties
```css
.navbar--modifier {
--_op-navbar-brand-height: 5.4rem;
--_op-navbar-horizontal-spacing: var(--op-space-small);
--_op-navbar-content-item-spacing: var(--op-space-x-small);
}
```
## New Navbar Variations
> **Important!:** These patterns represent how to create new variations of the Navbar for your project.
Your application may need a custom navbar. To add one, just follow this template:
```css
.navbar--{name} {
}
```
---
# Pagination
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/pagination.css)
Pagination is used to navigate through a series of pages, typically when dealing with tabular data.
A few classes are used in combination with the button component to achieve this.
An example of using this component with the Table component can be found in [Table With Pagination](components-table.md#with-pagination).
## Note on Implementation
This is just a styling pattern and does not implement the paging functionality. That is up to the projects needs.
A commonly used tool for Ruby on Rails projects is [Kaminari](https://github.com/kaminari/kaminari). It allows you to copy its templates and customize them. To apply these patterns to those templates, just edit the files it generates and use the classes in these examples.
[RoleModel Rails Kaminari Generator](https://github.com/RoleModel/rolemodel_rails/tree/master/lib/generators/rolemodel/kaminari) provides a generator to install and configure Kaminari with Optics classes applied.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `activePage` | | `1`, `2`, `3`, `10`, `11`, `12` | |
| `includeShowing` | | | |
### Selective Imports
Pagination can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
@import '@rolemodel/optics/dist/css/core/button';
@import '@rolemodel/optics/dist/css/core/form';
/* Component */
@import '@rolemodel/optics/dist/css/components/pagination';
```
## Variations
### Default
`.pagination` Is the main class. It can be placed on a `nav` element and wraps a collection of [buttons](components-button.md) to create a pagination component.
The buttons within can use any of the button classes, but form a default look, use the `.btn .btn--no-border .btn--small` classes.
For the first and last page buttons, `.btn--icon` can be added for ensure a square button.
For the currently active page, `.btn--active` can be used.
`.pagination__divider` can be used on a div with contents of `...` to indicate a break in the pagination.
This pattern is commonly used (and recommended to be used) when there are more that six pages of content. It prevents the pagination from becoming too long.
```html
```
### With Showing Select
Another common pattern is to allow users to change how many items are shown per page. The visuals of this can be achieved by using a form group with a select component. The pagination styling will handle making the form label inline.
```html
```
## Customizing Pagination styles
> **Important!:** These patterns represent how to customize the style of the pagination for your project.
The pagination classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all pagination behavior by overriding the `%pagination-global` selector and setting any properties:
```css
.pagination {
}
```
## New Pagination Variations
> **Important!:** These patterns represent how to create new variations of the pagination for your project.
Your application may need a custom pagination. To add one, just follow this template:
```css
.pagination--{name} {
}
```
---
# Segmented Control
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/segmented-control.css)
Segmented Control classes can be used to create a stylized radio select group.
Segmented Control component is similar to the Button Group component, however it has a different semantic purpose. Segmented Control is intended to be used for form option selection and submission where Button Group is intended to be used for grouping related actions or navigational buttons. See [Button Group](components-buttongroup.md) for details on its usage.
## Note on Implementation
This is just a styling pattern that builds on standard radio inputs and labels. Your project may need some tooling to generate this easily.
A commonly used tool for Ruby on Rails projects is [SimpleForm](https://github.com/heartcombo/simple_form). It allows you to build forms with pre-made inputs and allows you to make custom input types.
[RoleModel Rails SimpleForm Generator](https://github.com/RoleModel/rolemodel_rails/tree/master/lib/generators/rolemodel/simple_form) provides a generator to install a custom segmented control input that can be used with SimpleForm with Optics classes applied.
## Playground
```html
Option 1
Option 2
Option 3
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `size` | `"medium"` | `small`, `medium`, `large` | |
| `options` | `3` | | |
| `fullWidth` | | | |
| `showPrefixIcon` | `false` | | This is not a class. It just provides an example of using icons within the options |
| `showSuffixIcon` | `false` | | This is not a class. It just provides an example of using icons within the options |
### Selective Imports
SegmentedControl can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
@import '@rolemodel/optics/dist/css/components/icon';
/* Component */
@import '@rolemodel/optics/dist/css/components/segmented-control';
```
## Variations
### Default
`.segmented-control` Provides styled radio select group.
```html
Option 1
Option 2
Option 3
```
### Input
`.segmented-control__input` can be used on the radio inputs.
### Label
`.segmented-control__label` can be used on the radio labels.
The [Icon](components-icon.md) component can be used within the label as a prefix or suffix and will follow the sizing appropriately.
```html
Option 1
info
Option 2
info
Option 3
info
```
### Size
`.segmented-control--small`, `.segmented-control--medium`, `.segmented-control--large` (with large being the default) modify the size of any other segmented control class by changing the font, padding, and height to be smaller or larger.
```html
Option 1
Option 2
Option 3
```
### Full Width
`.segmented-control--full-width` can be used to make the segmented control take up the full width of its container.
```html
Option 1
Option 2
Option 3
```
## SegmentedControl API
Styles are built on css variables scoped to the segmented control.
Here are the variables that can be customized.
```css
/* Some global tokens are overridden within this component */
--op-input-inner-focus
--op-input-focus-primary
/* Public API (customizable component options) */
--_op-segmented-control-height-small
--_op-segmented-control-height-medium
--_op-segmented-control-height-large
--_op-segmented-control-font-small
--_op-segmented-control-font-medium
--_op-segmented-control-font-large
--_op-segmented-control-label-padding-small
--_op-segmented-control-label-padding-medium
--_op-segmented-control-label-padding-large
--_op-segmented-control-label-gap-small
--_op-segmented-control-label-gap-medium
--_op-segmented-control-label-gap-large
--_op-segmented-control-color-icon-default
--_op-segmented-control-color-icon-active
```
## Customizing Segmented Control styles
> **Important!:** These patterns represent how to customize the style of the segmentedcontrol for your project.
The segmented control classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all segmented control behavior by overriding the `.segmented-control` class and setting any properties:
```css
.segmented-control {
color: red;
}
```
If you need to override the behavior of a particular segmented control modifier, you can open the respective class and set or change properties
```css
.segmented-control--small {
color: red;
}
```
## New Segmented Control Variations
> **Important!:** These patterns represent how to create new variations of the SegmentedControl for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.segmented-control--{name} {
background-color: white;
color: purple;
&.segmented-control--small {
color: red;
}
&.segmented-control--medium {
color: green;
}
&.segmented-control--large {
color: blue;
}
}
```
---
# Sidebar
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/sidebar.css)
Sidebar classes provide simple styling for a navigation sidebar drawer, compact, or rail.
For instructions on how to integrate a sidebar into your applications layout, see [Layout With Sidebar](recipes-layout.md)
`.sidebar` is the main component that everything is contained within.
`.sidebar--drawer`, `.sidebar--compact`, and `.sidebar--rail` are used to denote which style of sidebar you would like to use.
```html
```
Any [Button](components-button.md#default) style can be used for the links.
- Drawer will use the normal button style, but left aligned
- Compact will use the `.icon-with-label` style
- Rail will use the `.btn--icon` style and hide the label
## Responsive Sidebar
The sidebar can be made responsive with a little snippet of Javascript. This allows for the sidebar to change from the larger state (compact or drawer) to the rail when the screen is smaller. e.g.
```js
const sidebarStyleOptions = {
drawer: 'sidebar--drawer',
compact: 'sidebar--compact',
rail: 'sidebar--rail',
}
const getSidebarStyle = (width) => {
let newStyle = sidebarStyleOptions['drawer']
if (window.innerWidth <= 1024) {
newStyle = sidebarStyleOptions['compact']
}
if (window.innerWidth <= 768) {
newStyle = sidebarStyleOptions['rail']
}
return newStyle
}
const applySidebarStyle = (newStyle) => {
const sidebar = document.getElementById('sidebar')
sidebar.classList.remove(sidebarStyleOptions['drawer'])
sidebar.classList.remove(sidebarStyleOptions['compact'])
sidebar.classList.remove(sidebarStyleOptions['rail'])
sidebar.classList.add(newStyle)
}
// Initial Page Load
applySidebarStyle(getSidebarStyle(window.innerWidth))
// Window Resize
window.addEventListener('resize', (event) => {
applySidebarStyle(getSidebarStyle(window.innerWidth))
})
```
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `size` | `"drawer"` | `drawer`, `compact`, `rail` | |
| `padded` | | | |
| `style` | `"default"` | `default`, `primary` | |
| `brand` | | | |
| `position` | | `start`, `center`, `end` | |
| `activeLink` | | `Inbox`, `Outbox`, `Favorite`, `Trash`, `Circle`, `Triangle`, `Square`, `Different` | |
### Selective Imports
Sidebar can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
@import '@rolemodel/optics/dist/css/components/icon';
@import '@rolemodel/optics/dist/css/components/button';
/* Component */
@import '@rolemodel/optics/dist/css/components/sidebar';
```
## Variations
### Default
`.sidebar` Provides a neutral colored sidebar. This uses the neutral color defined in your theme.
```html
```
```html
```
```html
```
### Primary
`.sidebar--primary` Provides a primary colored sidebar. This uses the primary color defined in your theme.
```html
```
```html
```
```html
```
### Padded
`.sidebar--padded` Adds a top and bottom padding to the sidebar.
```html
```
```html
```
```html
```
### Brand
`.sidebar__brand` can be used with an image tag inside. This can be used to display your applications branding or logo.
The brand is not required and the sidebar content will adjust itself accordingly.
```html
```
```html
```
```html
```
### Content
`.sidebar__content` defines the container that the buttons should be placed in. It can be positioned by using modifier classes.
`.sidebar__content--start`, `.sidebar__content--center`, `.sidebar__content--end` with start being the default.
```html
```
```html
```
```html
```
```html
```
```html
```
```html
```
```html
```
```html
```
```html
```
## Sidebar API
Color and hover styles are built on CSS variables scoped to the sidebar.
Here are the variables used:
```css
/* Public API */
/* Normal */
--_op-sidebar-background-color
--_op-sidebar-text-color
--_op-sidebar-border-color
/* Width */
--_op-sidebar-rail-width
--_op-sidebar-compact-width
--_op-sidebar-drawer-width
--_op-sidebar-rail-brand-width
--_op-sidebar-compact-brand-width
--_op-sidebar-drawer-brand-width
/* Spacing */
--_op-sidebar-spacing
--_op-sidebar-brand-spacing
--_op-sidebar-content-spacing
--_op-sidebar-content-item-spacing
/* Animation */
--_op-sidebar-transition
```
## Customizing Sidebar styles
> **Important!:** These patterns represent how to customize the style of the sidebar for your project.
The sidebar classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all sidebar behavior by overriding the `.sidebar` selector and setting any properties:
```css
.sidebar {
--_op-sidebar-rail-width: 10rem;
--_op-sidebar-compact-width: 20rem;
--_op-sidebar-drawer-width: 30rem;
}
```
There are also styles for the rail and drawer specific styles. They can be overridden like:
```css
.sidebar {
.sidebar__content {
align-items: flex-end;
}
}
.sidebar {
.sidebar__content {
> * {
font-weight: var(--op-font-weight-black);
}
}
}
```
If you need to override the color of a particular sidebar style, you can open the respective class and change the variables documented above
```css
/* This will only affect the primary sidebar, but not default */
.sidebar--primary {
--_op-sidebar-background-color: purple;
--_op-sidebar-text-color: purple;
}
```
## New Sidebar Variations
> **Important!:** These patterns represent how to create new variations of the sidebar for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.sidebar--{name} {
}
```
---
# SidePanel
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/side_panel.css)
Side Panel classes provide simple styling for a panel of sections with a scrollable body.
`.side-panel` is the main component that everything is contained within.
> **Note:** The wrapping div with a height in the code snippets is just for demonstration purposes in this documentation. It is not necessary for use in your application.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `border` | | `none`, `left`, `right`, `both` | |
| `headerPadding` | | `none`, `x`, `y`, `all` | |
| `bodyPadding` | | `none`, `x`, `y`, `all` | |
| `footerPadding` | | `none`, `x`, `y`, `all` | |
| `sections` | | | |
| `sectionPadding` | | `none`, `x`, `y`, `all` | |
| `showDividers` | | | |
### Selective Imports
Side Panel can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/side_panel';
```
## Variations
### Default
`.side-panel` provides the basic shell for your sidebar.
`.side-panel__header`, `.side-panel__body`, and `.side-panel__footer` are used to denote areas of the panel with body taking up as much height as available and adding a scrollbar for any content overflow.
```html
```
### Bordered
`.side-panel--border-left` or `.side-panel--border-right` provide a border on either side (or both if both used) of the panel.
```html
```
### Padded Header
`.side-panel__header--padded` Provides padding on the whole header area.
`.side-panel__header--padded-x` Provides padding on the left and right sides of the header area.
`.side-panel__header--padded-y` Provides padding on the top and bottom sides of the header area.
```html
```
### Padded Body
`.side-panel__body--padded` Provides padding on the whole body area.
`.side-panel__body--padded-x` Provides padding on the left and right sides of the body area.
`.side-panel__body--padded-y` Provides padding on the top and bottom sides of the body area.
```html
```
### Padded Footer
`.side-panel__footer--padded` Provides padding on the whole footer area.
`.side-panel__footer--padded-x` Provides padding on the left and right sides of the footer area.
`.side-panel__footer--padded-y` Provides padding on the top and bottom sides of the footer area.
```html
```
### Sections
`.side-panel__section` can be used within any of the other areas of the side panel and provide separation of content within it.
In this example, we are putting dividers between each section to show the separation.
```html
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
This is a section
```
### Padded Sections
One of the benefits is that each section supports the padding classes so individual sections can be padded as needed instead of the whole area.
`.side-panel__section--padded` Provides padding on the whole section.
`.side-panel__section--padded-x` Provides padding on the left and right sides of the section.
`.side-panel__section--padded-y` Provides padding on the top and bottom sides of the section.
```html
This is a section
This is a section
This is a section
```
## SidePanel API
Styles are built on CSS variables scoped to the SidePanel.
Here are the variables that can be customized:
```css
--_op-side-panel-width
--_op-side-panel-header-padding
--_op-side-panel-body-padding
--_op-side-panel-footer-padding
--_op-side-panel-section-padding
```
## Customizing SidePanel styles
> **Important!:** These patterns represent how to customize the style of the SidePanel for your project.
The SidePanel classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all SidePanel behavior by overriding the `.side-panel` selector and setting any properties:
```css
.side-panel {
background-color: var(--op-color-primary-plus-six);
color: var(--op-color-primary-on-plus-six);
}
```
## New SidePanel Variations
> **Important!:** These patterns represent how to create new variations of the SidePanel for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.sidepanel--{name} {
--_op-side-panel-width: calc(108 * var(--op-size-unit)); /* 432px */
--_op-side-panel-header-padding: var(--op-space-large);
--_op-side-panel-body-padding: var(--op-space-large);
--_op-side-panel-footer-padding: var(--op-space-large);
--_op-side-panel-section-padding: var(--op-space-small);
}
```
---
# Spinner
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/spinner.css)
Spinners are CSS loading indicators that should be shown when retrieving data or performing slow computations.
## Accessibility
A spinner should have the Aria `role="status"` and contain assistive text that explains what is currently happening. Inserting a `span.assistive-invisible Loading` which then gets hidden is the preferred method for adding this accessibility feature.
## Playground
```html
Loading
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `size` | `"large"` | `x-small`, `small`, `medium`, `large` | |
### Selective Imports
Spinner can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/spinner';
```
## Variations
### Default
Use `.spinner` to create the default spinner class which defaults to the `.spinner--large` size.
```html
Loading
```
### X-Small
Use `.spinner.spinner--x-small` to create an x-small spinner.
```html
Loading
```
### Small
Use `.spinner.spinner--small` to create a small spinner.
```html
Loading
```
### Medium
Use `.spinner.spinner--medium` to create a medium spinner.
```html
Loading
```
### Large
Use `.spinner.spinner--large` to create a large spinner.
```html
Loading
```
## Spinner API
Styles are built on CSS variables scoped to the spinner.
Here are the variables that can be customized:
```css
--_op-spinner-indicator-color
--_op-spinner-track-color
--_op-spinner-track-width-x-small
--_op-spinner-track-width-small
--_op-spinner-track-width-medium
--_op-spinner-track-width-large
--_op-spinner-diameter-x-small
--_op-spinner-diameter-small
--_op-spinner-diameter-medium
--_op-spinner-diameter-large
--_op-spinner-animation-duration
--_op-spinner-animation-timing-function
```
## Customizing Spinner styles
> **Important!:** These patterns represent how to customize the style of the spinner for your project.
The spinner classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all spinner behavior by overriding the `.spinner` selector and setting any properties:
```css
.spinner {
}
```
If you need to override the behavior of a particular spinner style, you can open the respective class and set or change properties:
```css
.spinner--modifier {
--_op-spinner-track-color: var(--op-color-primary-minus-three);
}
```
## New Spinner Variations
> **Important!:** These patterns represent how to create new variations of the Spinner for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.spinner--{name} {
--_op-spinner-indicator-color: red;
--_op-spinner-track-color: purple;
}
```
---
# Switch
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/switch.css)
Switch classes can be used to create a stylized checkbox or boolean input.
## Note on Implementation
This is just a styling pattern that builds on standard checkbox inputs. Your project may need some tooling to generate this easily.
A commonly used tool for Ruby on Rails projects is [SimpleForm](https://github.com/heartcombo/simple_form). It allows you to build forms with pre-made inputs and allows you to make custom input types.
[RoleModel Rails SimpleForm Generator](https://github.com/RoleModel/rolemodel_rails/tree/master/lib/generators/rolemodel/simple_form) provides a generator to install a custom switch input that can be used with SimpleForm with Optics classes applied.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `label` | | | |
| `size` | | `small`, `large` | |
| `disabled` | | | |
### Selective Imports
Switch can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/switch';
```
## Variations
### Default
`.switch` Provides basic styling for a checkbox or boolean input. It is intended to be used on an input element if type checkbox. It is also intended to be used within a form group. This typically would use `.form-group.form-group--inline` but can be used without the inline modifier.
```html
```
### Size
`.switch--large`, `.switch--small` (with large being the default) modify the size of the switch.
```html
```
### Disabled
`disabled='disabled'` will disable the switch.
```html
```
## Switch API
The size styles are built on CSS variables scoped to the switch.
Here are the variables that can be customized:
```css
--_op-switch-height-small
--_op-switch-height-large
--_op-switch-width-small
--_op-switch-width-large
--_op-switch-opacity-disabled
--_op-switch-switch-padding
```
## Customizing Switch styles
> **Important!:** These patterns represent how to customize the style of the switch for your project.
The switch classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all switch behavior by overriding the `.switch` selector and setting any properties:
```css
.switch {
}
```
If you need to override the behavior of a particular switch style, you can open the respective class and set or change properties
```css
.switch--modifier {
}
```
## New Switch Variations
> **Important!:** These patterns represent how to create new variations of the switch for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.switch--{name} {
}
```
---
# Tab
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/tab.css)
Tab classes provide simple styling for a tab group navigation.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `size` | | `small`, `large` | |
| `activeTab` | | `USA`, `Mexico`, `Canada`, `England`, `Germany`, `Spain`, `Austria`, `Australia` | |
| `disabledTab` | | `USA`, `Mexico`, `Canada`, `England`, `Germany`, `Spain`, `Austria`, `Australia` | |
### Selective Imports
Tab can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/tab';
```
## Variations
### Default
`.tab-group` Provides the grouping around a collection of links or buttons that have the `.tab` class.
Each item should use `.tab` and also supports `.tab--active` and `.tab--disabled`.
When using `.tab--disabled` the tabindex attributes should also be set to `-1` to skip the tab during keyboard navigation.
```html
```
### Small
A tab supports `.tab--small` or `.tab--large` with large being the default.
```html
```
## Tab API
Styles are built on CSS variables scoped to the tab.
Here are the variables that can be customized:
```css
--_op-tab-font-small
--_op-tab-font-large
--_op-tab-padding-small
--_op-tab-padding-large
--_op-tab-indicator-width-small
--_op-tab-indicator-width-large
--_op-tab-disabled-opacity
```
## Customizing Tab styles
> **Important!:** These patterns represent how to customize the style of the tab for your project.
The tab classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all tab behavior by overriding the `.tab` selector and setting any properties:
```css
.tab {
--_op-tab-font-small: var(--op-font-2x-small);
--_op-tab-padding-small: var(--op-space-3x-small) var(--op-space-small);
}
```
## New Tab Variations
> **Important!:** These patterns represent how to create new variations of the Tab for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.tab--{name} {
background-color: var(--op-color-primary-plus-two);
color: var(--op-color-primary-on-plus-two);
}
```
---
# Table
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/table.css)
Table classes provide simple styling for tables and their content.
## Playground
```html
Movie
Year Released
Trilogy
Episode IV - A New Hope
1977
Original
Episode V - The Empire Strikes Back
1980
Original
Episode VI - The Return of the Jedi
1983
Original
Episode I - The Phantom Menace
1999
Prequel
Episode II - Attack of the Clones
2002
Prequel
Episode III - The Revenge of the Sith
2005
Prequel
Episode VII - The Force Awakens
2015
Sequel
Rogue One
2016
Anthology
Episode VIII - The Last Jedi
2017
Sequel
Solo
2018
Anthology
Episode IX - The Rise of Skywalker
2019
Sequel
Total movies
11
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `style` | | `default`, `primary`, `danger` | |
| `layout` | | `auto`, `fixed` | |
| `density` | | `default`, `comfortable`, `compact` | |
| `striped` | | `off`, `even`, `odd` | |
| `sticky` | | `off`, `header`, `footer`, `both` | |
| `checkbox` | | | |
| `height` | | | This is not a class. It just provides a fixed height to demonstrate the sticky classes |
| `paginationInFooter` | | | An example of using the pagination component in the footer of the table |
### Selective Imports
Table can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/table';
```
## Variations
### Default
`.table` Provides a default style to a table element.
```html
Movie
Year Released
Trilogy
Episode IV - A New Hope
1977
Original
Episode V - The Empire Strikes Back
1980
Original
Episode VI - The Return of the Jedi
1983
Original
Episode I - The Phantom Menace
1999
Prequel
Episode II - Attack of the Clones
2002
Prequel
Episode III - The Revenge of the Sith
2005
Prequel
Episode VII - The Force Awakens
2015
Sequel
Rogue One
2016
Anthology
Episode VIII - The Last Jedi
2017
Sequel
Solo
2018
Anthology
Episode IX - The Rise of Skywalker
2019
Sequel
Total movies
11
```
### Primary
`.table.table--primary` Provides a Primary table. This uses the primary color in the header.
```html
Movie
Year Released
Trilogy
Episode IV - A New Hope
1977
Original
Episode V - The Empire Strikes Back
1980
Original
Episode VI - The Return of the Jedi
1983
Original
Episode I - The Phantom Menace
1999
Prequel
Episode II - Attack of the Clones
2002
Prequel
Episode III - The Revenge of the Sith
2005
Prequel
Episode VII - The Force Awakens
2015
Sequel
Rogue One
2016
Anthology
Episode VIII - The Last Jedi
2017
Sequel
Solo
2018
Anthology
Episode IX - The Rise of Skywalker
2019
Sequel
Total movies
11
```
### Danger
`.table.table--danger` Provides a Danger table. This uses the danger alert color in the header.
```html
Movie
Year Released
Trilogy
Episode IV - A New Hope
1977
Original
Episode V - The Empire Strikes Back
1980
Original
Episode VI - The Return of the Jedi
1983
Original
Episode I - The Phantom Menace
1999
Prequel
Episode II - Attack of the Clones
2002
Prequel
Episode III - The Revenge of the Sith
2005
Prequel
Episode VII - The Force Awakens
2015
Sequel
Rogue One
2016
Anthology
Episode VIII - The Last Jedi
2017
Sequel
Solo
2018
Anthology
Episode IX - The Rise of Skywalker
2019
Sequel
Total movies
11
```
### Layout
`.table.table--auto-layout`, `.table.table--fixed-layout` (with auto being the default) modify the table layout. Auto will adjust according to the contents, fixed will evenly divide based on the amount of columns.
```html
Movie
Year Released
Trilogy
Episode IV - A New Hope
1977
Original
Episode V - The Empire Strikes Back
1980
Original
Episode VI - The Return of the Jedi
1983
Original
Episode I - The Phantom Menace
1999
Prequel
Episode II - Attack of the Clones
2002
Prequel
Episode III - The Revenge of the Sith
2005
Prequel
Episode VII - The Force Awakens
2015
Sequel
Rogue One
2016
Anthology
Episode VIII - The Last Jedi
2017
Sequel
Solo
2018
Anthology
Episode IX - The Rise of Skywalker
2019
Sequel
Total movies
11
```
### Density
`.table.table--default-density`, `.table.table--comfortable-density`, `.table.table--compact-density` (with default being the default) modify the table cell padding to expand or contract how much space they use.
```html
Movie
Year Released
Trilogy
Episode IV - A New Hope
1977
Original
Episode V - The Empire Strikes Back
1980
Original
Episode VI - The Return of the Jedi
1983
Original
Episode I - The Phantom Menace
1999
Prequel
Episode II - Attack of the Clones
2002
Prequel
Episode III - The Revenge of the Sith
2005
Prequel
Episode VII - The Force Awakens
2015
Sequel
Rogue One
2016
Anthology
Episode VIII - The Last Jedi
2017
Sequel
Solo
2018
Anthology
Episode IX - The Rise of Skywalker
2019
Sequel
Total movies
11
```
```html
Movie
Year Released
Trilogy
Episode IV - A New Hope
1977
Original
Episode V - The Empire Strikes Back
1980
Original
Episode VI - The Return of the Jedi
1983
Original
Episode I - The Phantom Menace
1999
Prequel
Episode II - Attack of the Clones
2002
Prequel
Episode III - The Revenge of the Sith
2005
Prequel
Episode VII - The Force Awakens
2015
Sequel
Rogue One
2016
Anthology
Episode VIII - The Last Jedi
2017
Sequel
Solo
2018
Anthology
Episode IX - The Rise of Skywalker
2019
Sequel
Total movies
11
```
### Striping
`.table.table--even-striped`, `.table.table--odd-striped` color every other (odd or even) row with a light color on the neutral scale.
```html
Movie
Year Released
Trilogy
Episode IV - A New Hope
1977
Original
Episode V - The Empire Strikes Back
1980
Original
Episode VI - The Return of the Jedi
1983
Original
Episode I - The Phantom Menace
1999
Prequel
Episode II - Attack of the Clones
2002
Prequel
Episode III - The Revenge of the Sith
2005
Prequel
Episode VII - The Force Awakens
2015
Sequel
Rogue One
2016
Anthology
Episode VIII - The Last Jedi
2017
Sequel
Solo
2018
Anthology
Episode IX - The Rise of Skywalker
2019
Sequel
Total movies
11
```
```html
Movie
Year Released
Trilogy
Episode IV - A New Hope
1977
Original
Episode V - The Empire Strikes Back
1980
Original
Episode VI - The Return of the Jedi
1983
Original
Episode I - The Phantom Menace
1999
Prequel
Episode II - Attack of the Clones
2002
Prequel
Episode III - The Revenge of the Sith
2005
Prequel
Episode VII - The Force Awakens
2015
Sequel
Rogue One
2016
Anthology
Episode VIII - The Last Jedi
2017
Sequel
Solo
2018
Anthology
Episode IX - The Rise of Skywalker
2019
Sequel
Total movies
11
```
### Sticky Header/Footer
`.table.table--sticky-header`, `.table.table--sticky-footer` will make either the table header or table footer sticky; the default is top/bottom of the viewport.
These are best used in conjunction with a wrapping container fixed table height, though they will work outside of that being sticky to the browser window. Because the actual `table` HTML element is a bit finicky, you will need to wrap the `table` itself in a `.table-container` div to achieve correct overflow behavior. You will also need to set a fixed height. This will allow sticky header/footer with scrollable body rows.
```html
```
```html
```
```html
```
```html
```
### With Pagination
The [Pagination](components-pagination.md) component can be used with the table to provide a way to navigate through a large dataset.
Here is an example of using it in the table footer.
```html
```
## Table API
Padding table styles are built on CSS variables scoped to the table.
Here are the variables used:
```css
/* Variable API */
--_op-table-cell-padding-default
--_op-table-cell-padding-comfortable
--_op-table-cell-padding-compact
```
## Customizing Table styles
> **Important!:** These patterns represent how to customize the style of the table for your project.
The table classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all table behavior by overriding the `.table` selector and setting any properties:
```css
.table {
font-size: var(--op-font-2x-large);
}
```
If you want to override how the density modifier behaves, you can use API described above to change which padding each density uses.
```css
.table {
--_op-table-cell-padding-default: var(--op-space-x-small) var(--op-space-2x-small);
--_op-table-cell-padding-comfortable: var(--op-space-large) var(--op-space-medium);
--_op-table-cell-padding-compact: var(--op-space-2x-small) var(--op-space-3x-small);
}
```
If you need to override the color of a particular table style, you can open the respective class and set or change any properties:
```css
/* This will only affect the primary table, but not default or danger */
.table--primary {
thead {
background-color: purple;
color: white;
}
}
```
## New Table Variations
> **Important!:** These patterns represent how to create new variations of the table for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.table--{name} {
thead {
background-color:
color:
}
}
```
```css
.table--purple {
thead {
background-color: purple;
color: white;
}
}
```
---
# Tag
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/tag.css)
The tag component can be applied to an element with a button within it. The Tag component is similar to the Badge component, however it has a different semantic purpose. Tag is intended to be used for interaction and input where Badge is intended to be used for Notification and Information. See [Badge](components-badge.md) for details on its usage.
The tag will typically have a button within it. The button can be used to remove the tag from the UI. For Example, managing catgories or metadata tags on a data record.
## Playground
```html
Readonly
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `label` | `"Readonly"` | | |
| `type` | `"readonly"` | `readonly`, `primary`, `danger`, `warning`, `info`, `notice` | |
| `iconLeft` | | | |
| `iconRight` | | | |
### Selective Imports
Tag can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
@import '@rolemodel/optics/dist/css/components/icon';
/* Component */
@import '@rolemodel/optics/dist/css/components/tag';
```
## Variations
### Readonly
`.tag--readonly` Provides a Readonly tag. This is useful for displaying tags that cannot be removed.
```html
Readonly
```
### Primary
`.tag--primary` Provides a Primary tag. This uses the primary color.
```html
Primary
```
### Danger
`.tag--danger` Provides a Danger tag. This uses the danger alert color.
```html
Danger
```
### Warning
`.tag--warning` Provides a Warning tag. This uses the warning alert color.
```html
Warning
```
### Info
`.tag--info` Provides a Info tag. This uses the info alert color.
```html
Info
```
### Notice
`.tag--notice` Provides a Notice tag. This uses the notice alert color.
```html
Notice
```
## Customizing Tag styles
> **Important!:** These patterns represent how to customize the style of the tag for your project.
The tag classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all tag behavior by overriding the `.tag` class and setting any properties:
```css
.tag {
background-color: var(--op-color-alerts-danger-base);
}
```
If you need to override the behavior of a particular tag style, you can open the respective class and set or change properties
```css
.tag--danger {
background-color: var(--op-color-alerts-danger-base);
}
```
## New Tag Variations
> **Important!:** These patterns represent how to create new variations of the Tag for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.tag--{name} {
background-color:
color:
}
```
---
# Text Pair
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/text_pair.css)
The Text Pair component is used to display a title and subtitle together. It can also be used to group other elements within it, though should generally be reserved for text.
## Playground
```html
This is the Title
This is the Subtitle
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `inline` | | | |
| `titleText` | | | |
| `titleSize` | | `small`, `medium`, `large` | |
| `subtitleText` | | | |
| `subtitleSize` | | `small`, `medium`, `large` | |
| `gap` | | `none`, `xxs`, `xs`, `sm`, `md`, `lg`, `xl` | |
### Selective Imports
Text Pair can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/text_pair';
```
## Variations
### Default
`.text-pair` should be used on a div. Within it, `.text-pair__title` and `.text-pair__subtitle` on spans can be used to display the title and subtitle.
```html
This is the Title
This is the Subtitle
```
### Inline
`.text-pair--inline` can be added to display the title and subtitle horizontally aligned. This is useful for displaying a key, value pair.
```html
Temperature:
72℉
```
### Title Size
`.text-pair__title--small`, `.text-pair__title--medium`, `.text-pair__title--large`, (with medium being the default) modify the font size of the title text.
```html
Large Title
This is the Subtitle
```
### Subtitle Size
`.text-pair__subtitle--small`, `.text-pair__subtitle--medium`, `.text-pair__subtitle--large`, (with small being the default) modify the font size of the subtitle text.
Description of subtitle size example
```html
This is the Title
Large Subtitle
```
## Text Pair API
Styles are built on CSS variables scoped to the Text Pair.
Here are the variables that can be customized.
```css
--_op-text-pair-font-size-small:
--_op-text-pair-font-size-medium:
--_op-text-pair-font-size-large:
```
## Customizing Text Pair styles
> **Important!:** These patterns represent how to customize the style of the Text Pair for your project.
The Text Pair classes are structured using the [BEM methodology](https://getbem.com/naming).
This allows us to define core styles on a main [block](https://getbem.com/naming/#block) class, and use [modifiers](https://getbem.com/naming/#modifier) to encapsulate variant styles. You can modify all textpair behavior by overriding the `.text-pair` selector and setting any properties:
```css
.text-pair {
gap: var(--op-space-x-large);
}
```
## New Text Pair Variations
> **Important!:** These patterns represent how to create new variations of the Text Pair for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
.text-pair--{name} {
gap:
}
```
---
# Tooltip
[Source Code](https://github.com/RoleModel/optics/blob/main/src/components/tooltip.css)
Tooltips are build using data attributes on any element. Setting these will show text on hover.
`data-tooltip-text` can be set to any string and will be displayed as the contents of the tooltip.
`data-tooltip-position` can be set to `top`, `bottom`, `left`, or `right`(with top being used if nothing is set) and will position the tooltip relative to the element.
## Note on Implementation
This is a simple CSS only implementation of tooltips. As such, they will not automatically handle overflow clipping or container edge detection. You will need to handle that yourself or use a package.
Here are some commonly used JavaScript packages that can address those issues:
- [Floating UI](https://floating-ui.com)
- [Shoelace Tooltip](https://shoelace.style/components/tooltip)
- [TippyJS](https://atomiks.github.io/tippyjs/)
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `text` | `"A basic tooltip"` | | Note: The wrapping div with margin is not required. It is only used to create space around the tooltip for this example. |
| `position` | `"none"` | `none`, `top`, `right`, `bottom`, `left` | |
| `example` | `"text"` | `text`, `button`, `icon` | |
### Selective Imports
Tooltip can be used as a standalone component, however, it does have a few dependencies. To see a full dependency list, see [Dependency Graph](overview-selective-imports.md#dependencies)
```css
/* Depends on */
@import '@rolemodel/optics/dist/css/core/fonts';
@import '@rolemodel/optics/dist/css/core/tokens';
@import '@rolemodel/optics/dist/css/core/base';
/* Component */
@import '@rolemodel/optics/dist/css/components/tooltip';
```
## Note on usage with Button
There are cases when you might want to put a tooltip on a disabled [Button](components-button.md). Unfortunately due to the implementation of button which prioritizes simpler and easier to customize code, the hover is blocked which causes the tooltip to not show up.
The workaround for this is to wrap your disabled button in a span and put the tooltip on the span instead.
Disabled Button
```html
Disabled Button
```
## Variations
### Default
```html
```
### Top
```html
```
### Right
```html
```
### Bottom
```html
```
### Left
```html
```
### Button
Tooltips can be place on any element. Here is an example of a tooltip on a button.
```html
A Button Example
```
### Icon
Here is an example of a tooltip on an information icon.
```html
info
```
### Lots of Text
Tooltips have a maximum width and will wrap text if it is too long.
```html
```
## Tooltip API
Styles are built on CSS variables scoped to the tooltip.
Here are the variables that can be customized:
```css
--_op-tooltip-max-width
--_op-tooltip-padding
--_op-tooltip-background-color
--_op-tooltip-text-color
--_op-tooltip-arrow-size
--_op-tooltip-tooltip-offset
--_op-tooltip-tooltip-radius
--_op-tooltip-tooltip-font-size
```
## Customizing Tooltip styles
> **Important!:** These patterns represent how to customize the style of the tooltip for your project.
The tooltip using a data-attribute, not a class.
You can modify all tooltip behavior by overriding the `[data-tooltip-text]` selector and setting any properties:
```css
[data-tooltip-text] {
}
```
## New Tooltip Variations
> **Important!:** These patterns represent how to create new variations of the tooltip for your project.
Your application may need a variation. To add one, just follow this template. Note the double hyphen, indicating that this is a [modifier](https://getbem.com/naming/#modifier):
```css
[data-special-tooltip-text] {
/* Add your custom styles here */
}
```
---
# Aligned Header
[Source Code](https://github.com/RoleModel/optics/blob/main/src/recipes/aligned-header.css)
There are cases when you want to vertically center something on a line of text that wraps. Like a badge or edit button at the end of a text header.
Achieving this can be tricky as a simple flex or grid solution would result in the badge or button coming after the wrapped text in another block instead of inline with the wrapped text at the end of it.
Here is a solution that manually calculates the height of the suffix section based on the overall font size and line height. In this case, we need to explicity set those in order to calculate the height of the suffix section.
This is not a common problem and your particular use-case may need to tweak the implementation. Ultimately, this is not general enough to warrant being a full component in the library, but it is a good example of how to solve this specific problem.
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `example` | `"badge"` | `badge`, `icon-button` | |
## Badge Example
```css
/* Badge Example */
.aligned-header {
/* Public API (allowed to be overridden) */
--_op-line-height: var(--op-line-height-base);
--_op-font-size: var(--op-font-4x-large);
font-size: var(--_op-font-size);
font-weight: var(--op-font-weight-semi-bold);
line-height: var(--_op-line-height);
.aligned-header__centered-suffix {
display: inline-flex;
block-size: calc(var(--_op-line-height) * var(--_op-font-size));
align-items: center;
vertical-align: top;
}
}
```
```html
```
## Icon Button Example
The CSS is the same as the previous example, but the markup is different.
```html
```
---
# Custom Sidebar
[Source Code](https://github.com/RoleModel/optics/blob/main/src/recipes/16six-sidebar.css)
[Source Code](https://github.com/RoleModel/optics/blob/main/src/recipes/domains-sidebar.css)
Your app may want to customize the sidebar to change the look and feel. Here are a few examples to help you get started:
## Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `example` | `"16six"` | `domains`, `16six` | |
| `style` | `"drawer"` | `drawer`, `rail` | |
## Domain Registrar Example
```css
/* Domains Sidebar Example */
.sidebar {
&.sidebar--domains {
--_op-sidebar-drawer-width: 28rem;
--_op-sidebar-content-spacing: 0;
--_op-sidebar-content-item-spacing: 0;
box-shadow: none;
.btn {
border-radius: 0;
&.btn--no-border {
box-shadow: none;
&.btn--active {
background-color: var(--op-color-primary-plus-five);
color: var(--op-color-primary-on-plus-five);
}
&:hover:not(.btn--active) {
background-color: var(--op-color-neutral-plus-six);
box-shadow: none;
color: var(--op-color-neutral-on-plus-six);
}
}
&.btn--pill-right {
border-radius: 0 var(--op-radius-pill) var(--op-radius-pill) 0;
}
}
.sidebar__footer {
display: flex;
align-items: center;
gap: var(--op-space-small);
padding-inline-start: var(--op-space-large);
}
}
}
```
```html
```
## Performance Management Software Example
```css
/* 16Six Sidebar Example */
.icon--rotated-135 {
rotate: 135deg;
}
.icon--rotated-90 {
rotate: 90deg;
}
.sidebar {
.sidebar__brand {
justify-content: center;
.sidebar__brand-label {
display: none;
}
}
&.sidebar--16six {
--_op-sidebar-background-color: hsl(256deg 66% 15%);
--_op-sidebar-text-color: hsl(26deg 100% 95%);
--_op-sidebar-border-color: hsl(26deg 100% 95%);
--_op-sidebar-rail-width: 6.4rem;
--_op-sidebar-drawer-width: 22.4rem;
--_op-sidebar-drawer-brand-width: calc(var(--op-space-3x-large) + (2 * var(--op-space-medium)));
--_op-sidebar-brand-spacing: var(--op-space-medium) var(--op-space-x-small);
--_op-sidebar-content-item-spacing: var(--op-space-x-small);
--_op-sidebar-spacing: 0 0 var(--op-space-x-small);
.sidebar__brand {
display: flex;
margin: 0;
color: inherit;
gap: var(--op-space-medium);
text-decoration: none;
svg {
inline-size: var(--op-space-3x-large);
block-size: var(--op-space-3x-large);
}
.sidebar__brand-label {
display: flex;
flex-direction: column;
font-size: var(--op-font-small);
}
}
.btn {
&.btn--no-border {
background-color: transparent;
box-shadow: none;
color: var(--_op-sidebar-text-color);
&.btn--active,
&:hover {
background-color: hsl(256deg 23% 32%);
}
}
}
}
}
```
```html
```
---
# Layout
Optics provides two patterns for application layout. The basic (legacy) version is maintained for backwards compatibility, but all new projects should use the `op-page` pattern.
[Source Code](https://github.com/RoleModel/optics/blob/main/src/core/layout.css)
## OP Page
### Playground
Since the `op-page` layout utilizes the whole window, the playground is best experienced as a full page example.
Click here to open the playground
### Classes
Within the `op-page` layout, the sidebar on either side is completely optional, as is the header and footer within the main content area.
The full structure looks like the following:
```html
Optics Example Layout
```
#### `.op-page`
Is meant to be used on the body of your application to create a full window layout with optional areas.
#### `.op-page__sidebar`, `.op-page__sidebar--right`
Is meant to be used within the `.op-page` on either side of the the main content to create sidebar or panel areas on the or right side of the application. Add the modifier class `.op-page__sidebar--right` when using on the right side.
#### `.op-page__main`
Is meant to be used within the `.op-page` to wrap the main content area of your application. This contains the optional header, content, and optional footer areas.
#### `.op-page__main-header`
Is meant to be used on a header element within the `.op-page__main` to create a fixed header for your page. Often, the navbar component is used within here.
#### `.op-page__main-content`
Is meant to be used on a main element within the `.op-page__main` to create the container for your page content.
#### `.op-page__main-footer`
### Fullscreen Spinner
If you need a fullscreen spinner, use the following layout playground:
Click here to open the playground
### Login
If you need a login page, use the following layout playground:
Click here to open the playground
## Legacy Layout
This is the legacy layout that is maintained for backwards compatibility. New projects should not use these classes and instead, should use the `op-page` layout above.
### Playground
```html
```
| Arg | Default | Options | Description |
| --- | --- | --- | --- |
| `style` | `"basic"` | `basic`, `sidebar`, `navbar`, `spinner`, `sidepanel`, `login`, `utility`, `card-grid` | |
| `rightSidebar` | | | |
### Classes
#### `.app-with-sidebar`
Is meant to be used on the body of your application when using a sidebar. See the examples below.
#### `.app-body`
Is meant to be used on the body of your application when not using a sidebar, or as a `div` under the body when using a sidebar. See the examples below.
#### `.app__header`
Is meant to be used within the `.app-body` to achieve a fixed header for your application. This can container a navbar component. See the examples below.
#### `.app__content`
Is meant to be used within the `.app-body` to wrap your main page content. It would be a sibling element between `.app__header` and `.app-footer` if you are using those. See the examples below.
#### `.app__content-no-margin`
Is an alternate to `.app__content` that does not constrain the width of the content within. This can be used if you need a side panel in your app. You can wrap your content in `.container` to still achieve the width constraint. See the examples below.
#### `.app__footer`
Is meant to be used within the `.app-body` to achieve a fixed footer for your application. See the examples below.
### Basic
The basic layout that this design system expects looks like the following:
```html
Sample Layout
```
```html
```
The header and footer are sticky and can be used with `app__header` and `app__footer`.
### Fullscreen Spinner
If you need a fullscreen spinner, use a layout like this:
```html
Sample Layout
Loading
```
```html
```
### With Sidebar
For instructions on the sidebar itself, see [Sidebar Component](components-sidebar.md)
A layout with a sidebar looks like the following:
```html
Sample Layout
```
```html
```
### With Navbar
For instructions on the navbar itself, see [Navbar Component](components-navbar.md)
A layout with a navbar looks like the following:
```html
Sample Layout
```
```html
```
### Sidebar with Navbar and Side Panel
For instructions on the side panel itself, see [Side Panel Component](components-sidepanel.md)
A layout with a side panel looks like the following:
```html
```
### Login
A layout for a login page could look like the following:
```html
```
### Utility
A layout explaining how the stack, split, cluster, and flank utilities can be used to make flex layouts more readable.
```html
Timeline with Icons
eco
Germinated in
nutrient-rich soil
May 28
forest
Matured by
water
and
sunlight
Sep 14
Timeline with Icons
eco
Germinated in
nutrient-rich soil
May 28
forest
Matured by
water
and
sunlight
Sep 14
```
### Card Grid
A responsive card grid built with the `op-grid` and `op-frame` utilities. The `op-frame` utility keeps each card's
media at a consistent aspect ratio regardless of the source image dimensions, and it isn't limited to media — the
"Coming soon" card frames a text placeholder to hold the same shape.
```html
```