A design system that fully embraces web standards ๐ค
Think of it as HTML6
So modern it feels old!
Because UI should be fun ๐ฅณ
It's freedom, baby. Yeah!
Standards #FTW
Code depressed? Call 1-800-MDASH
28 components, 220+ utility classes, and it's how small???
"Nothing is faster than nothing."
-Me
The AWS bill was $90 last month!!
You can stop reading this.
How many of these are there?
15, including this one.
Does it loop though?
No.
Introduction
What is Mdash?
Mdash is a better kind of UI library. It's 100% standards-based and it's tiny.
Mdash components are comprised of standard HTML, custom HTML, and Custom Elements. As such, Mdash works with any framework (or no framework) and works with all types of web projects, like SSR, SPA, PWA, static site, and even popular email clients.
What makes Mdash different?
Quite literally, nothing. Nothing is exactly what makes Mdash different:
- No new concepts or abstractions
- No setup or configuration
- No dependencies
- No build step
It's just HTML plus custom HTML. As a result, no other UI library is as small or easy or familiar as Mdash.
Take a look around and compare Mdash's size and markup to see how nothing really is better.
Where did Mdash come from?
Mdash is the result of building design systems in large engineering organizations where - for better or worse - tech stacks and architectures vary wildly, but the products still need to share common UI elements. It was during this time the TAC CSS methodology was created with Mdash being the first open-source implementation.
Mdash is compatible with everything
Mdash can be used anywhere HTML is used because it is HTML. Larger organizations especially benefit here because unlike other UI libraries, Mdash will work with all your products regardless of technology stack. To demonstrate, here's code samples of 13 different technologies all using the same Mdash component:
Performance
Mdash is fast! It is by all practical measures instant. The execution speed comes from leveraging native technology and reducing abstractions as much as possible in order to minimize code and retain browser optimizations. When it comes to code, nothing is faster than nothing.
In addition to execution speed, pages load faster because Mdash is so much smaller than other UI libraries:
Mdash |
|
Bootstrap |
|
Material Web 2 |
|
Zurb Foundation |
|
React Bootstrap |
|
Material-UI |
|
Semantic UI |
|
Microsoft Fabric |
|
Shoelace |
|
Material Web 3 |
|
Installation
CDN
Mdash is designed for production use with a CDN. Copy and paste the following three resources into the <head>
section of your document and you're golden.
Icon preload
<link href="https://unpkg.com/m-@3.2.0/dist/m-.woff2" rel="preload" as="font" crossorigin>
The preload option tells the browser to start downloading the icon font now instead of waiting for the stylesheet to be parsed. If you don't use icons, then you don't need this.
Stylesheet
<link href="https://unpkg.com/m-@3.2.0/dist/m-.css" rel="stylesheet">
The stylesheet includes Mdash's custom properties, the component styles, and all the utility classes.
Custom Elements
<script src="https://unpkg.com/m-@3.2.0/dist/m-.js" defer></script>
The defer option tells the browser to download the script but delay its evaluation to avoid blocking document parsing.
NPM
If the CDN is not an option, you can install the Mdash package and bundle the files.
npm install m-
Built assets (those three files above) are located in /dist
. The hyper optimization of inlining CSS is also possible with Mdash because its so small, so go for it you speed demon!
Browser support
Mdash works with the latest versions of all major browsers. Please file a bug if you see something not working as expected.
More about Mdash
The purpose
To return the UI layer back to its rightful owner: the web platform.
The UI layer - the pixels - should be built with the modern web platform. Technologies likes CSS Custom Properties, Web Components, and new HTML and JavaScript features can and should be used to create the UI layer. No dependencies needed!
The application layer - data, routing, business logic, services - should also be built with the modern web stack as well as 3rd-party libraries and frameworks.
Mdash gives you a complete set of modern compatible-with-everything UI components instantly available from a CDN. No downloads. No CLI. No configuration. No build steps. No prespiling the virtual tree-shake lint matrix, or whatever. It does this by embracing HTML (and CSS and JavaScript) and relentlessly leveraging it. The result is a fun and uniquely small design system with standards-level longevity.
Depending on the kind of project you're working on, you can use Mdash on its own or alongside your framework of choice. In the latter case, the framework is responsible for the structure and state of your application while HTML and Mdash supply the final layer of UI.
Frameworks are misused
The UI layer of web applications has been overcomplicated and made dependent upon non-standard frameworks and methodologies that, in the context of generic UI components, do not add value. Frameworks are best applied to application-centric problems like routing, state management, and high-level product-centric component structure. Frameworks are not ideal for pure UI-centric problems like layout, shared UI elements, and generic styles.
The m- prefix
A prefix is required for any custom HTML (tags or elements). The "m" is for markup, because Mdash is all about that beautiful declarative markup! And no the name "Mdash" doesn't have anything to do with Lodash. It was suggested the proper name be changed from "M-" to "Mdash" to help with search engine results.
Design philosophy
Mdash believes in and is committed to the web platform. Developing on the web is awesome because:
- It's open
- Has low barriers to entry
- Easier than other platforms
- Available on virtually every device in the world!
- Has the biggest and most active user base by far!
Mdash was designed with all that in mind. It's why CDN install is the first option and not buried or unavailable as if linking to other resources on the internet is a last resort. It's why Mdash components are built with standard, approachable tech and not a popular JavaScript library. It's why there is no special syntax or proprietary ideas and why there's no dependencies. It's why the project is open source.
The intent of the Mdash API design is to be familiar. Where possible, Mdash matches native HTML, e.g. type=""
, name=""
, disabled
, and when there isn't a native example to follow Mdash strives to use familiar patterns, e.g. dismissible="false"
for Alert was chosen because it feels similar to the native draggable="false"
attribute. If you could cover up all the m-
prefixes in your markup, the hope is you couldn't tell the difference between native HTML elements and Mdash.
It's for everyone!
The web is an open platform accessible to everyone and so a design system for the web shouldn't require advanced knowledge just to get started, and it shouldn't require a commitment to learn a specific framework's idioms and API in order to make full use of it. Mdash serves true beginners equally as well as it does professional software engineers. So, whether you're building your first website or a large scale application with millions of users, Mdash helps you quickly build UI with significantly less code and with the longevity that only comes with standards-based code.
Accordion
List of expandable details elements
Demo
Summary
Details about this thing
Summary
Details about this thing
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
m-accordion |
Custom tag | Details children only |
Guidelines
Opening all or one
Accordion does not control its details children, it only styles them. This means more than one details can be open at a time by default. Controlling this behavior can be managed by your app by adding/removing open
to the details. Details elements publish a
toggle
event makes this easy.
It's worth noting that limiting an accordion to one details at a time may result in a poor UX for users who want to reference information in multiple details and would need to constantly re-open them as they do so.
Here's two examples showing an imperative solution and a more declarative state-driven solution with Vue:
Summary
Details...
Summary
Details...
Summary
Details...
Summary
Details...
Accessibility
All accessibility recommendations apply to the Details children.
Alert
Dismissible container for escalated messages
Demo
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
m-alert |
Custom Element | Any |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
type required |
|
Sets the type of the message. Error messages should use "error", cautionary messages should use "warn", positive messages should use "success", and important informational messages should use "info". | |||||||
autodismiss |
|
If present, the Alert will automatically remove itself after 4 seconds. To increase or decrease the delay, set its value to the desired number of seconds. | |||||||
dismissible |
|
When set to "false", the dismiss button will not be displayed and the user can't dismiss the alert. The application can still directly remove the alert from the DOM or call dismiss() and autodismiss is also still effective. |
|||||||
icon |
Any icon name | Adds the specified icon. Good pairings for each type are info for info, check_circle for success, warning for warn, and error for error, but use whatever is best for your alert. |
Events
Name | Detail | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
dismiss |
None | Fires after alert has been dismissed. This happens when the user clicks the dismiss button, after autodismiss completes, or when dismiss() is called directly. |
Methods
Signature | Description | ||||||||
---|---|---|---|---|---|---|---|---|---|
dismiss() |
Removes the alert from the DOM and fires dismiss event. |
Guidelines
Alert vs. Dialog
Some information is so important it justifies interrupting the user experience. In those cases consider displaying it in a dialog instead of an alert.
Accessibility
When type
is "warn" or "error" the ARIA alert role will be added automatically. Add aria-label=""
to the dismiss button with something helpful like "Remove confirmation message".
Autocomplete
Text input for searching values or getting suggestions
Demo
API
Tags
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
m-autocomplete |
Custom Element | None | |||||||
datalist |
Native element | <option> elements |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
source required |
String | The source of data to query for matches. This must be the id of a <datalist> element or the name of a custom source function. Learn how to create them below. |
|||||||
max |
Number | Truncates the number of results to max . Autocomplete will overflow at about 10 visible results regardless of the max set. |
Events
Name | Details | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
select |
{ // Name of the source for easy reference source: '', // Value from matches value: '', // Id of match, if provided id: '' } |
Fires after a match is selected. Try it:
|
Guidelines
Creating data sources for autocomplete
Sources can come from a standard datalist
element or a custom function added to the global MdashAutocomplete
.
1. Datalist element
Include a standard datalist element in the DOM. Its id
must match the Autocomplete's source
. The options' value attributes and optional text are searched for matches. Here's an example:
2. Custom source function
These are asynchronous functions added to the static MdashAutocomplete.sources
object. Here's another fruit
example similar to the datalist above:
const matches = cache[query] || await fetchAndCacheResults(query)
, but the
Cache API is another excellent option. You can also use max
if it's beneficial while searching to know the maximum number of matches that will be shown.
Accessibility
There are no extra recommendations for Autocomplete.
Badge
Display notification counts
Demo
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
m-badge |
Custom tag | Text or the count attribute |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
count |
Number | A number to display. When zero or empty the badge will hide itself. |
Guidelines
Badge hides itself
Badge can be used to display a count or text. If either is omitted, the badge will be set to display: none
.
Localization
Localize the count value before setting it.
Accessibility
Use aria-labelledby
or aria-label
to provide context for the count.
Box
Static container for elevating content
Demo
Content outside a Box is considered neutral
See more examples
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
m-box |
Custom tag | Any |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
ord |
|
Ordinal number word for describing the content's importance. |
Guidelines
Nesting
Although possible, Boxes of the same ord
should not be nested inside each other. Nesting a secondary Box inside a primary Box is ok:
Terms of service
Boxes of the same ord
should not be nested inside each other. Nesting a secondary Box inside a primary Box is ok. You must agree to these guidelines to continue.
Box header
Because a Box header is more tricky than it seems (compensating for default padding), it doesn't get any special styles. However, it just takes a few classes to get a nice Box header:
Accessibility
There are no accessibility recommendations for Box.
Checkbox
Form element for selecting many options
Demo
See more examples
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
input |
Native element | None |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
name required |
String | All checkboxes in a group use the same name. |
Guidelines
Radio, checkbox, or select?
There's many uses cases where a single checkbox works very well and other use cases where 50 checkboxes makes sense too. If only one of the options can be selected, use radio or select.
Accessibility
Like other input elements, be sure to use for
and id
.
Container
Primary container element for page layout
Demo
maxwidth
.See more examples
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
m-container |
Custom tag | Any |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
maxwidth |
|
Sets the max width of the container, which includes some padding. "lg" grows up to 1536px, "md" starts at 800px and
shrinks down, and "sm" starts at 576px and shrinks down. Read more on maxwidth for details. |
Guidelines
More on maxwidth
By default Container will grow up to 1,536 pixels wide, which is intended to make full use of a screen up to the equivalent of a 16" MacBook Pro. You can remove this limit with none
.
In cases where there isn't a full page of content or maybe a more focused layout is desired, md
is often the right width. On-boarding flows or a promotional page are good examples where medium would be useful. In some cases a very narrow and focused layout is needed, like a log in form. Use sm
for these.
In all cases Container includes padding and centers itself in the viewport.
Multiple containers
A page can have multiple containers. This is most common when two components should share the same container characteristics, like max width and centered in the viewport, but need to have different backgrounds or other design elements that prevent sharing a single container. A site navigation is a good example:
And the rest of the page's content is here in another container.
Note how this section and the site nav's content are aligned.
Other layout elements
In addition to Mdash's Container and Grid, HTML offers a number of semantic elements for layout. From W3Schools:
<header>
Defines a header for a document or a section<nav>
Defines a container for navigation links<section>
Defines a section in a document<article>
Defines an independent self-contained article<aside>
Defines content aside from the content (like a sidebar)<footer>
Defines a footer for a document or a section
Accessibility
There are no accessibility recommendations for Container.
Details
Expandable container for progressive disclosure
Demo
Click to see details
The deets.
See more examples
API
Tags
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
details |
Native element | <summary> as first child and any other content after that |
|||||||
summary |
Native element | Any, but should be a โsummary, caption, or legend for the rest of the contents" |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
open |
Boolean attribute | When present, the details are shown (everything after summary). When removed details are hidden. If you want Details open by default, add this attribute. |
Events
Name | Detail | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
toggle |
None |
Fires after Details was opened or closed. If |
Guidelines
Is the content even necessary?
Although Details and Accordion are great tools for progressive disclosure, you should consider if the hidden content is necessary or if it could just be removed altogether.
Clickable elements inside summary
Some designs will include a button or other interactive element in <summary>
that should not toggle the details. Most elements behave as normal without toggling Details, but some, like in the example below, need an event handler to preventDefault
to stop this from happening:
Show report history
Delete
Export
Navigation
A common application of Details is an expandable navigation. Here's a working example:
Safari flexbox bug
Safari has a bug that prevents summary
from being styled as a flex container. It looks like a fix is coming. If your summary needs flexbox, add a div:
This works
...
Accessibility
The aria-expanded
attribute is managed automatically. Pressing spacebar will open/close details.
Dialog
Modal content container
Demo
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
dialog |
Native element | Any. The first element with autofocus will receive focus when the dialog is opened. |
Slot
Name | Element | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
close |
type="remove" button |
None. See Close button for details. |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
open |
Boolean attribute | Will open the Dialog when added or close when removed. If you want the dialog displayed "modelessly", you have to call the show method. |
Events
Name | Detail | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
close |
None | MDN says: "Fired when the dialog is closed, whether with the escape key, the HTMLDialogElement.close() method, or via submitting a form within the dialog with
method="dialog" ." |
|||||||
cancel |
None | MDN says: "Fired when the user dismisses the current open dialog with the escape key." |
Methods
Signature | Description | ||||||||
---|---|---|---|---|---|---|---|---|---|
close([returnValue]) |
MDN says: "Closes the dialog. An optional DOMString may be passed as an argument, updating the returnValue of the the dialog." Also note that the Dialog and its contents are still present in the DOM (e.g. forms still have user-entered values, so reset it if that's what your use case requires). | ||||||||
show() |
MDN says: "Displays the dialog modelessly, i.e. still allowing interaction with content outside of the dialog." | ||||||||
showModal() |
MDN says: "Displays the dialog as a modal, over the top of any other dialogs that might be present. Interaction outside the dialog is blocked." |
Guidelines
Close button
Dialog elements do not come with a button to close themselves, so Mdash includes style-only support for one. Add <button slot="close" type="remove">
and Mdash will style it for you, but your application must implement the click handler (e.g. calling the dialog's close
method or removing its open
attribute). Note that this is required only if a dialog doesn't implement any other buttons for closing. Here's a basic example:
Forms and DOM state
The state of the content is controlled by your application. Dialog does not change the state of its children other than moving them into a containing div on init. Forms and all other elements will initialize the way they are provided by the application and will continue to remain untouched even when the Dialog is closed. For example, if a Dialog is used to present a login form the application should remove the Dialog completely or reset the form after successful authentication. If left alone the Dialog and the login form inside it will contain the user's credentials. It's your content; you have to manage it.
Accessibility
The necessary ARIA attributes are added automatically; however, if your Dialog "contains an alert message" you should set role="alertdialog"
.
Dot
Status indicator
Demo
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
m-dot |
Custom tag | Text (optional) |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
type |
|
Sets the type of the indicator and has the same meaning as Alert's type. |
Guidelines
Dot text
In most cases Dot should include text, but sometimes it's okay to have a Dot without text (see Accessibility). An Accordion of system summaries works as a good example:
Databases
All good!
API
All good!
Notification service
Increase in avgerage response time.
Unknown type
A Dot with an unknown type is useful when a generic dot is needed. Another use case is when your app wants to display a dot, but its type is still being determined. A Loader can help communicate in these situations:
Accessibility
When there is no text use aria-label
, e.g. <m-dot type="success" aria-label="Systems okay">
.
Form elements
Basic elements used when creating forms
Demo
See more examples
API
Tags
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
form |
Native element | Any | |||||||
fieldset |
Native element | Any | |||||||
label |
Native element | Text | |||||||
small |
Native element | Text for "side-comments" associated with an input. Read more |
Attributes
Nothing special to call out. See MDN: form attributes for the full list.
Events
Name | Detail | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
submit |
None | Fires when the form is submitted, which happens when the user clicks the submit button or hits enter. | |||||||
input |
None | Fires when the value of a text-like input or text area changes. | |||||||
change |
None | Fires when a value is committed, like selecting from a list, picking a file or date, checking a box, or blurring away from a text input. |
Guidelines
Submit button vs. input button
Mdash recommends forms use <button type="submit">
instead of <input type="submit">
. This is more semantic and provides greater control of the button style and content. For example, you can't put an Icon or Loader inside a submit input.
Why <fieldset>?
Rather than inventing new tags or using boilerplate divs and classes, Mdash leverages the native fieldset tag. Although it's historically uncommon to put just one input inside a fieldset, it is perfectly valid markup. Single or multiple input combinations of various types work perfectly well and results in the most clean and uniform form code:
Why <small>?
Understand that small's semantics have to do with its type of content and not font size or other visual characteristic. The HTML spec uses examples such as "disclaimers, caveats, legal restrictions, or copyrights", which is inline with this use case. Some examples:
Accessibility
See Input, Checkbox, Radio, Select, and Textarea for their respective accessibility recommendations.
Grid
Responsive 12-column grid system
Demo
See more examples
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
m-row |
Custom tag | m-col children only |
|||||||
m-col |
Custom tag | Any |
Attributes
Name | Value | Description |
---|
For m-row only:
center |
Boolean attribute | Centers the columns in the row. |
For m-col only:
span |
[sm-|md-|lg-]1-12 | Sets the number of columns to span on a 12 column grid. Use the screen size prefixes to resize on specific screen sizes, e.g. span="9 sm-12" span 12 columns on small screens, otherwise 9. |
|||||||
indent |
[sm-|md-|lg-]1-12 | Sets the number of columns to indent on a 12 column grid. Use the screen size prefixes to resize on specific screen sizes. Indenting a column by 12 is only useful if you're animating that column back into view. | |||||||
order |
[sm-|md-|lg-]1-12 | Overrides the order of the column in its row. Use the screen size prefixes to reorder columns for specific screen sizes. |
Guidelines
Nesting Grids
Grids can be nested inside other grids to create complex responsive layouts. Two or even three Grids deep are normal, but any more than that and your implementation could be poorly designed.
Simpler solutions
Although Grid is very capable, avoid the temptation to use it for everything. Sometimes a utility class is sufficient. Compare the three centered headings below to see how Grid may not always be the right solution:
Example 1
Example 2
Example 3
Accessibility
There are no accessibility recommendations for Grid.
Icons
Symbols used to enhance communication
Demo
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
m-icon |
Custom tag | None |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
name required |
See available icons below | Sets the icon's symbol | |||||||
fill |
Boolean attribute | Uses filled version |
Guidelines
Available icons
Mdash now uses Material Symbols Outlined. On that page, getting an icon name is easier if you click the icon, then select the Android tab, then copy the name.
Pair with some text
Icons should be used to enhance content not replace it. Users can misinterpret icons, so strive to accompany an icon with a label or other relevant content in close proximity.
If an icon is on its own, use the title
attribute to explain what it symbolizes (e.g. "Your current location") or its action (e.g. "Reload this page", like your browser's refresh icon). Hover over the user icon for a clue:
Why not SVG?
Implementing SVG icons requires a relatively expensive abstraction and because there is no visual or accessibility difference between SVG and glyph icons, that abstraction would be all cost and no benefit. Mdash icons require no JavaScript and so they save kilobytes and have maximum compatibility.
Accessibility
Because icons should be paired with some text (see above) they should reference that text with aria-labelledby
attribute. In cases where there is no label, use
aria-label
and title
.
Input
Form element for receiving user input
Demo
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
input |
Native element | None |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
type |
|
Sets the expected type of value. Take care to set email, tel, password, and number inputs based on use case to ensure optimal user experience.
See checkbox, radio, and range for details on those specific types. |
|||||||
disabled |
Boolean attribute | Disables the input so it can't be changed or interacted with. It will be skipped when tabbing and its value will not be submitted with the form. | |||||||
readonly |
Boolean attribute | Makes the input read-only, which means the user can't change its value, but can still tab to it and copy the text. Its value will be submitted with the form. | |||||||
invalid |
Boolean attribute | Highlights input as having an invalid value. When the input is invalid it should have a small element explaining how to correct it. Validation is owned by your application not Mdash. | |||||||
placeholder |
String | Displays a message inside the input. Ideal for showing an expected format or sample value. | |||||||
autofocus |
Boolean attribute | If present, the browser will bring focus to this element on page load. Excellent for log in or search pages or whenever the first interaction is likely to type something. | |||||||
autocomplete |
|
These are required in order for the browser to autofill the form. Not all values are shown here! See the complete list and learn more at MDN: HTML autocomplete attribute. |
Guidelines
Use the right type
It's very important to take the time to understand what values a user can enter in a given input and to use the right type
for those values. If, for example, the input is for a membership number then using type="number"
will present an easier to use numbers-only keyboard on most touch devices. The same goes for email and phone numbers. These UX optimizations are important to users and are virtually free to implement, so take a moment to ensure you're using the right input type.
Accessibility
Labels should use the for
attribute to reference the id of its corresponding input. Inputs should use the right type (see above), autofocus, and autocomplete to improve their usability.
Keyboard
Represents text from an input device
Demo
Press โงโT to close window
Ctrl + NAPI
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
kbd |
Native element (documentation) | Text or other kbd elements |
Guidelines
Formatting
Mdash doesn't define a format for keyboard shortcuts because there are many popular ways to do it. Shortcuts are also platform-specific and so it is recommended to follow the format used by the user's OS. There are several ways to detect OS using the Navigator object.
Windows seems to use a format that includes + characters to indicate a combination of key presses, like Ctrl + C.
macOS seems to use a sequence of characters to indicate a combination of key presses, like โC. Symbols are used for modifier keys (see below).
Be careful how you show the + character. Users can misinterpret it as representing a required key.
macOS Modifier Key Symbols
To create macOS keyboard shortcuts, copy these symbols:
- โ - Command key
- โง - Shift key
- โฅ - Option/Alt key
- โ - Control key
- โช - Caps Lock key
Accessibility
There are no accessibility recommendations for the keyboard element.
Link
Used for navigating
Demo
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
a |
Native element | Any |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
href required |
|
Sets the type of link. Be sure to use target fragments or the other URL schemes correctly to ensure optimal user experience. Every phone number, for example, should be wrapped in a link with the |
|||||||
disabled |
Boolean attribute | Disables the link. |
For span elements only:
role required |
link | Styles the element as a link. Use this instead of <a> when your use case is not a real link. |
Guidelines
Security
When linking to websites you don't control, you should add the rel="noopener"
attribute.
Open link in new tab
Quite often it is more convenient for users to open links in a new browser tab. This is especially true when a link goes to another website or when the link is on a page (or in a place on a page) that the user would have trouble getting back to. Simply add target="_blank"
.
Accessibility
Links should behave as links, i.e. they activate when clicked. Links that don't behave this way should not use the anchor tag and should instead use a span
with role="link"
attribute to avoid confusing screen-readers. Also, groups of links like menus, breadcrumbs, or primary navigation should be contained in a nav
element.
Loader
Indicates a processing state
Demo
See more examples
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
m-loader |
Custom tag | Text (optional) |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
loading |
Boolean attribute | When present the loader will rotate infinitely. Without it Loader remains still. |
Guidelines
Loader text
In most cases the loader should have its own text or be in close proximity to a related message, like a button label. In some cases it's appropriate to have a loader on it's own without a message (in those cases see Accessibility).
Loader size
The default size works for most use cases, but you can enlarge or shrink Loader with the text size utility classes or set its own font size:
Nesting Loader
Loader will inherit font properties, so when it's nested in elements like button, anchor, or headings it looks as you would expect it to:
Accessibility
If a Loader doesn't have text it should use
aria-labelledby
or aria-label
.
Radio input
Form element for picking one of many choices
Demo
See more examples
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
input |
Native element | None |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
name required |
String | All radios in a group use the same name. |
Guidelines
Radio, checkbox, or select?
If only one of the options can be selected, don't use checkbox. There are no hard rules, but generally radio is best for 2-4 choices and select (or Autocomplete) is better for more.
Accessibility
Like other input elements, be sure to use for
and id
.
Range Slider
Form element for fine-grained values
Demo
See more examples
API
Tags
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
input[type="range"] |
Native element | None | |||||||
output |
Native element | The value of range |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
min |
Number | Minimum value, default is 0 | |||||||
max |
Number | Maximum value, default is 100 | |||||||
step |
Number | Sets the granularity of values, default is 1 | |||||||
orient coming soon |
vertical | Displays the range vertically |
Events
Name | Detail | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
change |
None | Fires after the value is committed. | |||||||
input |
None | Fires as the value changes. |
Guidelines
Displaying range values
A common use case is to display the value of range as it updates. Mdash leaves that part of the design open for customization, but with the one requirement to use the standard <output>
element to contain the value.
Here's two simple designs to get you started:
Accessibility
Use for
and id
as usual, but also use for
on output
elements. MDN has more details
ARIA: Using the slider role.
Select
Drop-down list of choices
Demo
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
select |
Native element | <option> or <optgroup> children |
|||||||
optgroup |
Native element | <option> children |
|||||||
option |
Native element | Text |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
label |
String | Displayed as the <optgroup> heading. |
|||||||
value |
String | Used as the value of the element. |
Events
Name | Detail | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
change |
None | Fired after an option was selected. |
Guidelines
{{> more-autocomplete}}Accessibility
Label should use the for
attribute to reference the id of its corresponding select.
Separator
An element that divides sections of content or groups of menu items
Demo
Content
Content
API
Tags
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
hr |
Native element | None |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
aria-orientation |
vertical |
Displays the separator vertically. Must have a Flexbox or Grid parent (use display utility classes). |
Guidelines
Where to use
Separators are useful in menus, toolbars, and written content.
Avoid using too many separators. Font size, font weight, whitespace, color contrast and other common visual characteristics are usually enough to create the needed distinction between elements.
Accessibility
The hr element has an implicit role="separator"
, so don't add it. There is also no need to set aria-orientation="horizontal"
since it's the default.
Switch
A control for toggling binary values like on/off
Demo
See more examples
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
input[type=checkbox] |
Native element | None |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
role required |
switch | Defines the checkbox as a switch. | |||||||
checked |
Boolean attribute | Standard checkbox attribute | |||||||
disabled |
Boolean attribute | Standard checkbox attribute |
Events
Name | Detail | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
input |
None | Switch is a checkbox, so you can listen to the same standard input event. | |||||||
change |
None | Switch is a checkbox, so you can listen to the same standard change event. |
Guidelines
Standalone or form
A switch can be used on its own or more commonly as a list of options in a form, like this:
Network settings
Accessibility
MDN says, "The first rule of ARIA is if a native HTML element or attribute has the semantics and behavior you require, use it instead of re-purposing an element and adding ARIA. Instead use the native HTML checkbox of <input type="checkbox">
, which natively provides all the functionality required."
Table
Used for tabular data
Demo
Product | |
---|---|
Socks | $9.99 |
Shorts | $19.99 |
Sweater | $29.99 |
Shoes | $49.99 |
API
Tags
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
table |
Native element | <thead> (optional) and <tbody> |
|||||||
thead |
Native element | <tr> with <th> children |
|||||||
tbody |
Native element | <tr> with <td> children, first child can be <th> for row headings |
|||||||
tfoot |
Native element | <tr> with <td> children |
Attributes
For <table> only:
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
layout |
fixed | Table cells are sized automatically by the browser. This doesn't always produce the desired layout, so use this option with colspan to control the layout. Note this option does not mean the table size won't change at all - it'll still respond nicely to screen size. |
|||||||
striped |
Boolean attribute | Creates a visual distinction between alternate rows. |
For <td> and <th> only:
colspan |
Number | Defines how many columns the cell should span. |
For <th> only:
aria-sort |
|
Defines that column as sorted. Your application is responsible for the sorting behavior. |
Guidelines
Not for page layout
Use Grid for creating a page's layout. Do not use Table.
Accessibility
The sorted column must have the appropriate aria-sort
value. When the user clicks a sort button, add aria-pressed="true"
to it to indicate the pressed state.
Tabs
Master-detail pattern for navigating content
Demo
See selecting tabs to learn how to select a tab
API
Tags
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
m-tabs |
Custom tag | button or a children |
Attributes
Name | Value | Description |
---|
For m-tabs only:
scrollable |
Boolean attribute | Makes the tab list horizontally scrollable. In some cases, like flex grow, overflow doesn't happen and so the parent element will need an explicit width (try the width-full utility class). |
For tab only:
aria-selected |
true or false | Set the selected tab to true. See Selecting tabs for examples. | |||||||
disabled |
Boolean attribute | Disables the tab. |
Guidelines
Selecting tabs
Selecting the tab
Setting the selected tab is handled by your app. To select a tab, set aria-selected="true"
. There are a several approaches you could take to manage this, but event delegation comparing tabs to the clicked tab is probably the simplest without a framework:
That will only select the tab. Selecting the corresponding tab panel is explained next.
Showing a tab panel
Mdash assumes nothing about what happens when a tab is selected, which allows for multiple solutions like toggling the hidden
attribute, directly changing the DOM, rendering different components, navigating to a new page, or something else. Here's an example of the typical use case of selecting a tab and showing its panel:
Here's the same thing with a more declarative approach using Riot.js, for example:
Accessibility
All of the necessary ARIA attributes are here in the example below:
Tag
Used for keywords, labeling, and filters
Demo
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
m-tag |
Custom tag | Text, icon, or link and optional remove button for removable tags |
Guidelines
Removable tags
Simply include a remove button and, using your preferred method, attach a click handler that removes the tag. Here's a basic example:
Accessibility
Use aria-label
and title
when the Tag only contains an icon:
Text area
Multi-line input
Demo
API
Tag
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
textarea |
Native element | Text |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
rows |
Number | Sets a starting height that will accommodate the given number of rows, i.e. lines of text. This does not prevent additional lines from being typed and the user can also resize it to be taller or shorter. | |||||||
maxlength |
Number | Limits the number of characters allowed in the text area. | |||||||
minlength |
Number | Sets a minimum required number of characters in the text area. |
Guidelines
Sensible row size
The default is three rows, i.e. three lines of text, but you should set a number that makes the most sense for your use case. For example, a chat app makes sense to take the default of three, but a customer feedback form should likely have 5-10. Note that text areas are resizable so the user can extend it further if needed, just take care to set a sensible default.
Accessibility
There are no accessibility recommendations for text area.
Code
For displaying text as code
Demo
code
element for inline code and the pre
element for multiple lines of code:const user = await fetch(url, init); alert(user.name);
API
Tags
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
code |
Native element | Text | |||||||
pre |
Native element | Multi-line text |
Guidelines
Security
Because these elements' content is code, take extra care to ensure you're preventing cross-site scripting. There's nothing that makes these elements more or less secure than any other, but in this case you know for sure you're dumping code into the DOM, so be careful!
Accessibility
You should use aria-label
and/or aria-description
to explain the code. For example:
fetch(url, init)
Headings
Headings elements
Demo
Heading 1
Heading 2
Heading 3
Heading 4
Heading 5
Heading 6
API
Tags
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
h1-h6 |
Native element | Any | |||||||
hgroup |
Native element | One heading and one or more paragraphs |
Guidelines
SEO
Using heading elements improves SEO and accessibility.
Accessibility
Strive to use the heading elements. If your situation doesn't allow for that, there is role="heading"
and aria-level
for defining the same.
Lists
Lists of data or content
Demo
- Foo
- Bar
- Baz
- Foo
- Bar
- Baz
- Foo
- Bar
- Baz
- Foo
- Bar
- Baz
API
Tags
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
ul |
Native element | <li> children |
|||||||
ol |
Native element | <li> children |
|||||||
dl |
Native element | <dt> and <dd> children |
Attributes
Name | Value | Description | |||||||
---|---|---|---|---|---|---|---|---|---|
type |
|
Defines a vertical list of content. Used for implementing designs like the master-detail pattern. See guideline below. |
For ul only:
type |
|
Sets the marker type |
For ol only:
type |
|
Sets the marker type | |||||||
reversed |
Boolean attribute | Reverses the order of items | |||||||
start |
Number | Sets the starting number |
Guidelines
Lists are for lists
List elements should be used for real lists. It's tempting to overuse them for anything that repeats, so take time to think about some better alternatives to list elements that should be used instead. For example, one alternative is the nav
element when building a navigation bar:
Content list type
The content list type is meant for building a vertical list of content.
Semantics and accessibility
To retain list semantics and accessibility, Mdash leverages the standard tags for content lists. Use the correct tag for the content, i.e. if order matters use ol
, otherwise ul
. Example:
Ordered, like steps in a recipe:
- Prep Cook rice the day before ๐
- Step 1 Preheat wok on high heat, add 2 tbsp. oil ๐ฅ
- Step 2 Chop veggies and meat ๐ง๐ฅฉ
- Step 3 Add everything to wok and stir fry ๐ซ
- Step 4 Top with fresh basil and serve ๐ฟ
Unordered, like notification preferences:
- SMS
- Push
Nesting
Content list is designed to work wherever you need it. It can be used on its own or, for example, nested in a dialog, menu, or a box like this:
- one
- two
- three
Alternatives
Be intentional. Not every vertical layout is a content list. Sometimes you don't need any particular component at all. In some cases you have tabular content, so use a table. In other cases you may just need horizontal rules, like this recreation of the GitHub sidebar:
About
The modern web's design system.
Releases
Packages
Accessibility
Use the correct list parent elements for your use case, i.e. ol
when the list order is meaningful and ul
when it isn't.
Text
Paragraph and other text-based elements
Demo
This is a paragraph with some bold text and some italic text. More text variations can be done using the utility classes.
This is for small print, side-comments, disclaimers, etc.This is something somebody said.
API
Tags
Name | Type | Content | |||||||
---|---|---|---|---|---|---|---|---|---|
p |
Native element | Any | |||||||
blockquote |
Native element | p element for the actual quotation |
|||||||
small |
Native element | Any, but intended to represent "side-comments...small print, like copyright and legal text, independent of its styled presentation." |
Guidelines
Characters per line
It is recommend that lines of text be no more than 65-75 characters, including spaces (Designing With Type, James Craig). This makes for a more comfortable reading experience. Usability studies dating back to the 1970's show readers experience fatigue with text running longer than this.
To demonstrate, the paragraph above has no width limit while that same paragraph below maxes out at 75ch using the txt-maxlength
utility class:
It is recommend that lines of text be no more than 65-75 characters, including spaces (Designing With Type, James Craig). This makes for a more comfortable reading experience. Usability studies dating back to the 1970's show readers experience fatigue with text running longer than this.
SEO
Using these text semantically will improve SEO and accessibility.
Accessibility
The smallest font size that Mdash has is 13px, which is the smallest recommended by WCAG 2.1. Any smaller can be illegible for some users.
Custom Properties
Design tokens referenced internally and externally for custom styles
Demo
API
Colors
All color values are in the perceptually uniform color space to provide visually appealing colors while still achieving a11y contrast guidelines.
Name | Example | Description | |||||
---|---|---|---|---|---|---|---|
--m-color-red-[1|2|3] |
|
Used to denote something has or will go wrong. | |||||
--m-color-orange-[1|2|3] |
|
Used for bringing attention to something that may not be desirable. | |||||
--m-color-blue-[1|2|3] |
|
Used to highlight primary actions. | |||||
--m-color-green-[1|2|3] |
|
Used to communicate something desirable has or will happen. | |||||
--m-color-gray-[7|8|9] |
|
Used for text and high-contrast backgrounds. | |||||
--m-color-gray-[1|2|3|4|5|6] |
|
Grayscale used for backgrounds, borders, and disabled state. | |||||
--m-color-primary-action |
|
Used for links and other primary action elements. | |||||
--m-color-disabled-[bg|fg] |
|
Disabled background and foreground. | |||||
--m-color-border |
|
Default border color. |
Spacing
The spacing sizes are based on Divine Proportions to help provide a natural rhythm. Padding, margin, and gap use these values.
Name | Value | Description | |||||
---|---|---|---|---|---|---|---|
--m-space-[xs|sm|md|lg|xl] |
6px, 12px, 18px, 30px, 48px | Used for developing a visual rhythm between elements. Loosely follows Divine Proportion. You should use the
padding and margin utility classes whenever possible and reserve use of --m-space-* for other spacing needs like position. |
Element styles
All elements use these values for their relevant styles.
Name | Value | Description | |||||
---|---|---|---|---|---|---|---|
--m-border-radius-[sm|md|full] |
2px, 4px, fully round | Used for border radius. |
Breakpoints
Although custom properties are unfortunately not usable in media queries, these breakpoint values are useful elsewhere.
The large breakpoint and above are considered desktop-sized
Name | Value | Description | |||||
---|---|---|---|---|---|---|---|
--m-breakpoint-sm |
576px | The portrait width of an iPhone X. | |||||
--m-breakpoint-md |
768px | The portrait width of an iPad. | |||||
--m-breakpoint-lg |
992px | The landscape width of an iPad. |
Other
Name | Value | Description | |||||
---|---|---|---|---|---|---|---|
--m-font-family |
'Helvetica Neue', Arial | The typefaces in use. | |||||
--m-max-content-width |
1320px | The max width used by Container. Wrapping your content in a m-container is more likely what you need, but you can use this if necessary. |
|||||
--m-min-input-height |
34px | The min height used for form elements. Reference this if you'd like your element to match the height of inputs. |
Guidelines
Do not hard code values
Facebook famously had 548 unique colors hard-coded 6,498 times across all their stylesheets. Custom properties are a modern CSS feature that helps you avoid such a mess by defining reusable values. Use custom properties instead of hard coding their values. Like this:
Go here to learn more about custom properties and how to use them.
Accessibility
The colors and spacing meet accessibility requirements.
Utility Classes
220+ CSS shortcuts and utility classes
Demo
API
Categories: Display Flexbox Spacing Position Font Text Border Background Other
Display
Name | Description | ||||||
---|---|---|---|---|---|---|---|
grid |
Shortcut for display: grid | ||||||
inline-grid |
Shortcut for display: inline-grid | ||||||
flex |
Shortcut for display: flex | ||||||
inline-flex |
Shortcut for display: inline-flex | ||||||
block |
Shortcut for display: block | ||||||
inline-block |
Shortcut for display: inline-block | ||||||
inline |
Shortcut for display: inline | ||||||
hidden |
Shortcut for display: none. Consider using the HTML hidden attribute instead. |
Flexbox
Name | Description | ||||||
---|---|---|---|---|---|---|---|
flx-grow-0 |
Shortcut for flex-grow: 0 | ||||||
flx-grow-1 |
Shortcut for flex-grow: 1 | ||||||
flx-shrink-0 |
Shortcut for flex-shrink: 0 | ||||||
flx-shrink-1 |
Shortcut for flex-shrink: 1 | ||||||
flx-wrap |
Shortcut for flex-wrap: wrap | ||||||
flx-col |
Shortcut for flex-direction: column | ||||||
flx-row |
Shortcut for flex-direction: row | ||||||
flx-basis-content |
Shortcut for flex-basic: content | ||||||
justify-content-start |
Shortcut for justify-content: flex-start | ||||||
justify-content-center |
Shortcut for justify-content: center | ||||||
justify-content-between |
Shortcut for justify-content: between | ||||||
justify-content-evenly |
Shortcut for justify-content: evenly | ||||||
justify-content-around |
Shortcut for justify-content: around | ||||||
justify-content-end |
Shortcut for justify-content: flex-end | ||||||
align-items-center |
Shortcut for align-items: center | ||||||
align-items-start |
Shortcut for align-items: flex-start | ||||||
align-items-end |
Shortcut for align-items: flex-end | ||||||
align-self-stretch |
Shortcut for align-self: stretch | ||||||
align-self-center |
Shortcut for align-self: center | ||||||
align-self-start |
Shortcut for align-self: flex-start | ||||||
align-self-end |
Shortcut for align-self: flex-end | ||||||
place-content-center |
Shortcut for place-content: center |
Spacing
Name | Description | |||||||
---|---|---|---|---|---|---|---|---|
pad-[xs|sm|md|lg|xl|0] |
Sets padding on all sides to the specified size. Sizes map to the
space custom props and 0 really means zero. |
|||||||
pad-[t|r|b|l]-[xs|sm|md|lg|xl|0] |
Sets padding on the specified side (top, right, bottom, or left) in the specified size. Sizes map to the
space custom props and 0 really means zero. |
|||||||
mar-[xs|sm|md|lg|xl|0|auto] |
Sets margin on all sides to the specified size. Sizes map to the
space custom props and 0 really means zero. |
|||||||
mar-[t|r|b|l]-[xs|sm|md|lg|xl|0|auto] |
Sets margin on the specified side (top, right, bottom, or left) in the specified size. Sizes map to the
space custom props and 0 really means zero. |
|||||||
gap-[xs|sm|md|lg|xl|0] |
Sets gap to the specified size. Sizes map to the
space custom props and 0 really means zero. |
Position
Name | Description | ||||||
---|---|---|---|---|---|---|---|
pos-absolute |
Shortcut for position: absolute | ||||||
pos-fixed |
Shortcut for position: fixed | ||||||
pos-relative |
Shortcut for position: relative | ||||||
pos-static |
Shortcut for position: static | ||||||
pos-sticky |
Shortcut for position: sticky | ||||||
pos-[t|r|b|l]-0 |
Shortcut for setting top, right, bottom, or left to zero |
Font
Name | Description | ||||||
---|---|---|---|---|---|---|---|
fnt-bold |
Shortcut for font-weight: 700 | ||||||
fnt-med |
Shortcut for font-weight: 500 | ||||||
fnt-reg |
Shortcut for font-weight: 400 | ||||||
fnt-light |
Shortcut for font-weight: 300 | ||||||
fnt-italic |
Shortcut for font-style: italic | ||||||
fnt-mono |
Shortcut for font-family: monospace | ||||||
fnt-normal |
Shortcut for font-style: normal |
Text
Name | Description | ||||||
---|---|---|---|---|---|---|---|
txt-left |
Shortcut for text-align: left | ||||||
txt-right |
Shortcut for text-align: right | ||||||
txt-center |
Shortcut for text-align: center | ||||||
txt-justify |
Shortcut for text-align: justify | ||||||
txt-lower |
Shortcut for text-transform: lowercase | ||||||
txt-upper |
Shortcut for text-transform: uppercase | ||||||
txt-caps |
Shortcut for text-transform: capitalize | ||||||
txt-space |
Shortcut for letter-spacing: 2px | ||||||
txt-truncate |
Truncates overflowing text and shows an ellipsis. | ||||||
txt-nowrap |
Shortcut for white-space: nowrap. Good for forcing inline elements to stretch wide enough to accommodate the text. | ||||||
txt-break-all |
Shortcut for word-break: break-all. Good for permitting characters to wrap when there's not enough room. | ||||||
txt-break-word |
Shortcut for word-break: break-word. Good for permitting words to wrap when there's not enough room. | ||||||
txt-maxlength |
Shortcut for max-width: 75ch. Good for limiting text line length to improve readability. See Readability: The Optimal Line Length | ||||||
txt-noselect |
Prevents the user from selecting the text of this element. | ||||||
txt-[xs|sm|md|lg|xl|xxl] |
Sets font-size. | ||||||
txt-[color-name] |
Sets text color. The class names map to the
color custom props, e.g. txt-red-dark => --m-color-red-dark . |
||||||
txt-[info|success|warn|error] |
Sets text color to the alert type. |
Border
Name | Description | ||||||
---|---|---|---|---|---|---|---|
brd |
Adds a border. | ||||||
brd-[t|r|b|l] |
Adds a border to the specified side. | ||||||
brd-none |
Removes border from all sides. | ||||||
brd-radius-[sm|md|full] |
Sets border radius. Use full to create a circle. |
||||||
brd-[sm|md] |
Sets border width. | ||||||
brd-dashed |
Sets border style to dashed . Good for placeholders and drop targets. |
Background
Name | Description | ||||||
---|---|---|---|---|---|---|---|
bg-clip-text |
Clips background to match foreground text. | ||||||
bg-cover |
Background will be scaled to fill entire area of element. The aspect ratio is preserved, but the image may be cropped. | ||||||
bg-contain |
Background will be scaled to fit size of element. The aspect ratio is preserved and the image will not be cropped. | ||||||
bg-[color-name] |
Sets background color. The class names map to the
color custom props, e.g. bg-red-dark => --m-color-red-dark . |
Other
Name | Description | ||||||
---|---|---|---|---|---|---|---|
pointer |
Shortcut for cursor: pointer. Useful when you want an element to seem clickable. Buttons and links already have pointer set. | ||||||
height-full |
Shortcut for height: 100% | ||||||
height-half |
Shortcut for height: 50% | ||||||
height-min-0 |
Shortcut for min-height: 0 | ||||||
width-full |
Shortcut for width: 100% | ||||||
width-half |
Shortcut for width: 50% | ||||||
width-fit |
Shortcut for width: fit-content | ||||||
width-min-0 |
Shortcut for min-width: 0 | ||||||
box-sizing-border |
Shortcut for box-sizing: border-box | ||||||
box-sizing-content |
Shortcut for box-sizing: content-box | ||||||
overflow-auto |
Shortcut for overflow: auto | ||||||
overflow-hidden |
Shortcut for overflow: hidden | ||||||
overflow-clip |
Shortcut for overflow: clip (good for rounded corners) | ||||||
vis-hidden |
Shortcut for visibility: hidden | ||||||
shadow |
Adds default shadow | ||||||
content-vis-auto |
Shortcut for content-visibility: auto. Use on large sections of content not visible to the user after page load. The browser skips rendering and layout until needed thereby reducing the initial page rendering time. | ||||||
left |
Shortcut for float: left | ||||||
right |
Shortcut for float: right | ||||||
clear |
Shortcut for clear: both | ||||||
all-unset |
Shortcut for all: unset |
Guidelines
Reduce CSS maintenance
You can drastically cut down and even eliminate your CSS maintenance by leveraging these classes as much as possible.
Create and use templates
The demo above with all those classes is fine on its own or even 2-3 copies sitting next to each other, but beyond that you'll want a way to reuse chunks of HTML.
Reuse is possible with the <template>
element or template literals (see below). If standard tools aren't enough, templating partials or static components are another low-code option. Avoid the temptation to turn every chunk of HTML into a framework-dependent component.
Accessibility
There are no accessibility recommendations for these classes.