* first pass at starlight
* converting to starlight
* working on converting to starlight
* working on data
* watch custom-elements.json
* turn on pagefind
* add component meta data
* fix renderings / overrides.
* fix mdx logo
* continue starlight work
* building site
* get global styles + reloads working
* themer fixes
* adding additional headings
* working on dynamic content
* have TableOfContents.astro push to TOC
* working on code stuff
* remove code preview
* deploy
* add patch package
* patch in build
* patch in build
* remove {% raw %} calls
* convert to starlight...complete
* prettier
* update lockfile
* merge main
* fix index.mdx
* prettier'
* fix small things
* docs updates
* add dark mode shortcut
* prettier
* prettier
* prettier
* remove pagefind from public
* add twitteR
* prettier
* fix tests
* prettier
* remove square, stretch, and squish spacing tokens
* remove units from base tokens
* rename corner tokens with t-shirt size scale
* rename 'font-size' tokens to 'size'
* rename 'neutral' primitives to 'base'
* remove black and white tokens
* improve 'form-controls' tokens
* reintroduce granular focus ring tokens
* fix themer styles
* tweak shadow styles
* improve naming and scope of foundational colors
* overhaul color naming and add new themes
* more classic sl component styles
* make 'chic' theme dark by default
* adjust table row colors
* remove deprecated properties from 'classic' theme
* remove mistakenly committed stylesheets
* revert adjustment to space properties
* delete web-types.json
* revert "rename 'font-size' tokens to 'size'"
* Move custom properties related to shadows and borders to separate stylesheets
* Change base values and themer calculations related to shadows and borders to be unitless
* Add low-level custom properties for alert, button, card, input, select, switch, and textarea
* Add generic guidance for authoring custom properties to the Contributing docs
* [RFC] Proof-of-concept commit for submenu support
This is a Request For Comments to seek directional guidance towards
implementing the submenu slot of menu-item.
Includes:
- SubmenuController to manage event listeners on menu-item.
- Example usage in menu-item documentation.
- Trivial tests to check rendering.
Outstanding questions include:
- Accessibility concerns. E.g. where to handle 'ArrowRight',
'ArrowLeft'?
- Should selection of menu-item denoting submenu be possible or
customizable?
- How to parameterize contained popup?
- Implementation concerns:
- Use of ref / id
- delegation of some rendering to the controller
- What to test
Related to [#620](https://github.com/shoelace-style/shoelace/issues/620).
* Update submenu-controller.ts
Removed extraneous `console.log()`.
* PoC working of ArrowRight to focus on submenu.
* Revert "PoC working of ArrowRight to focus on submenu."
(Didn't mean to publish this.)
This reverts commit be04e9a221.
* [WIP] Submenu WIP continues.
- Submenus now close on change-of-focus, not a timeout.
- Keyboard navigation support added.
- Skidding fix for better alignment.
- Submenu documentation moved to Menu page.
- Tests for accessibility, right and left arrow keys.
* Cleanup: Removed dead code and dead code comments.
* style: Eslint warnings and errors fixed. npm run verify now passes.
* fix: 2 changes to menu / submenu on-click behavior:
1. Close submenu on click explicitly, so this occurs even if the menu is
not inside of an sl-dropdown.
2. In menu, ignore clicks that do not explicitly target a menu-item.
Clicks that were on (e.g. a menu-border) were emitting select events.
* fix: Prevent menu's extraneous Enter / space key propagation.
Menu's handleKeyDown calls item.click (to emit the selection).
Propagating the keyboard event on Enter / space would the cause re-entry
into a submenu, so prevent the needless propagation.
* Submenu tweaks ...
- 100 ms delay when opening submenus on mouseover
- Shadows added
- Distance added to popup to have submenus overlap menu slightly.
* polish up submenu stuff
* stay highlighted when submenu is open
* update changelog
* resolve feedback
---------
Co-authored-by: Bryce Moore <bryce.moore@gmail.com>
* Never select tree items when clicking the chevron
This changes the behaviour of sl-tree so that clicking on the expand/collapse icon will not select/deselect the item, only toggle it's expanded state.
* Refactor: inline SlTree.syncTreeItems
This was only called from 2 places, and they each had different
behaviour anyways.
* SlTree: separate expand/collapse from selection
This makes 'multi' and 'single' mode consistent with each other, and
with native file managers.
* feat(clipboard): add new component sl-clipboard
* using slots
* using a single copyStatus
* feat(clipboard): support inputs/textarea/links and shadow dom
* fix(clipboard): add area-live to announce copied
* feat(clipboard): support any component with a value property
* initial attempt at not auto defining
* add files with -
* continued work on removing auto-define
* fix component definitions
* update with new tag stuff
* fix lots of things
* fix improper scoped elements
* working through side effects
* continued react wrapper work
* update changelog
* formatting
* fixes
* update changelog
* lint / formatting
* fix version injection
* fix version injection, work on test
* fix version injection, work on test
* fix merge conflicts
* fix jsdoc null issue
* fix templates
* use exports
* working on tests
* working on registration mocking
* fix customElements test
* linting
* fix some test stuff
* clean up test
* clean up comment
* rename scopedElements to dependencies
* linting / formatting
* linting / formatting
* mark all packages external and still bundle
* set bundle false
* set bundle true
* dont minify
* fix merge conflicts
* use built shoelace-element
* fix lint errors
* prettier
* appease eslint
* appease eslint gods
* appease eslint gods
* appease eslint gods
* appease eslint gods
* add shoelace-autoloader
* move it all into 1 function
* add exportmaps note
* prettier
* add jsdelivr entrypoint
* read as utf8
* update docs with .component.js importS
* prettier
* Move keydown handler for sl-drawer back to base div
This restores the stacking behaviour of drawers
See: #1457
* Autofocus panel of sl-drawer when it is open on firstUpdate
* Rename SlSlideChange for consistency with other events
* Setup React event types for events used by Shoelace components
Means that consumers of Shoelace via the React wrapper will be able to
use callback methods with the correct event type, instead of having to
rely on casting and friends when using Typescript.
* Add docs demonstrating importing event types for React callbacks
* add modal tab tracking
* prettier
* sort by tabindex
* sort by tabindex
* add a dialog test case for shadow roots
* add a changelog note
* add a changelog note
* prettier + test fixes
* prettier + test fixes
* Add tests for qr-code
* Fix a small bug in qr-code
The background color was not passed to the
qr code
---------
Co-authored-by: Dominikus Hellgartner <dominikus.hellgartner@gmail.com>
The current statement is incorrect and will result in
`Module not found: Package path ./dist/shoelace is not exported from package /your/path/to/node_modules/@shoelace-style/shoelace (see exports field in /your/path/to/node_modules/@shoelace-style/shoelace/package.json)`
* Added tests for sl-split-panel
test for horizontal arrangement
* Added tests for sl-split-panel
tests for vertical arrangement
---------
Co-authored-by: stefanie.hellgartner <stefanie.hellgartner@in-tech.com>
* add regression test for checkbox focusing
* change number of checkboxes / switches
* change max-height to 400px so it fails
* re-add positon: relative;
* Improve performance of sl-icon by caching later
* Fixed error handling
* Don't use requestInclude in sl-icon
* Separate sl-icon errors into cacheable and retryable errors
* Fix acessability issue
* Additionally adapted the test
* Added more accessability tests
* Updated the testing documentation
to take the fact that accessability checks cover only
rendered content into account
---------
Co-authored-by: Dominikus Hellgartner <dominikus.hellgartner@gmail.com>
Did not manage to check
that the properties are correctly passed
to the animation api at this point so this
stays a blackbox test
Co-authored-by: Dominikus Hellgartner <dominikus.hellgartner@gmail.com>
The reason for the problems is that the error event does
not escape from the shadow dom.
Thus it cannot be awaited for in the test
Co-authored-by: Dominikus Hellgartner <dominikus.hellgartner@gmail.com>
* fix(carousel): don't resume autoplay if interacting
* fix(carousel): wrap pagination items
* chore(carousel): add unit tests
* feat(carousel): more reactive pagination dots
* fix(carousel): trigger scrollend when user scroll exactly over a snap point
* Resize observer sometimes throws errors which
are nothing to worry about, see also the corresponding
comment on tab-group.test.ts
* Unfortunately, the web testing library installs an
error event handler which takes precedence before the
event handlers installed in the tests
(see node_modules/@web/browser-logs/dist/logUncaughtErrors.js)
* the only possibility to avoid these null logs is to install
an error event handler at an even earlier place
Co-authored-by: Dominikus Hellgartner <dominikus.hellgartner@gmail.com>
* Improved tests for SlAlert
* added more test for coverage
* Grouped tests in multiple subgroups
* remove executing only one tests
* Fix the now executing tests
---------
Co-authored-by: Dominikus Hellgartner <dominikus.hellgartner@gmail.com>
* #1163 - added read-only properties 'validity' and 'validationMessage' to all nine form controls
* #1163 - added base support for showing form validation messages below the form controls
* #1163 - animated validation errors in demo
* #1181 - Removed all previous changes that have been validation error specific
* Started with 'Inline validation' demo / fixed merge issues / etc.
* #1181 - continued work on missing form validation features
* #1181 - enhanced validation support for SlColorPicker / some cleanup
* #1181 - fixed CSS issues
* #1181 - fixed again CSS issues
* '1181 - added form validation features finally working
* #1181 - bug fixes
* #1181 - fixed open issues / added API doc comments
* #1181 - updated inline validation demos / removed some legacy code
* #1181 - finished invalid form validation example
* #1181 - added tests / several bugfixes
* #1181 - fixed typos etc.
* #1181 - tests
* #1181 - tests
* #1181 - tests
* dropdown filtered menu items
* updated filter, added test
- updated filter to match menu getAllItems private method
- added test
---------
Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
* remove duplicate test
* Add tests for sl-tab-group -- initial round of tests
* use individual fixtures for each test
* extract mocks + utility functions in external files
* remove unnecessary internals of intersection observer from the mock
* added first test on scroll buttons
* add scrolling tests
* remove resize observer mock
Resize observer is triggered but waiting for element
to be updated is not enough. You need to free the main thread
with the test for some time
* Also removed intersection observer mock
By waiting long enough for the things to happen automatically
* Fix problems with resize observer
These problems appeared after npm ci but (according
to the sources linked in the comments) unproblematic
* Handle merge request comments
* replace custom wait function with corresponding function
from openwc/testing
* Extracted waitForScrollingToEnd and isElementVisibleFromScrolling into
dedicated files to be reused
* Improve queryByTestId --> make it usable for more complex values
* Add js docs
* run lint fix
* Added tests for selecting a tab by click
* added further tests for tab group selection
* use Promise<void> instead of Promise<any>
to avoid eslint errors
---------
Co-authored-by: Dominikus Hellgartner <dominikus.hellgartner@gmail.com>
* Initial example of a JSON schema and converter for design tokens
* Clean up script and relocate file
* Update token JSON format and finish build process
* removed checked and indeterminate parts from doc
* Revert "removed checked and indeterminate parts from doc"
This reverts commit 5e702387e1ace4e5d6b424f861df8e6a3a1a4fdd.
* control--checked & control--indeterminate parts
* sl-color-picker use lib '@ctrl/tinycolor' instead of 'color'
typescript, esm and smaller
* parseColor adjustments
removed normalizeColorString and other tweaks
* added hsv format
* fixed const
* Fix mapping in exports
Fixes#1019
- Add correct mapping for public entrypoints.
* Remove shoelace.js from from exports list
Should still works fine while importing this way: import { thing } from '@shoelace-style/shoelace';
* added stepUp and stepDown to sl-range
* step function & default props tests for sl-range
* stepUp, stepDown & showPicker functions for input
* step functions & default props tests for sl-input
* made name and placeholder default to empty string
* updated changelog
Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
add check to input component if japanese character is chosen by pressing enter key and prevent form submitting
Co-authored-by: VitaliyMaznyi <vitalii.maznyi@fasterthanlight.me>
* Added tests for sl-relative-time
* Solves a blinker which appears only when I run
the full test suite: Chromium and webkit are fine
but sometimes there is this one error on firefox
for the disabled test of the menu item (saying there
was a timeout waiting). Did not happen again after
doing the change.
Co-authored-by: Dominikus Hellgartner <dominikus.hellgartner@gmail.com>
* move component description from docs to component
* use component description in docs
* add style for lead sentence, keep bc for not updated components
* run `npm prettier`
* render summary as part of the header
* add `title` as another custom tag for JSDoc
* render components title in header
* provide possibility to render components "description" into docs with `[component-description:COMPONENT_NAME]`
* the meta summary should be rendered into header too
* Avoid bubbling events for sl-include
I ran into an issue where icons inside of an HTML include were dispatching `sl-load` events, which was causing my `sl-include` event handler to run multiple times. By adding these guards, we ensure only events immediately dispatched by the element itself will be handled.
* Use the correct event variable
The description for the checkbox's value attribute is currently "the checkbox's value attribute." I think we can do better than that, especially considering anyone who hasn't worked with old-school HTML forms that POST to the URL in the `action` attribute is unlikely to know why a checkbox has a value and that value is not boolean.
While I was here I improved a couple of other descriptions. If there's an interest, I can expand this PR to update all of the properties in all controls where the description is tautological.
* Tooltip: Recalculate target after slotchange
The tooltip's positioning breaks after a slotchange, unless the tooltips target is recalculated.
* Update src/components/tooltip/tooltip.test.ts
Co-authored-by: Cory LaViska <cory@abeautifulsite.net>
* initial button tests and setup helpers
* fix as many linting errors as I could
* switch back to regular fixtures
* test(button|button-group|divider|format-bytes) add tests for more components
* add tests for format util components
* finish format-number tests
* remove unnecessary ignore
* Create integrating-with-laravel.md
Instructions for using Shoelace components in a Laravel 8.x application.
* Update integrating-with-laravel.md
Added a section for setting the base path and switched to using the full import path for each component. Also included a full `bootstrap.js` example.
* test: migrate skipped tests to the breadcrumb-item
* test: when rendering a HTMLAnchorElement
* test: add checks for classes.
* test: uplift langauge and query selector to test label part
* test: default button test
* refactor: set default for rel on prop declaration.
* test: introduce first pass test for components/avatar
feat: set alt="" on img element
* test: resolve img src 404 errors
* test: remove bad test
* test: test children by assigning nodes...
* test: add patches similar to badge patch
* style: address typing issues.
The sl-input's value state being `undefined` is very common when using shoelace with frameworks. Instead of erroring out and not showing the input, this should handle it gracefully.
* Add prefix and suffix slot to sl-select component
* Adding align-items: center in prefix/suffix and changing documentation to showcase using as visual aids
* automate github release creation
Adds a workflow file to create a GitHub release, when a version tag is pushed.
* set fix latest version of auto release action
The path to assets should be consistent and not depend on the current script source. There are at least two situations when this assumption fails:
- When running `webpacker-dev-server`, the _pack_ URL doesn't contain `/js/` part.
- In test environment, `/packs-test` is used by default.
@@ -35,7 +35,7 @@ This Code of Conduct applies within all project spaces, and it also applies when
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at cory@abeautifulsite.net. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at support@fontawesome.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
about: Create a bug report to help us fix a demonstrable problem with code in the library.
title: ''
labels: bug
assignees: claviska
assignees:
---
**Describe the bug**
A clear and concise description of what the bug is.
### Describe the bug
A bug is _a demonstrable problem_ caused by code in the library. Please provide a clear and concise description of what the bug is here.
**To Reproduce**
### To Reproduce
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
2. Click on '...'
3. Scroll down to '...'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
### Demo
**Screenshots**
If applicable, add screenshots to help explain your problem.
If the bug isn't obvious, please provide a link to a CodePen or Fiddle with a minimal reproduction. Bugs that have repros get attention faster than those that don't.
**Desktop (please complete the following information):**
- OS: [e.g. iOS]
- Browser [e.g. chrome, safari]
- Version [e.g. 22]
Tip: use the CodePen button on any example in the docs!
**Smartphone (please complete the following information):**
- Device: [e.g. iPhone6]
- OS: [e.g. iOS8.1]
- Browser [e.g. stock browser, safari]
- Version [e.g. 22]
### Screenshots
If applicable, add screenshots to help explain the bug.
**Additional context**
Add any other context about the problem here.
### Browser / OS
- OS: [e.g. Mac, Windows]
- Browser: [e.g. Chrome, Firefox, Safari]
- Browser version: [e.g. 22]
### Additional information
Provide any additional information about the bug here.
# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name:Node.js CI
on:
push:
branches:[next]
pull_request:
branches:[next]
jobs:
build:
runs-on:ubuntu-latest
strategy:
matrix:
node-version:[18.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
Shoelace is an open source project, meaning everyone can use it and contribute to its development. When you join our community, you'll find a friendly group of enthusiasts at all experience levels who are willing to chat about anything and everything related to Shoelace.
Before contributing, please review the contributions guidelines at:
The easiest way to get started contributing is to join the [community chat](https://discord.gg/mg8f26C). This is where we hang out, discuss new ideas, ask for feedback, and more!
A common misconception about contributing to an open source project is that you need to know how to code. This simply isn't true. In fact, there are _many_ ways to contribute, and some of the most important contributions come from those who never write a single line of code. Here's a list of ways you can make a meaningful contribution to the project:
- Submitting well-written bug reports
- Submitting feature requests that are within the scope of the project
- Improving the documentation
- Responding to users that need help in the community chat
- Triaging issues on GitHub
- Being a developer advocate for the project
- Sponsoring the project financially
- Writing tests
- And, of course, contributing code!
Please take a moment to review these guidelines to make the contribution process as easy as possible for both yourself and the project's maintainers.
## Using the Issue Tracker
The [issue tracker](https://github.com/shoelace-style/shoelace/issues) is for bug reports, feature requests, and pull requests.
- Please **do not** use the issue tracker for personal support requests. Please [join the community chat](https://discord.gg/mg8f26C) or [ask your question](https://stackoverflow.com/questions/ask) on StackOverflow instead.
- Please **do not** derail, hijack, or troll issues. Keep the discussion on topic and be respectful of others.
- Please **do not** post comments with "+1" or "👍". Use [reactions](https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) instead.
- Please **do** use the issue tracker for feature requests, bug reports, and pull requests.
Issues that do not follow these guidelines are subject to closure. There simply aren't enough resources for the author and contributors to troubleshoot personal support requests.
### Feature Requests
Feature requests can be added using the issue tracker.
- Please **do** search for an existing request before suggesting a new feature.
- Please **do** use the "👍" reaction to vote for a feature.
- Please **do** share substantial use cases and perspective that support new features if they haven't already been mentioned.
- Please **do not** bump, spam, or ping contributors to prioritize your own feature.
If you would like your feature prioritized, please consider [sponsoring the project](https://github.com/sponsors/claviska).
### Bug Reports
A bug is _a demonstrable problem_ caused by code in the library. Bug reports are an important contribution to the quality of the project. When submitting a bug report, there are a few steps you can take to make sure your issues gets attention quickly.
- Please **do not** paste in large blocks of irrelevant code
- Please **do** search for an existing issue before creating a new one
- Please **do** explain the bug clearly
- Please **do** provide a minimal test case that demonstrates the bug (e.g. [jsfiddle.net](https://jsfiddle.net/) or [CodePen](https://codepen.io/))
- Please **do** provide additional information, when necessary, to replicate the bug
**A minimal test case is critical to a successful bug report.** It demonstrates that the bug exists in the library and not in surrounding code. Contributors should be able to understand the bug without studying your code, otherwise they'll probably move on to another bug.
If you would like your bug prioritized, please consider [sponsoring the project](https://github.com/sponsors/claviska).
### Pull Requests
To keep the project on track, please consider the following guidelines before submitting a PR.
- Please **do not** submit a PR without opening an issue first, especially for non-trivial changes. This may prevent you from doing work that won't be accepted for various reasons (e.g. someone is already working on it, it's not a good fit for the project, it needs additional planning, etc.)
- Please **do** make sure your PR clearly defines what you're changing. Even if you feel your changes are obvious, please explain them so other contributors can more easily review your works. PRs without detailed descriptions are subject to closure pending more details.
- Please **do not** edit anything in `dist/`. These files are generated automatically, so you need to edit the source files instead.
The author reserves the right to reject any PR that's outside the scope of the project or doesn't meet code quality standards.
### Branches
`current` - This branch reflects the latest release and powers [shoelace.style](https://shoelace.style/).
`next` - This branch is where pull requests will land. It reflects what's coming in the _next_ release, which can be previewed at [next.shoelace.style](https://next.shoelace.style/).
## Conventions
This section aims to describe some of the design decisions and code conventions that support the project. All contributors are expected to follow conventions and best practices, even those not explicitly defined in this document. When in doubt, refer to existing source code and execute your best judgment.
In order to keep the project in a maintainable state, code that doesn't follow conventions and best practices will need to be refactored before it will be accepted. This isn't a knock on your code or your style — it's something the author considers necessary to operate a successful open source project.
### Semantic Versioning
Shoelace follows [Semantic Versioning](https://semver.org/). Breaking changes in components with the "Stable" badge will not be accepted until the next major version. As such, all contributions must consider the project's roadmap and take this into consideration. Features that are deemed no longer necessary will be deprecated but not removed.
Components with the "Experimental" badge should not be used in production. They are made available as release candidates for development and testing purposes. As such, changes to experimental components will not be subject to semantic versioning.
### Code Formatting & Linting
The majority of code formatting is handled automatically by [Prettier](https://prettier.io/) at build time. However, for the best experience, you should [install it in your editor](https://prettier.io/docs/en/editors.html) and enable format on save.
Linting is run automatically at build time. By design, the project will not build if the linter is unhappy. Contributors are strongly encouraged to install an ESLint plugin for your editor for the best developer experience.
### BEM Class Names
All components use a [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM), so styles are completely encapsulated from the rest of the document. As a result, class names _inside_ a component won't conflict with class names _outside_ the component, so we're free to name them whatever we want.
Internally, each component uses the [BEM methodology](http://getbem.com/) for its class names. There is no technical requirement to do this — it's purely the preference of the author. However, all contributions are expected to follow this practice for the sake of consistency.
## Developer Tips
### Documentation is the key to success
Nobody likes writing documentation, but not having good docs is frustrating to users and makes the project less appealing. Fortunately, writing documentation for Shoelace is really easy!
A lot of the documentation is generated automatically based on JSDoc comments in each component's source code. If you have ESLint enabled, your editor will tell you when a comment is missing. This may feel a bit naggy, but it's a very good thing. Every property, method, event, etc. is documented this way. By adding comments as you code, the docs are more easily kept up to date.
The documentation pages are served up by [Docsify](https://docsify.now.sh/). Check out `docs/_sidebar.md` and `docs/components/` to get an idea of how pages are created and formatted. If you're creating a new component, it may help to use an existing component's markdown file as a template.
If you need help with documentation, feel free to reach out!
### Choose composability when possible
When designed right, web components are highly composable, meaning you can easily reuse them in other components. This reduces the overall size of the library, expedites feature development, and maintains a consistent user experience throughout.
The select component, for example, makes use of the dropdown, input, and menu components. Because it's offloading most of its functionality and styles to these lower-level components, the select component remains very lightweight and its appearance and behavior is consistent with other form controls and menus.
### When to use a standard property vs. a CSS custom property
When designing a component's API, standard properties ("props") are generally used to change the _behavior_ of a component, whereas CSS custom properties ("CSS variables") are used to change the _appearance_ of a component. Remember that props can't respond to media queries, but CSS variables can.
There are some exceptions to this (e.g. when it significantly improves developer experience), but a good rule of thumbs is "will this need to change based on screen size?" If so, you probably want to use a CSS variable.
### Custom event names
All custom events must start with `sl-` as a namespace. For compatibility with frameworks that utilize DOM templates, custom events must have lowercase, kebab-style names. For example, use `sl-change` instead of `slChange`.
This convention avoids the problem of browsers lowercasing attributes, causing some frameworks to be unable to listen to them. This problem isn't specific to one framework, but [Vue's documentation](https://vuejs.org/v2/guide/components-custom-events.html#Event-Names) provides a good explanation of the problem.
> Additionally, `v-on` event listeners inside DOM templates will be automatically transformed to lowercase (due to HTML’s case-insensitivity), so `v-on:myEvent` would become `v-on:myevent` – making `myEvent` impossible to listen to.
### When to use a CSS custom property vs. a CSS part
There are two ways to enable customizations for components. One way is with CSS custom properties ("CSS variables"), the other is with CSS parts ("parts").
CSS variables are scoped to the host element and can be reused throughout the component. A good example of a CSS variable would be `--border-width`, which might get reused throughout a component to ensure borders share the same width for all internal elements.
Parts let you target a specific element inside the component's shadow DOM but, by design, you can't target a part's children or siblings. You can _only_ customize the part itself. Use a part when you need to allow a single element inside the component to accept styles.
This convention can be relaxed when the developer experience is greatly improved by not following these suggestions.
### Boolean Props
Boolean props should _always_ default to `false`, otherwise there's no way for the user to unset it without JavaScript. To keep the API as friendly and consistent as possible, use a name like `noHeader` with a default value of `false` instead of `header` with a default value of `true`.
### A Note About Sass
The Shoelace _source_ is developed using Sass for the convenience of nested selectors, imports, and tedious things such as color palette generation. By design, Sass variables, color functions, and other preprocessor-specific feaures are not used in the source and will not be accepted in a PR.
Consumers of the library should never need to worry about preprocessing the library.
### Positioning Popovers
Shoelace uses an internal popover utility for dropdowns, tooltips, etc. This is a light abstraction of Popper.js designed to make positioning and transitioning things easy and consistent throughout the library. When possible, use this utility instead of relying on Popper directly. See `src/utilities/popover.ts` for details.
### Host and Base Elements
All components have a host element, which is a reference to the actual `<sl-*>` elements. Make sure to always set the host element's `display` property to the appropriate value depending on your needs, as the default is `inline` per the HTML spec.
```css
:host{
display:inline-block;
}
```
Aside from `display`, avoid setting properties on the host element when possible. The reason for this is that styles applied to the host element are not encapsulated. Instead, create a base element that wraps the internals and style that instead. This convention also makes it easier to use BEM in components.
```css
.sl-example{
/* This is the base element */
}
.sl-example--primary{
/* Primary modifier */
}
```
To expose custom properties for a component, define them in the `:host` block and use the following syntax for comments so they appear in the generated docs.
```css
/**
* @param --color: The component's text color.
* @param --background-color: The component's background color.
*/
:host{
--color:white;
--background-color:tomato;
display:inline-block;
}
```
### Conditional Slots
When a component relies on the presence of slotted content to do something, don't assume its initial state is permanent. Slotted content can be added or removed any time and components must be aware of this. A good practice to manage this is:
- Create a `handleSlotChange` method that uses `hasSlot` (imported from `src/utilities/slot.ts`) to update state variables for the associated slot(s)
- Add `onSlotchange={this.handleSlotChange}` to the slots you want to watch
- Never conditionally render `<slot>` elements in a component — always use `hidden` so the slot remains in the DOM and the `slotchange` event can be captured
See the source of card, dialog, or drawer for examples.
### Form Controls
Form controls should support validation through the following conventions:
- All form controls must an `invalid` prop that reflects its validity
- All form controls must have a `setCustomValidity()` method so the user can set a custom validation message
- All form controls must have a `reportValidity()` method that reports its validity during form submission
- All form controls should mirror their native validation attributes such as `required`, `pattern`, `minlength`, `maxlength`, etc. when possible
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Shoemakers, or "Shoelace developers," can use this documentation to learn how to build Shoelace from source. You will need Node >= 12.10.0 to build and run the project locally.
Developers can use this documentation to learn how to build Web Awesome from source. You will need Node >= 14.17 to build and run the project locally.
**You don't need to do any of this to use Shoelace!** This page is for people who want to contribute to the project, tinker with the source, or create a custom build of Shoelace.
**You don't need to do any of this to use Web Awesome!** This page is for people who want to contribute to the project, tinker with the source, or create a custom build of Web Awesome.
If that's not what you're trying to do, the [documentation website](https://shoelace.style) is where you want to be.
### What are you using to build Shoelace?
### What are you using to build Web Awesome?
Components are built with [Stencil](https://stenciljs.com/), a compiler that generates standards-based web components. The source code is a combination of TypeScript + JSX (TSX). Stylesheets are written in SCSS.
The build is done through a combination of Stencil's CLI and a handful of custom scripts.
Components are built with [LitElement](https://lit-element.polymer-project.org/), a custom elements base class that provides an intuitive API and reactive data binding. The build is a custom script with bundling powered by [esbuild](https://esbuild.github.io/).
### Forking the Repo
Start by [forking the repo](https://github.com/shoelace-style/shoelace/fork) on GitHub, then clone it locally and install dependencies.
Once you've cloned the repo, run the following command.
```bash
npm run start
npm start
```
This will spin up the Shoelace dev server. Note that the dev server requires ports 4000, 4001, and 4002 to be available.
After the initial build, a browser will open at `http://localhost:4000`.
Hot module reloading (HMR) is enabled for components, so changes will instantly reflect in the browser as you work. The documentation is powered by Docsify, which uses raw markdown files to generate pages. As such, no static files are built for the docs. Unfortunately, changes to _documentation pages_ will trigger a page refresh (no HMR).
This will spin up the dev server. After the initial build, a browser will open automatically. There is currently no hot module reloading (HMR), as browser's don't provide a way to reregister custom elements, but most changes to the source will reload the browser automatically.
### Building
@@ -67,22 +59,20 @@ To generate a production build, run the following command.
npm run build
```
### Creating New Components
To scaffold a new component, run the following command, replacing `wa-tag-name` with the desired tag name.
```bash
npm run create wa-tag-name
```
This will generate a source file, a stylesheet, and a docs page for you. When you start the dev server, you'll find the new component in the "Components" section of the sidebar.
### Contributing
Shoelace is an open source project and contributions are encouraged! If you're interesting in contributing, please review the [contribution guidelines](CONTRIBUTING.md) first.
Web Awesome is an open source project and contributions are encouraged! If you're interesting in contributing, please review the [contribution guidelines](CONTRIBUTING.md) first.
## License
Shoelace is designed in New Hampshire by [Cory LaViska](https://twitter.com/claviska). It’s available under the terms of the MIT license.
Designing, developing, and supporting this library requires a lot of time, effort, and skill. I’d like to keep it open source so everyone can use it, but that doesn’t provide me with any income.
**Therefore, if you’re using my software to make a profit,** I respectfully ask that you help [fund its development](https://github.com/sponsors/claviska) by becoming a sponsor. There are multiple tiers to choose from with benefits at every level, including prioritized support, bug fixes, feature requests, and advertising.
👇 Your support is very much appreciated! 👇
- [Become a sponsor](https://github.com/sponsors/claviska)
- [Star on GitHub](https://github.com/shoelace-style/shoelace/stargazers)
- [Follow on Twitter](https://twitter.com/shoelace_style)
Whether you're building Shoelace or building something _with_ Shoelace — have fun creating! 🥾
Web Awesome is available under the terms of the MIT license.
The content in this example was included from <ahref="/assets/examples/include.html"target="_blank">a separate file</a>. 🤯
</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Lectus vestibulum mattis ullamcorper velit sed ullamcorper morbi. Fringilla urna porttitor rhoncus dolor purus non enim. Nullam vehicula ipsum a arcu cursus vitae congue mauris. Gravida in fermentum et sollicitudin.</p>
<p>Cursus sit amet dictum sit amet justo donec enim. Sed id semper risus in hendrerit gravida. Viverra accumsan in nisl nisi scelerisque eu ultrices vitae. Et molestie ac feugiat sed lectus vestibulum mattis ullamcorper velit. Nec ullamcorper sit amet risus nullam. Et egestas quis ipsum suspendisse ultrices gravida dictum. Lorem donec massa sapien faucibus et molestie. A cras semper auctor neque vitae.</p>
<script>
console.log('This will only execute if the `allow-scripts` prop is present');
To display an alert as a toast notification, or "toast", create the alert and call its `toast()` method. This will move the alert out of its position in the DOM and into [the toast stack](#the-toast-stack) where it will be shown. Once dismissed, it will be removed from the DOM completely. To reuse a toast, store a reference to it and call `toast()` again later on.
You should always use the `closable` prop so users can dismiss the notification. It's also common to set a reasonable `duration` when the notification doesn't require acknowledgement.
For convenience, you can create a utility that emits toast notifications with a function call rather than composing them in your HTML. To do this, generate the alert with JavaScript, append it to the body, and call the `toast()` method as shown in the example below.
The toast stack is a fixed position singleton element created and managed internally by the alert component. It will be added and removed from the DOM as needed when toasts are shown. When more than one toast is visible, they will stack vertically in the toast stack.
By default, the toast stack is positioned at the top-right of the viewport. You can change its position by targeting `.sl-toast-stack` in your stylesheet. To make toasts appear at the top-left of the viewport, for example, use the following styles.
```css
.sl-toast-stack {
left: 0;
right: auto;
}
```
?> By design, it is not possible to show toasts in more than one stack simultaneously. Such behavior is confusing and makes for a poor user experience.
Animate elements declaratively with over 500 baked-in presets, or roll your own with custom keyframes. Powered by the [Web Animations API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Animations_API).
To animate an element, wrap it in `<sl-animation>` and set a `name` and `duration`.
?> The animation will be applied only to the first child element found in `<sl-animation>`.
## Examples
### Animations & Easings
This example demonstrates all of the baked-in animations and easings. All animations were generated based on the popular [Animate.css](https://animate.style/) and [Animista](https://animista.net/) projects.
playbackRate.tooltipFormatter = val => `Playback Rate = ${val}`;
</script>
<style>
.animation-sandbox .box {
width: 100px;
height: 100px;
background-color: var(--sl-color-primary-50);
}
.animation-sandbox .controls {
max-width: 300px;
margin-top: 2rem;
}
.animation-sandbox .controls sl-select {
margin-bottom: 1rem;
}
</style>
```
### Using Intersection Observer
Use an [Intersection Observer](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) to control the animation when an element enters or exits the viewport. For example, scroll the box below in and out of your screen. The animation stops when the box exits the viewport and restarts each time it enters the viewport.
When you don't have an image to use, you can set the `initials` attribute to show something more personalized than an icon.
```html preview
<sl-avatar initials="SL"></sl-avatar>
```
### Custom Icons
When no image or initials are set, an icon will be shown. The default avatar shows a generic "user" icon, but you can customize this with the `icon` slot.
```html preview
<sl-avatar>
<sl-icon slot="icon" name="image"></sl-icon>
</sl-avatar>
<sl-avatar>
<sl-icon slot="icon" name="archive"></sl-icon>
</sl-avatar>
<sl-avatar>
<sl-icon slot="icon" name="briefcase"></sl-icon>
</sl-avatar>
```
### Shapes
Avatars can be shaped using the `shape` attribute.
Badges are used to draw attention and display statuses or counts.
```html preview
<sl-badge>Badge</sl-badge>
```
## Examples
### Types
Set the `type` attribute to change the badge's type.
```html preview
<sl-badge type="primary">Primary</sl-badge>
<sl-badge type="success">Success</sl-badge>
<sl-badge type="info">Info</sl-badge>
<sl-badge type="warning">Warning</sl-badge>
<sl-badge type="danger">Danger</sl-badge>
```
### Pill Badges
Use the `pill` attribute to give badges rounded edges.
```html preview
<sl-badge type="primary" pill>Primary</sl-badge>
<sl-badge type="success" pill>Success</sl-badge>
<sl-badge type="info" pill>Info</sl-badge>
<sl-badge type="warning" pill>Warning</sl-badge>
<sl-badge type="danger" pill>Danger</sl-badge>
```
### Pulsating Badges
Use the `pulse` attribute to draw attention to the badge with a subtle animation.
```html preview
<div class="badge-pulse">
<sl-badge type="primary" pill pulse>1</sl-badge>
<sl-badge type="success" pill pulse>1</sl-badge>
<sl-badge type="info" pill pulse>1</sl-badge>
<sl-badge type="warning" pill pulse>1</sl-badge>
<sl-badge type="danger" pill pulse>1</sl-badge>
</div>
<style>
.badge-pulse sl-badge:not(:last-of-type) {
margin-right: 1rem;
}
</style>
```
### With Buttons
One of the most common use cases for badges is attaching them to buttons. To make this easier, badges will be automatically positioned at the top-right when they're a child of a button.
```html preview
<sl-button>
Requests
<sl-badge pill>30</sl-badge>
</sl-button>
<sl-button style="margin-left: 1rem;">
Warnings
<sl-badge type="warning" pill>8</sl-badge>
</sl-button>
<sl-button style="margin-left: 1rem;">
Errors
<sl-badge type="danger" pill>6</sl-badge>
</sl-button>
```
### With Menu Items
When including badges in menu items, use the `suffix` slot to make sure they're aligned correctly.
It's often helpful to have a button that works like a link. This is possible by setting the `href` attribute, which will make the component render an `<a>` under the hood. This gives you all the default link behavior the browser provides (e.g. <kbd>CMD/CTRL/SHIFT + CLICK</kbd>) and exposes the `target` and `download` attributes.
?> When a `target` is set, the link will receive `rel="noreferrer noopener"` for [security reasons](https://mathiasbynens.github.io/rel-noopener/).
### Setting a Custom Width
As expected, buttons can be given a custom width by setting its `width`. This is useful for making buttons span the full width of their container on smaller screens.
Use the `caret` prop to add a dropdown indicator when a button will trigger a dropdown, menu, or popover.
```html preview
<sl-button size="small" caret>Small</sl-button>
<sl-button size="medium" caret>Medium</sl-button>
<sl-button size="large" caret>Large</sl-button>
```
### Loading
Use the `loading` prop to make a button busy. The width will remain the same as before, preventing adjacent elements from moving around. Clicks will be suppressed until the loading state is removed.
Set the color picker's format with the `format` attribute. Valid options include `hex`, `rgb`, and `hsl`. Note that the color picker will accept any parsable format (including CSS color names) regardless of this option.
Details show a brief summary and expand to show additional content.
```html preview
<sl-details summary="Toggle Me">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</sl-details>
```
## Examples
### Disabled
Use the `disable` attribute to prevent the details from expanding.
```html preview
<sl-details summary="Disabled" disabled>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</sl-details>
```
### Grouping Details
Details are designed to function independently, but you can simulate a group or "accordion" where only one is shown at a time by listening for the `sl-show` event.
```html preview
<div class="details-group-example">
<sl-details summary="First" open>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</sl-details>
<sl-details summary="Second">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
</sl-details>
<sl-details summary="Third">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
By design, a dialog's height will never exceed that of the viewport. As such, dialogs will not scroll with the page ensuring the header and footer are always accessible to the user.
By default, the drawer slides out of its [containing block](https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#Identifying_the_containing_block), which is usually the viewport. To make the drawer slide out of its parent element, add the `contained` prop and `position: relative` to the parent.
By design, a drawer's height will never exceed 100% of its container. As such, drawers will not scroll with the page to ensure the header and footer are always accessible to the user.
Dropdowns expose additional content that "drops down" in a panel.
Dropdowns consist of a trigger and a panel. By default, activating the trigger will expose the panel and interacting outside of the panel will close it.
Dropdowns are designed to work well with [menus](/components/menu.md) to provide a list of options the user can select from. However, dropdowns can also be used in lower-level applications (e.g. [color picker](/components/color-picker.md) and [select](/components/select.md)). The API gives you complete control over showing, hiding, and positioning the panel.
The preferred placement of the dropdown can be set with the `placement` attribute. Note that the actual position may vary to ensure the panel remains in the viewport.
```html preview
<sl-dropdown placement="top-start">
<sl-button slot="trigger" caret>Edit</sl-button>
<sl-menu>
<sl-menu-item>Cut</sl-menu-item>
<sl-menu-item>Copy</sl-menu-item>
<sl-menu-item>Paste</sl-menu-item>
<sl-menu-divider></sl-menu-divider>
<sl-menu-item>Find</sl-menu-item>
<sl-menu-item>Replace</sl-menu-item>
</sl-menu>
</sl-dropdown>
```
### Distance
The distance from the panel to the trigger can be customized using the `distance` attribute. This value is specified in pixels.
```html preview
<sl-dropdown distance="30">
<sl-button slot="trigger" caret>Edit</sl-button>
<sl-menu>
<sl-menu-item>Cut</sl-menu-item>
<sl-menu-item>Copy</sl-menu-item>
<sl-menu-item>Paste</sl-menu-item>
<sl-menu-divider></sl-menu-divider>
<sl-menu-item>Find</sl-menu-item>
<sl-menu-item>Replace</sl-menu-item>
</sl-menu>
</sl-dropdown>
```
### Skidding
The offset of the panel along the trigger can be customized using the `skidding` attribute. This value is specified in pixels.
```html preview
<sl-dropdown skidding="30">
<sl-button slot="trigger" caret>Edit</sl-button>
<sl-menu>
<sl-menu-item>Cut</sl-menu-item>
<sl-menu-item>Copy</sl-menu-item>
<sl-menu-item>Paste</sl-menu-item>
<sl-menu-divider></sl-menu-divider>
<sl-menu-item>Find</sl-menu-item>
<sl-menu-item>Replace</sl-menu-item>
</sl-menu>
</sl-dropdown>
```
### Hoisting
Dropdown panels will be clipped if they're inside a container that has `overflow: auto|hidden`. The `hoist` attribute forces the panel to use a fixed positioning strategy, allowing it to break out of the container. In this case, the panel will be positioned relative to its containing block, which is usually the viewport unless an ancestor uses a `transform`, `perspective`, or `filter`. [Refer to this page](https://developer.mozilla.org/en-US/docs/Web/CSS/position#fixed) for more details.
When dropdowns are used with [menus](/components/menu.md), you can listen for the `sl-select` event to determine which menu item was selected. The menu item element will be exposed in `event.detail.item`. You can set `value` props to make it easier to identify commands.
Alternatively, you can listen for the `click` event on individual menu items. Note that, using this approach, disabled menu items will still emit a `click` event.
Forms collect data that can easily be processed and sent to a server.
All Shoelace components make use of a [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) to encapsulate markup, styles, and behavior. One caveat of this approach is that native `<form>` elements will not recognize Shoelace form controls.
This component solves that problem by serializing _both_ Shoelace form controls and native form controls when the form is submitted. The resulting form data is exposed in the `sl-submit` event as a [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) object in `event.detail.formData`. You can also find an array of form controls in `event.detail.formControls`.
Shoelace forms don't make use of `action` and `method` attributes and they don't submit the same was as native forms. To handle submission, you need to listen for the `sl-submit` event as shown in the example below and make an XHR request with the resulting form data.
// Example 2: Output all form control names + values
//
for (const entry of formData.entries()) {
output += `${entry[0]}: ${entry[1]}\n`;
}
alert(output);
//
// Example 3: Get all form controls that were serialized as
// an array of HTML elements
//
console.log(event.detail.formControls);
});
</script>
```
## Form Control Validation
Client-side validation can be enabled through the browser's [Constraint Validation API](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation) for many form controls. You can enable it using props such as `required`, `pattern`, `minlength`, and `maxlength`. As the user interacts with the form control, the `invalid` attribute will reflect its validity based on its current value and the constraints that have been defined.
When a form control is invalid, the containing form will not be submitted. Instead, the browser will show the user a relevant error message. If you don't want to use client-side validation, you can suppress this behavior by adding `novalidate` to the `<sl-form>` element.
All form controls support validation, but not all validation props are available for every component. Refer to a component's documentation to see which validation props it supports.
Note that validity is not checked until the user interacts with the control or its containing form is submitted. This prevents required controls from being rendered as invalid right away, which can result in a poor user experience. If you need this behavior, set the `invalid` attribute initially.
!> Client-side validation can be used to improve the UX of forms, but it is not a replacement for server-side validation. **You should always validate and sanitize user input on the server!**
### Required Fields
To make a field required, use the `required` prop. The form will not be submitted if a required form control is empty.
const form = document.querySelector('.input-validation-required');
form.addEventListener('sl-submit', () => alert('All fields are valid!'));
</script>
```
### Input Patterns
To restrict a value to a specific [pattern](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/pattern), use the `pattern` attribute. This example only allows the letters A-Z, so the form will not submit if a number or symbol is entered. This only works with `<sl-input>` elements.
const form = document.querySelector('.input-validation-type');
form.addEventListener('sl-submit', () => alert('All fields are valid!'));
</script>
```
### Custom Validation
To create a custom validation error, use the `setCustomValidity` method. The form will not be submitted when this method is called with anything other than an empty string, and its message will be shown by the browser as the validation error. To make the input valid again, call the method a second time with an empty string as the argument.
const form = document.querySelector('.input-validation-custom');
const input = form.querySelector('sl-input');
form.addEventListener('sl-submit', () => alert('All fields are valid!'));
input.addEventListener('sl-input', () => {
if (input.value === 'shoelace') {
input.setCustomValidity('');
} else {
input.setCustomValidity('Hey, you\'re supposed to type \'shoelace\' before submitting this!');
}
});
</script>
```
### Custom Validation Styles
The `invalid` attribute reflects the form control's validity, so you can style invalid fields using the `[invalid]` selector. The example below demonstrates how you can give erroneous fields a different appearance. Type something other than "shoelace" to demonstrate this.
To opt out of the browser's built-in validation and use your own, add the `novalidate` attribute to the form. This will ignore all constraints and prevent the browser from showing its own warnings when form controls are invalid.
Remember that the `invalid` prop on form controls reflects validity as defined by the [Constraint Validation API](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation). You can set it initially, but the `invalid` prop will update as the user interacts with the form control. As such, you should not rely on it to set invalid styles using a custom validation library.
Instead, toggle a class and target it in your stylesheet as shown below.
Formats a date/time using the specified locale and options.
Localization is handled by the browser's [`Intl.DateTimeFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat). No language packs are required.
The `date` prop determines the date/time to use when formatting. It must be a string that [`Date.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse) can interpret or a [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) object set via JavaScript. If omitted, the current date/time will be assumed.
?> When using strings, avoid ambiguous dates such as `03/04/2020` which can be interpreted as March 4 or April 3 depending on the user's browser and locale. Instead, always use a valid [ISO 8601 date time string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#Date_Time_String_Format) to ensure the date will be parsed properly by all clients.
## Examples
### Date & Time Formatting
Formatting options are based on those found in the [`Intl.DateTimeFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat). When formatting options are provided, the date/time will be formatted according to those values. When no formatting options are provided, a localized, numeric date will be displayed instead.
Formats a number using the specified locale and options.
Localization is handled by the browser's [`Intl.NumberFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat). No language packs are required.
To format a number as a monetary value, set the `type` attribute to `currency` and set the `currency` attribute to the desired ISO 4217 currency code. You should also specify `locale` to ensure the the number is formatted correctly for the target locale.
Icon buttons are designed to have a uniform appearance, so their color is not inherited. However, you can still customize them by styling the `base` part.
Icon libraries let you register additional icons to use with the `<sl-icon>` component.
An icon library is a renderless component that registers a custom set of SVG icons. The icon files can exist locally or on a CORS-enabled endpoint (i.e. a CDN). There is no limit to how many icon libraries you can register and there is no cost associated with registering them, as individual icons are only requested when they're used.
To register an icon library, create an `<sl-icon-library>` element with a name and resolver function. The resolver function translates an icon name to a URL where its corresponding SVG file exists. Refer to the examples below to better understand how it works.
If necessary, a mutator function can be used to mutate the SVG element before rendering. This is necessary for some libraries due to the many possible ways SVGs are crafted. For example, icons should inherit the current text color via `currentColor`, so you may need to apply `fill="currentColor` or `stroke="currentColor"` to the SVG element using this function.
Here's an example that registers an icon library located in the `/assets/icons` directory.
To display an icon, set the `library` and `name` attributes of an `<sl-icon>` element.
```html
<!-- This will show the icon located at /assets/icons/smile.svg -->
<sl-iconlibrary="my-icons"name="smile"></sl-icon>
```
The location of the icon library in the DOM doesn't matter as long as it's within the `<body>` element. If an icon is used before registration, it will be empty until registration has completed. It's perfectly acceptable to place all `<sl-icon-library>` elements before the `</body>` tag if you prefer to organize them that way.
## Examples
The following examples demonstrate how to register a number of popular, open source icon libraries via CDN. Feel free to adapt the code as you see fit to use your own origin or naming conventions.
### Boxicons
This will register the [Boxicons](https://boxicons.com/) library using the jsDelivr CDN. This library has three variations: regular (`bx-*`), solid (`bxs-*`), and logos (`bxl-*`). A mutator function is required to set the SVG's `fill` to `currentColor`.
Icons in this library are licensed under the [Creative Commons 4.0 License](https://github.com/atisawd/boxicons#license).
This will register the [Font Awesome Free](https://fontawesome.com/) library using the jsDelivr CDN. This library has three variations: regular (`far-*`), solid (`fas-*`), and brands (`fab-*`). A mutator function is required to set the SVG's `fill` to `currentColor`.
Icons in this library are licensed under the [Font Awesome Free License](https://github.com/FortAwesome/Font-Awesome/blob/master/LICENSE.txt). Some of the icons that appear on the Font Awesome website require a license and are therefore not available in the CDN.
This will register the [Ionicons](https://ionicons.com/) library using the jsDelivr CDN. This library has three variations: outline (default), filled (`*-filled`), and sharp (`*-sharp`). A mutator function is required to polyfill a handful of styles we're not including.
Icons in this library are licensed under the [MIT License](https://github.com/ionic-team/ionicons/blob/master/LICENSE).
This will register the [Jam Icons](https://jam-icons.com/) library using the jsDelivr CDN. This library has two variations: regular (default) and filled (`*-f`). A mutator function is required to set the SVG's `fill` to `currentColor`.
Icons in this library are licensed under the [MIT License](https://github.com/michaelampr/jam/blob/master/LICENSE).
This will register the [Material Icons](https://material.io/resources/icons/?style=baseline) library using the jsDelivr CDN. This library has three variations: outline (default), round (`*_round`), and sharp (`*_sharp`). A mutator function is required to set the SVG's `fill` to `currentColor`.
Icons in this library are licensed under the [Apache 2.0 License](https://github.com/google/material-design-icons/blob/master/LICENSE).
This will register the [Remix Icon](https://remixicon.com/) library using the jsDelivr CDN. This library has two variations: line (default) and fill (`*-fill`). It also groups icons by categories, so the name must include the category and icon separated by a slash. A mutator function is required to set the SVG's `fill` to `currentColor`.
Icons in this library are licensed under the [Apache 2.0 License](https://github.com/Remix-Design/RemixIcon/blob/master/License).
This will register the [Unicons](https://iconscout.com/unicons) library using the jsDelivr CDN. This library has two variations: line (default) and solid (`*-s`). A mutator function is required to set the SVG's `fill` to `currentColor`.
Icons in this library are licensed under the [Apache 2.0 License](https://github.com/Iconscout/unicons/blob/master/LICENSE). Some of the icons that appear on the Unicons website, particularly many of the solid variations, require a license and are therefore not available in the CDN.
Shoelace comes bundled with over 1,100 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. These are the default icons that display when you use `<sl-icon>` without a `name` attribute. If you prefer to have these icons resolve elsewhere, you can register an icon library with the `default` name and a custom resolver.
This example will load the same set of icons from the jsDelivr CDN instead of your local assets folder.
Icons are symbols that can be used to represent various options within an application.
Shoelace comes bundled with over 1,100 icons courtesy of the [Bootstrap Icons](https://icons.getbootstrap.com/) project. If you prefer, you can also register [custom icon libraries](/components/icon-library.md).
Click or tap on an icon below to copy its name and use it like this.
Icons are sized relative to the current font size. To change their size, set the `font-size` property on the icon itself or on a parent element as shown below.
```html preview
<div style="font-size: 32px;">
<sl-icon name="exclamation-triangle"></sl-icon>
<sl-icon name="archive"></sl-icon>
<sl-icon name="battery-charging"></sl-icon>
<sl-icon name="bell"></sl-icon>
<sl-icon name="clock"></sl-icon>
<sl-icon name="download"></sl-icon>
<sl-icon name="file-earmark"></sl-icon>
<sl-icon name="flag"></sl-icon>
<sl-icon name="heart"></sl-icon>
<sl-icon name="image"></sl-icon>
<sl-icon name="lightning"></sl-icon>
<sl-icon name="mic"></sl-icon>
<sl-icon name="search"></sl-icon>
<sl-icon name="star"></sl-icon>
<sl-icon name="trash"></sl-icon>
<sl-icon name="x-circle"></sl-icon>
</div>
```
### Custom Icons
Custom icons can be loaded individually with the `src` attribute. Only SVGs on a local or CORS-enabled endpoint are supported. If you're using more than one custom icon, it might make sense to register a [custom icon library](/components/icon-library.md).
Compare visual differences between similar photos with a sliding panel.
For best results, use images that share the same dimensions. The slider can be controlled by dragging or pressing the left and right arrow keys. (Tip: press shift + arrows to move the slider in larger intervals, or home + end to jump to the beginning or end.)
```html preview
<sl-image-comparer>
<img slot="before" src="https://images.unsplash.com/photo-1517331156700-3c241d2b4d83?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80&sat=-100&bri=-5" alt="Grayscale version of kittens in a basket looking around.">
<img slot="after" src="https://images.unsplash.com/photo-1517331156700-3c241d2b4d83?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=800&q=80" alt="Color version of kittens in a basket looking around.">
</sl-image-comparer>
```
## Examples
### Initial Position
Use the `position` attribute to set the initial position of the slider. This is a percentage from `0` to `100`.
```html preview
<sl-image-comparer position="0">
<img slot="before" src="https://images.unsplash.com/photo-1520903074185-8eca362b3dce?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1200&q=80" alt="A person sitting on bricks wearing untied boots.">
<img slot="after" src="https://images.unsplash.com/photo-1520640023173-50a135e35804?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=2250&q=80" alt="A person sitting on a yellow curb tying shoelaces on a boot.">
Includes give you the power to embed external HTML files into the page.
Included files are asynchronously requested using `window.fetch()`. Requests are cached, so the same file can be included multiple times, but only one request will be made.
The included content will be inserted into the `<sl-include>` element's default slot so it can be easily accessed and styled through the light DOM.
When an include file loads successfully, the `sl-load` event will be emitted. You can listen for this event to add custom loading logic to your includes.
If the request fails, the `sl-error` event will be emitted. In this case, `event.detail.status` will contain the resulting HTTP status code of the request, e.g. 404 (not found).
Add descriptive help text to an input with the `help-text` slot.
```html preview
<sl-input label="Nickname">
<div slot="help-text">What would you like people to call you?</div>
</sl-input>
```
### Inputs with Dropdowns
Dropdowns can be used in the `prefix` or `suffix` slot to make inputs more versatile. Make sure to use the `hoist` prop so the dropdown breaks out of the input's overflow.
Menus provide a list of options for the user to choose from.
Use [menu items](/components/menu-item.md), [menu dividers](/components/menu-divider.md), and [menu labels](/components/menu-label.md) to compose a menu.
The `indeterminate` attribute can be used to inform the user that the operation is pending, but its status cannot currently be determined. In this state, `percentage` is ignored and the label, if present, will not be shown.
Outputs a localized time phrase relative to the current date and time.
Localization is handled by the browser's [`Intl.RelativeTimeFormat` API](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/RelativeTimeFormat). No language packs are required.
The `date` prop determines when the date/time is calculated from. It must be a string that [`Date.parse()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse) can interpret or a [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) object set via JavaScript.
?> When using strings, avoid ambiguous dates such as `03/04/2020` which can be interpreted as March 4 or April 3 depending on the user's browser and locale. Instead, always use a valid [ISO 8601 date time string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse#Date_Time_String_Format) to ensure the date will be parsed properly by all clients.
!> The `Intl.RelativeTimeFormat` API is available [in all major browsers](https://caniuse.com/mdn-javascript_builtins_intl_relativetimeformat), but it only became available to Safari in version 14. If you need to support Safari 13, you'll need to [use a polyfill](https://github.com/catamphetamine/relative-time-format).
## Examples
### Keeping Time in Sync
Use the `sync` attribute to update the displayed value automatically as time passes.
relativeTime.date = new Date(new Date().getTime() - 60000);
</script>
```
### Formatting Styles
You can change how the time is displayed using the `format` attribute. Note that some locales may display the same values for `narrow` and `short` formats.
Resize observers offer a thin, declarative interface to the [`ResizeObserver API`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver).
The resize observer will report changes to the dimensions of the elements it wraps through the `sl-resize` event. When emitted, a collection of [`ResizeObserverEntry`](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry) objects will be attached to `event.detail`, containing the target element and information about its dimensions.
Skeletons are used to show where content will eventually be drawn.
These are simple containers for scaffolding layouts that mimic what users will see when content has finished loading. This prevents large areas of empty space during asynchronous operations.
Skeletons try not to be opinionated, as there are endless possibilities for designing layouts. Therefore, you'll likely use more than one skeleton to create the effect you want. If you find yourself using them frequently, consider creating a template that renders them with the desired arrangement and styles.
The default effect is `sheen`, which animates a sheen horizontally across the skeleton. There's also `pulse`, which fades the skeleton in and out. To disable animations, use `none`. Effects are intentionally subtle, as they can be distracting otherwise.
```html preview
<div class="skeleton-effects">
<sl-skeleton effect="sheen"></sl-skeleton>
Sheen
<sl-skeleton effect="pulse"></sl-skeleton>
Pulse
<sl-skeleton effect="none"></sl-skeleton>
None
</div>
<style>
.skeleton-effects {
font-size: var(--sl-font-size-small);
}
.skeleton-effects sl-skeleton:not(:first-child) {
margin-top: 1rem;
}
</style>
```
### Paragraphs
Use multiple skeletons and some clever styles to simulate paragraphs.
```html preview
<div class="skeleton-paragraphs">
<sl-skeleton></sl-skeleton>
<sl-skeleton></sl-skeleton>
<sl-skeleton></sl-skeleton>
<sl-skeleton></sl-skeleton>
<sl-skeleton></sl-skeleton>
</div>
<style>
.skeleton-paragraphs sl-skeleton {
margin-bottom: 1rem;
}
.skeleton-paragraphs sl-skeleton:nth-child(2) {
width: 95%;
}
.skeleton-paragraphs sl-skeleton:nth-child(4) {
width: 90%;
}
.skeleton-paragraphs sl-skeleton:last-child {
width: 50%;
}
</style>
```
### Avatars
Set a matching width and height to make a circle, square, or rounded avatar skeleton.
```html preview
<div class="skeleton-avatars">
<sl-skeleton></sl-skeleton>
<sl-skeleton></sl-skeleton>
<sl-skeleton></sl-skeleton>
</div>
<style>
.skeleton-avatars sl-skeleton {
display: inline-block;
width: 3rem;
height: 3rem;
margin-right: .5rem;
}
.skeleton-avatars sl-skeleton:nth-child(1) {
--border-radius: 0;
}
.skeleton-avatars sl-skeleton:nth-child(2) {
--border-radius: var(--sl-border-radius-medium);
}
</style>
```
### Custom Shapes
Use the `--border-radius` custom property to make circles, squares, and rectangles. For more complex shapes, you can apply `clip-path` to the `indicator` part. [Try Clippy](https://bennettfeely.com/clippy/) if you need help generating custom shapes.
Spinners are used to show the progress of an indeterminate operation.
```html preview
<sl-spinner></sl-spinner>
```
## Examples
### Size
Spinners are sized relative to the current font size. To change their size, set the `font-size` property on the spinner itself or on a parent element as shown below.
Tab groups organize content into a container that shows one section at a time.
Tab groups make use of [tabs](/components/tab.md) and [tab panels](/components/tab-panel.md). Each tab must be slotted into the `nav` slot and its `panel` must refer to a tab panel of the same name.
Themes change the visual appearance of components.
This component will activate a theme and apply its styles to everything inside. All themes must adhere to [theming guidelines](/getting-started/themes) and expose a class that follows the `sl-theme-{name}` convention.
To activate a theme, include the necessary stylesheet(s) and wrap your content in an `<sl-theme>` element. The theme to use is specified by the `name` prop.
```html
<linkrel="stylesheet"href="your-theme.css">
<sl-themename="dark">
<!-- Everything inside will use the dark theme -->
</sl-theme>
```
?> It's important to note that the default "light" theme isn't actually a theme — it's a set of design tokens and base styles that themes can use as a foundation to build upon. As such, it's not possible to opt in to the default theme using this component.
## Examples
### Dark Theme
To use the official dark theme, include its stylesheet per the instructions on the [themes page](/getting-started/themes) and activate it as shown in the example below. All design tokens and components will render accordingly.
```html preview
<div class="theme-overview">
<sl-theme name="dark">
<!-- Design tokens used inside <sl-theme> will reflect the theme's colors -->
Tooltips display additional information based on a specific action.
A tooltip's target is its _first child element_, so you should only wrap one element inside of the tooltip. If you need the tooltip to show up for multiple elements, nest them inside a container first.
Tooltips use `display: contents` so they won't interfere with how elements are positioned in a flex or grid layout.
```html preview
<sl-tooltip content="This is a tooltip">
<sl-button>Hover Me</sl-button>
</sl-tooltip>
```
## Examples
### Placement
Use the `placement` attribute to set the preferred placement of the tooltip.
Shoelace follows [Semantic Versioning](https://semver.org/). Breaking changes in components with the <sl-badge type="primary" pill>Stable</sl-badge> badge will not be accepted until the next major version. As such, all contributions must consider the project's roadmap and take this into consideration. Features that are deemed no longer necessary will be deprecated but not removed.
Components with the <sl-badge type="warning" pill>Experimental</sl-badge> badge should not be used in production. They are made available as release candidates for development and testing purposes. As such, changes to experimental components will not be subject to semantic versioning.
_During the beta period, these restrictions may be relaxed in the event of a mission-critical bug._ 🐛
## 2.0.0-beta.24
- Added `sl-format-date` component
- Added `indeterminate` state to `sl-progress-bar` [#274](https://github.com/shoelace-style/shoelace/issues/274)
- Added `--track-color`, `--indicator-color`, and `--label-color` to `sl-progress-bar` [#276](https://github.com/shoelace-style/shoelace/issues/276)
- Added `allow-scripts` prop to `sl-include` [#280](https://github.com/shoelace-style/shoelace/issues/280)
- Fixed a bug where `sl-menu-item` color variable was incorrect [#272](https://github.com/shoelace-style/shoelace/issues/272)
- Fixed a bug where `sl-dialog` and `sl-drawer` would emit the `sl-hide` event twice [#275](https://github.com/shoelace-style/shoelace/issues/275)
- Fixed a bug where calling `event.preventDefault()` on certain form elements wouldn't prevent `sl-form` from submitting [#277](https://github.com/shoelace-style/shoelace/issues/277)
- Fixed drag handle orientation in `sl-image-comparer`
- Restyled `sl-spinner` so the track is visible and the indicator is smaller.
- Removed `resize-observer-polyfill` in favor of `@types/resize-observer-browser` since all target browsers support `ResizeObserver`
- Upgraded the status of `sl-form`, `sl-image-comparer`, and `sl-include` from experimental to stable
## 2.0.0-beta.23
- Added `sl-format-number` component
- Added `sl-relative-time` component
- Added `closable` prop to `sl-tab`
- Added experimental `sl-resize-observer` utility
- Added experimental `sl-theme` utility and updated theming documentation
- Fixed a bug where `sl-menu-item` wouldn't render properly in the dark theme
- Fixed a bug where `sl-select` would show an autocomplete menu
- Improved placeholder contrast in dark theme
- Updated to Boostrap Icons 1.1.0
- Updated to Stencil 2.3.0
## 2.0.0-beta.22
- 🚨 BREAKING CHANGE: Refactored `sl-menu` and `sl-menu-item` to improve accessibility by using proper focus states [#217](https://github.com/shoelace-style/shoelace/issues/217)
- Moved `tabindex` from `sl-menu` to `sl-menu-item`
- Removed the `active` prop from `sl-menu-item` because synthetic focus states are bad for accessibility
- Removed the `sl-activate` and `sl-deactivate` events from `sl-menu-item` (listen for `focus` and `blur` instead)
- Updated `sl-select` so keyboard navigation still works
- Added `no-scroll-controls` prop to `sl-tab-group` [#253](https://github.com/shoelace-style/shoelace/issues/253)
- Fixed a bug where setting `open` initially wouldn't show `sl-dialog` or `sl-drawer` [#255](https://github.com/shoelace-style/shoelace/issues/255)
- Fixed a bug where `disabled` could be set when buttons are rendered as links
- Fixed a bug where hoisted dropdowns would render in the wrong position when placed inside `sl-dialog` [#252](https://github.com/shoelace-style/shoelace/issues/252)
- Fixed a bug where boolean aria attributes didn't explicitly set `true|false` string values in the DOM
- Fixed a bug where `aria-describedby` was never set on tooltip targets in `sl-tooltip`
- Fixed a bug where setting `position` on `sl-image-comparer` wouldn't update the divider's position
- Fixed a bug where the check icon was announced to screen readers in `sl-menu-item`
- Improved `sl-icon-button` accessibility by encouraging proper use of `label` and hiding the internal icon from screen readers [#220](https://github.com/shoelace-style/shoelace/issues/220)
- Improved `sl-dropdown` accessibility by attaching `aria-haspopup` and `aria-expanded` to the slotted trigger
- Refactored position logic to remove an unnecessary state variable in `sl-image-comparer`
- Refactored design tokens to use `rem` instead of `px` for input height and spacing [#221](https://github.com/shoelace-style/shoelace/issues/221)
- Removed `console.log` from modal utility
- Updated to Stencil 2.2.0
## 2.0.0-beta.21
- Added `label` slot to `sl-input`, `sl-select`, and `sl-textarea` [#248](https://github.com/shoelace-style/shoelace/issues/248)
- Added `label` slot to `sl-dialog` and `sl-drawer`
- Added experimental `sl-include` component
- Added status code to the `sl-error` event in `sl-icon`
- Fixed a bug where initial transitions didn't show in `sl-dialog` and `sl-drawer` [#247](https://github.com/shoelace-style/shoelace/issues/247)
- Fixed a bug where indeterminate checkboxes would maintain the indeterminate state when toggled
- Fixed a bug where concurrent active modals (i.e. dialog, drawer) would try to steal focus from each other
- Improved `sl-color-picker` grid and slider handles [#246](https://github.com/shoelace-style/shoelace/issues/246)
- Refactored `sl-icon` request logic and removed unused cache map
- Reworked show/hide logic in `sl-alert`, `sl-dialog`, and `sl-drawer` to not use reflow hacks and the `hidden` attribute
- Reworked slot logic in `sl-card`, `sl-dialog`, and `sl-drawer`
- Updated to Popper 2.5.3 to address a fixed position bug in Firefox
## 2.0.0-beta.20
- 🚨 BREAKING CHANGE: Transformed all Shoelace events to lowercase ([details](#why-did-event-names-change))
- Added support for dropdowns and non-icon elements to `sl-input`
- Added `spellcheck` prop to `sl-input`
- Added `sl-icon-library` to allow custom icon library registration
- Added `library` prop to `sl-icon` and `sl-icon-button`
- Added "Integrating with Rails" tutorial to the docs, courtesy of [ParamagicDev](https://github.com/ParamagicDev)
- Fixed a bug where `sl-progress-ring` rendered incorrectly when zoomed in Safari [#227](https://github.com/shoelace-style/shoelace/issues/227)
- Fixed a bug where tabbing into slotted elements closes `sl-dropdown` when used in a shadow root [#223](https://github.com/shoelace-style/shoelace/issues/223)
- Fixed a bug where scroll anchoring caused undesirable scrolling when `sl-details` are grouped
### Why did event names change?
Shoelace events were updated to use a lowercase, kebab-style naming convention. Instead of event names such as `slChange` and `slAfterShow`, you'll need to use `sl-change` and `sl-after-show` now.
This change was necessary to address a critical issue in frameworks that use DOM templates with declarative event bindings such as `<sl-button @slChange="handler">`. Due to HTML's case-insensitivity, browsers translate attribute names to lowercase, turning `@slChange` into `@slchange`, making it impossible to listen to `slChange`.
While declarative event binding is a non-standard feature, not supporting it would make Shoelace much harder to use in popular frameworks. To accommodate those users and provide a better developer experience, we decided to change the naming convention while Shoelace is still in beta.
The following pages demonstrate why this change was necessary.
- [This Polymer FAQ from Custom Elements Everywhere](https://custom-elements-everywhere.com/#faq-polymer)
- Added `input`, `label`, `prefix`, `clear-button`, `suffix`, `help-text` exported parts to `sl-select` to make the input customizable
- Added toast notifications through the `toast()` method on `sl-alert`
- Fixed a bug where mouse events would bubble up when `sl-button` was disabled, causing tooltips to erroneously appear
- Fixed a bug where pressing space would open and immediately close `sl-dropdown` panels in Firefox
- Fixed a bug where `sl-tooltip` would throw an error on init
- Fixed a bug in custom keyframes animation example
- Refactored clear logic in `sl-input`
## 2.0.0-beta.18
- Added `name` and `invalid` prop to `sl-color-picker`
- Added support for form submission and validation to `sl-color-picker`
- Added touch support to demo resizers in the docs
- Added `sl-responsive-embed` component
- Fixed a bug where swapping an animated element wouldn't restart the animation in `sl-animation`
- Fixed a bug where the cursor was incorrect when `sl-select` was disabled
- Fixed a bug where `slblur` and `slfocus` were emitted twice in `sl-select`
- Fixed a bug where clicking on `sl-menu` wouldn't focus it
- Fixed a bug in the popover utility where `onAfterShow` would fire too soon
- Fixed a bug where `bottom` and `right` placements didn't render properly in `sl-tab-group`
- Improved keyboard logic in `sl-dropdown`, `sl-menu`, and `sl-select`
- Updated `sl-animation` to stable
- Updated to Stencil 2.0 (you may need to purge `node_modules` and run `npm install` after pulling)
- Updated entry points in `package.json` to reflect new filenames generated by Stencil 2
## 2.0.0-beta.17
- Added `minlength` and `spellcheck` attributes to `sl-textarea`
- Fixed a bug where clicking a tag in `sl-select` wouldn't toggle the menu
- Fixed a bug where options where `sl-select` options weren't always visible or scrollable
- Fixed a bug where setting `null` on `sl-input`, `sl-textarea`, or `sl-select` would throw an error
- Fixed a bug where `role` was on the wrong element and aria attribute weren't explicit in `sl-checkbox`, `sl-switch`, and `sl-radio`
- Fixed a bug where dynamically adding/removing a slot wouldn't work as expected in `sl-card`, `sl-dialog`, and `sl-drawer`
- Fixed a bug where the value wasn't updated and events weren't emitted when using `setRangeText` in `sl-input` and `sl-textarea`
- Optimized `hasSlot` utility by using a simpler selector
- Updated Bootstrap Icons to 1.0.0 with many icons redrawn and improved
- Updated contribution guidelines
**Form validation has been reworked and is much more powerful now!**
- The `invalid` prop now reflects the control's validity as determined by the browser's constraint validation API
- Added `required` to `sl-checkbox`, `sl-select`, and `sl-switch`
- Added `reportValidity()` and `setCustomValidity()` methods to all form controls
- Added validation checking for custom and native form controls to `sl-form`
- Added `novalidate` prop to `sl-form` to disable validation
- Removed the `valid` prop from all form controls
- Removed valid and invalid design tokens and related styles (you can use your own custom styles to achieve this)
## 2.0.0-beta.16
- Add `hoist` prop to `sl-color-picker`, `sl-dropdown`, and `sl-select` to work around panel clipping
- Add `sl-format-bytes` utility component
- Add `clearable` and `required` props to `sl-select`
- Add `slclear` event to `sl-input`
- Added keyboard support to the preview resizer in the docs
- Fixed a bug where the `aria-selected` state was incorrect in `sl-menu-item`
- Fixed a bug where custom properties applied to `sl-tooltip` didn't affect show/hide transitions
- Fixed a bug where `--sl-input-color-*` custom properties had no affect on `sl-input` and `sl-textarea`
- Refactored `sl-dropdown` and `sl-tooltip` to use positioner elements so panels/tooltips can be customized easier
## 2.0.0-beta.15
- Added `image-comparer` component
- Added `--width`, `--height`, and `--thumb-size` custom props to `sl-switch`
- Fixed an `aria-labelledby` attribute typo in a number of components
- Fixed a bug where the `change` event wasn't updating the value in `sl-input`
- Fixed a bug where `sl-color-picker` had the wrong border color in the dark theme
- Fixed a bug where `sl-menu-item` had the wrong color in dark mode when disabled
- Fixed a bug where WebKit's autocomplete styles made inputs looks broken
- Fixed a bug where aria labels were wrong in `sl-select`
- Fixed a bug where clicking the label wouldn't focus the control in `sl-select`
## 2.0.0-beta.14
- Added dark theme
- Added `--sl-panel-background-color` and `--sl-panel-border-color` tokens
- Added `--tabs-border-color` custom property to `sl-tab-group`
- Added `--track-color` custom property to `sl-range`
- Added `tag` part to `sl-select`
- Updated `package.json` so custom elements imports can be consumed from the root
- Fixed a bug where scrolling dialogs didn't resize properly in Safari
- Fixed a bug where `slshow` and `slhide` would be emitted twice in some components
- Fixed a bug where `custom-elements/index.d.ts` was broken due to an unclosed comment (fixed in Stencil 1.17.3)
- Fixed bug where inputs were not using border radius tokens
- Fixed a bug where the text color was being erroneously set in `sl-progress-ring`
- Fixed a bug where `sl-progress-bar` used the wrong part name internally for `indicator`
- Removed background color from `sl-menu`
- Updated to Stencil 1.17.3
## 2.0.0-beta.13
- Added `slactivate` and `sldeactivate` events to `sl-menu-item`
- Added experimental `sl-animation` component
- Added shields to documentation
- Fixed a bug where link buttons would have `type="button"`
- Fixed a bug where button groups with tooltips experienced an odd spacing issue in Safari
- Fixed a bug where scrolling in dropdowns/selects didn't work properly on Windows (special thanks to [Trendy](http://github.com/trendy) for helping troubleshoot!)
- Fixed a bug where selecting a menu item in a dropdown would cause Safari to scroll
- Fixed a bug where type to select wouldn't accept symbols
- Moved scrolling logic from `sl-menu` to `sl-dropdown`
## 2.0.0-beta.12
- Added support for `href`, `target`, and `download` to buttons
- Fixed a bug where buttons would have horizontal spacing in Safari
- Fixed a bug that caused an import resolution error when using Shoelace in a Stencil app
## 2.0.0-beta.11
- Added button group component
- Fixed icon button alignment
- Fixed a bug where focus visible observer wasn't removed from `sl-details`
- Replaced the deprecated `componentDidUnload` lifecycle method with `disconnectedCallback` to prevent issues with frameworks
## 2.0.0-beta.10
- Added community page to the docs
- Fixed a bug where many components would erroneously receive an `id` when using the custom elements bundle
- Fixed a bug where tab groups weren't scrollable with the mouse
## 2.0.0-beta.9
- Added the icon button component
- Added the skeleton component
- Added the `typeToSelect` method to menu so type-to-select behavior can be controlled externally
- Added the `pulse` prop to badge
- Fixed a bug where hovering over select showed the wrong cursor
- Fixed a bug where tabbing into a select control would highlight the label
- Fixed a bug where tabbing out of a select control wouldn't close it
- Fixed a bug where closing dropdowns wouldn't give focus back to the trigger
- Fixed a bug where type-to-select wasn't working after the first letter
- Fixed a bug where clicking on menu items and dividers would steal focus from the menu
- Fix a bug where the color picker wouldn't parse uppercase values
- Removed `noFooter` prop from dialog and drawer (slot detection is automatic, so the prop is not required)
- Removed `close-icon` slot from alert
- Replaced make-shift icon buttons with `sl-icon-button` in alert, dialog, drawer, and tag
- Updated Stencil to 1.17.1
- Switched to jsDelivr for better CDN performance
## 2.0.0-beta.8
- Added the card component
- Added `--focus-ring` custom property to tab
- Fixed a bug where range tooltips didn't appear on iOS
- Fixed constructor bindings so they don't break the custom elements bundle
- Fixed tag color contrast to be AA compliant
- Fixed a bug that made it difficult to vertically align rating
- Fixed a bug where dropdowns would always close on mousedown when inside a shadow root
- Made tag text colors AA compliant
- Promoted badge to stable
- Refactored `:host` variables and moved non-display props to base elements
- Refactored event handler bindings to occur in `connectedCallback` instead of the constructor
- Refactored scroll locking logic to use `Set` instead of an array
- Updated the custom elements bundle documentation and added bundler examples
- Upgraded Stencil to 1.17.0-0 (next) to fix custom elements bundle
## 2.0.0-beta.7
- Added links to version 1 resources to the docs
- Added rating component
- Fixed a bug where some build files were missing
- Fixed clearable tags demo
- Fixed touch icon size in docs
## 2.0.0-beta.6
- Enabled the `dist-custom-elements-bundle` output target
- Fixed a bug where nested form controls were ignored in `<sl-form>`
## 2.0.0-beta.5
- Fixed bug where `npm install` would fail due to postinstall script
- Removed unused dependency
## 2.0.0-beta.4
- Added `pill` variation to badges
- Fixed a bug where all badges had `pointer-events: none`
- Fixed `@since` props to show 2.0 instead of 1.0
- Fixed giant cursors in inputs in Safari
- Fixed color picker input width in Safari
- Fixed initial transitions for drawer, dialog, and popover consumers
- Fixed a bug where dialog, dropdown, and drawer would sometimes not transition in on the first open
Shoelace has a budding community of designers and developers that are building amazing things with web components. We'd love for you to become a part of it!
## Discord
The [community chat](https://discord.gg/mg8f26C) is open to the public and powered by [Discord](https://discord.com/). This is the best place to:
- Ask questions
- Get feedback
- Show the community what you're working on
- Hang out with other designers, developers, and Shoelace users
- Talk to the creator
Please be respectful of other users and remember that Shoelace is an open source project. We'll try to help when we can, but there's no guarantee we'll be able solve your problem. Please manage your expectations and don't forget to contribute back to the conversation when you can!
Follow [@shoelace_style](https://twitter.com/shoelace_style) on Twitter for general updates and announcements about Shoelace. This is a great place to say "hi" or to share something you're working on. You're also welcome to follow [@claviska](https://twitter.com/claviska), the creator, for tweets about web components, web development, and life.
**Please avoid using Twitter for support questions.** The community chat is a much better place to share code snippets, screenshots, and other troubleshooting info. You'll have much better luck there, as more users will have a chance to help you.
Oh, and don't forget to tell your followers about Shoelace!
Shoelace components can be customized at a high level through design tokens. This gives you control over theme colors and general styling. For more advanced customizations, you can make use of component parts and custom properties to target individual components.
## Design Tokens
Shoelace makes use of several design tokens to provide a consistent appearance across components. You can customize them and use them in your own application with pure CSS — no preprocessor required.
Design tokens offer a high-level way to customize the library with minimal effort. There are no component-specific variables, however, as design tokens are intended to be generic and highly reusable. To customize an individual component, refer to the section entitled [Component parts](#component-parts).
Design tokens are CSS custom properties ("CSS variables") that are defined in the `:root` block of `shoelace.css`. This stylesheet is imported when you install Shoelace, so design tokens are available on your page at that point. Because design tokens are global, they're always prefixed with `--sl` to avoid collisions with other libraries.
To customize a design token, simply override it in your stylesheet using a `:root` block.
```css
:root{
/* Changes the primary color to a shade of orange at 90% saturation */
--sl-color-primary-hue:30;
--sl-color-primary-saturation:90%;
}
```
Many design tokens are described further along in this documentation. For a complete list, refer to `shoelace.scss` in the project's [source code](https://github.com/shoelace-style/shoelace/blob/current/src/styles/shoelace.scss).
!> **Never modify variables directly in `shoelace.css`** because your changes will be overwritten when you upgrade the library. Even if you don't plan on upgrading, it's always better to override design tokens in your own stylesheet for better maintainability.
## Component Parts
Whereas design tokens offer a high-level way to customize the library, component parts offer a low-level way to customize individual components. Again, this is done with pure CSS — no preprocessor required.
Shoelace components use a [shadow DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM) to encapsulate their styles and behaviors. As a result, you can't simply target their internals with the usual CSS selectors. Instead, components expose "parts" that can be targeted with the [CSS part selector](https://developer.mozilla.org/en-US/docs/Web/CSS/::part), or `::part()`.
Here's an example that modifies buttons with the `tomato-button` class.
```html preview
<sl-button class="tomato-button">
Tomato Button
</sl-button>
<style>
.tomato-button::part(base) {
background: white;
border: solid 1px tomato;
}
.tomato-button::part(base):hover {
background: rgba(255, 99, 71, .1);
}
.tomato-button::part(base):active {
background: rgba(255, 99, 71, .2);
}
.tomato-button::part(base):focus {
box-shadow: 0 0 0 3px rgba(255, 99, 71, .33);
}
.tomato-button::part(label) {
color: tomato;
}
</style>
```
At first glance, this approach might seem a bit verbose or even limiting, but it comes with a few important advantages:
- Customizations can be made to components with explicit selectors, such as `::part(icon)`, rather than implicit selectors, such as `.button > div > span + .icon`, that are much more fragile.
- The internal structure of a component will likely change as it evolves. By exposing component parts through an API, the internals can be reworked without fear of breaking customizations as long as its parts remain intact.
- It encourages us to think more about how components are designed and how customizations should be allowed before userscan take advantage of them. Once we opt a part into the component's API, it's guaranteed to be supported and can't be removed until a major version of the library is released.
Most (but not all) components expose parts. You can find them in each component's API documention under the "CSS Parts" section.
## Custom Properties
For convenience, some components expose CSS custom properties you can override. These are not design tokens, nor do they have the same `--sl-` prefix since they're scoped to a component.
You can set custom properties on a component in your stylesheet.
```css
sl-avatar {
--size: 6rem;
}
```
This will also work if you need to target a subset of components with a specific class.
```css
sl-avatar.your-class {
--size: 6rem;
}
```
Alternatively, you can set them inline directly on the element.
```html
<sl-avatar style="--size: 6rem;"></sl-avatar>
```
Not all components expose CSS custom properties. For those that do, they can be found in the component's API documentation.
You can use Shoelace via CDN or by installing it locally.
## CDN Installation (Recommended)
The easiest way to install Shoelace is with the CDN. A lightweight loader will be added to your page that registers components asynchronously as you use them. It's like magic. ✨
Now you can [start using Shoelace!](/getting-started/usage.md)
## Local Installation
If you don't want to use the CDN, you can install Shoelace locally with the following command.
```bash
npm install @shoelace-style/shoelace
```
It's up to you to make the source files available to your app. One way to do this is to create a route in your app called `/assets/shoelace` that serves static files from `node_modules/@shoelace-style/shoelace`.
Once you've done that, add the following tags to your page. Make sure to update `href` and `src` so they point to the route you created.
A [custom elements bundle](https://stenciljs.com/docs/custom-elements) is available so you can import components and register them individually. This is a more flexible alternative to the lazy loading approach, but it requires the use of a bundler such as [webpack](https://webpack.js.org/) or [Rollup](https://rollupjs.org/guide/en/). You'll also need to manage static assets on your own.
Instructions vary depending on the bundler you're using.
## Using webpack
To use the custom elements bundle with webpack, install Shoelace first.
```bash
npm install @shoelace-style/shoelace
```
Your `webpack.config.js` should look something like what's shown below. Note how assets such as icons are copied from `node_modules` to `dist/icons` via the `CopyPlugin` utility.
For convenience, the bundle also exports a `defineCustomElements()` method. When this method is called, it will register all Shoelace components in the bundle.
While convenient for prototyping, importing all components will make your bundle larger. For best results, only import the components you're actually using.
?> An [example webpack project](https://github.com/shoelace-style/webpack-example) is also available on GitHub for your convenience.
## Using Rollup
To use the custom elements bundle with Rollup, install Shoelace first.
```bash
npm install @shoelace-style/shoelace
```
Your `rollup.config.js` should look something like what's shown below. Note how assets such as icons are copied from `node_modules` to `dist/icons` via the `rollup-copy-plugin`.
For convenience, the bundle also exports a `defineCustomElements()` method. When this method is called, it will register all Shoelace components in the bundle.
While convenient for prototyping, importing all components will make your bundle larger. For best results, only import the components you're actually using.
?> An [example Rollup project](https://github.com/shoelace-style/rollup-example) is also available on GitHub for your convenience.
<p><strong>A forward-thinking library of web components.</strong></p>
<ul>
<li>Works with all frameworks 🧩</li>
<li>Works with CDNs 🚛</li>
<li>Fully customizable with CSS 🎨</li>
<li>Includes an official dark theme 🌛</li>
<li>Built with accessibility in mind ♿️</li>
<li>Open source 😸</li>
</ul>
<p>Designed in New Hampshire by <a href="https://twitter.com/claviska" rel="noopener" target="_blank">Cory LaViska</a>.</p>
</div>
<div class="splash-end">
<img class="splash-image" src="/assets/images/undraw-content-team.svg" alt="Cartoon of people assembling components while standing on a giant laptop.">
Now you have access to all of Shoelace's components! Try adding a button:
```html
<sl-button>Click me</sl-button>
```
See the [installation instructions](getting-started/installation.md) for more details and other ways to install Shoelace.
## New to Web Components?
**TL;DR**–we finally have a way to create [our own HTML elements](https://html.spec.whatwg.org/multipage/custom-elements.html) and use them in any framework we want!
Thanks to the popularity of frameworks such as Angular, Vue, and React, component-driven development has become a part of our every day lives. Components help us encapsulate styles and behaviors into reusable building blocks. They make a lot of sense in terms of design, development, and testing.
Unfortunately, _framework-specific_ components fail us in a number of ways:
- You can only use them in the framework they're designed for 🔒
- Their lifespan is limited to that of the framework's ⏳
- New frameworks/versions can lead to breaking changes, requiring substantial effort to update components 😭
Web components solve these problems. They're [supported by all modern browsers](https://caniuse.com/#feat=custom-elementsv1), they're framework-agnostic, and they're [part of the standard](https://developer.mozilla.org/en-US/docs/Web/Web_Components), so we know they'll be supported for many years to come.
This is the technology that Shoelace is built on.
## What Problem Does This Solve?
Shoelace provides a collection of professionally designed, every day UI components built on a framework-agnostic technology. Why spend hundreds of hours (or more) building a design system from scratch? Why make a component library that only works with one framework?
With Shoelace, you can:
- Start building things faster (no need to roll your own buttons)
- Build multiple apps with different frameworks that all share the same UI
- Skip having to learn a new component library every time you switch frameworks
If your organization is looking to build a design system, [Shoelace will save you thousands of dollars](https://medium.com/eightshapes-llc/and-you-thought-buttons-were-easy-26eb5b5c1871).* All the foundational components you need are right here, ready to be customized for your brand. And since it's built on web standards, browsers will continue to support it for many years to come.
Whether you use Shoelace as a starting point for your organization's design system or for a fun personal project, there's no limit to what you can do with it.
<small>*Please consider giving back some of what you save by [supporting this project with a sponsorship](https://github.com/sponsors/claviska).</small>
## Browser Support
Shoelace is tested in the latest two versions of the following browsers.
Critical bug fixes in earlier versions will be addressed based on their severity and impact.
If you need to support IE11 or pre-Chromium Edge, this library isn't for you. Although web components can (to some degree) be polyfilled for legacy browsers, supporting them is outside the scope of this project. If you're using Shoelace in such a browser, you're gonna have a bad time. ⛷
## License
Shoelace is designed in New Hampshire by [Cory LaViska](https://twitter.com/claviska). It's available under the terms of the MIT license.
Designing, developing, and supporting this library requires a lot of time, effort, and skill. I'd like to keep it open source so everyone can use it, but that doesn't provide me with any income.
**Therefore, if you're using my software to make a profit,** I respectfully ask that you help [fund its development](https://github.com/sponsors/claviska) by becoming a sponsor. There are multiple tiers to choose from with benefits at every level, including prioritized support, bug fixes, feature requests, and advertising.
Special thanks to the following projects and individuals that helped make Shoelace possible.
- Components are compiled by [Stencil](https://stenciljs.com/)
- Documentation is powered by [Docsify](https://docsify.js.org/)
- CDN services are provided by [jsDelivr](https://www.jsdelivr.com/)
- Theme colors and form controls are inspired by [Element](https://element.eleme.io/)
- Icons are courtesy of [Bootstrap Icons](https://icons.getbootstrap.com/)
- Illustrations are courtesy of [unDraw](https://undraw.co/)
- Positioning of menus, tooltips, et al is handled by [Popper.js](https://popper.js.org/)
- The animation component was inspired by [animatable-component](https://github.com/proyecto26/animatable-component)
- The Shoelace logo was designed with a single shoelace by [Adam K Olson](https://twitter.com/adamkolson)
## Previous Versions
Shoelace v1 has been deprecated, but you can still [view the docs](https://v1.shoelace.style) or [download the source](https://github.com/shoelace-style/shoelace/releases/tag/1.0.0-beta.25) for historical purposes.
If you're new to this project, please see the [installation instructions](/getting-started/installation.md) for v2 instead.
Shoelace ships with a dark theme that complements the default light theme. You can even take things a step further by designing your own custom theme.
The default theme is included as part of `shoelace.css` and should always be loaded first, even if you want to use another theme exclusively. The default theme contains important base tokens and utilities that many components rely on.
## Dark Mode
To install the dark theme, add the following to the `<head>` section of your app.
**Themes must be activated after importing!** You can do this with the [`<sl-theme>`](/components/theme.md) component. Only the contents of `<sl-theme>` will inherit the theme's styles.
```html
<sl-button>Light Mode</sl-button>
<sl-themename="dark">
<sl-button>Dark Mode</sl-button>
</sl-theme>
```
### Detecting the User's Color Scheme Preference
Shoelace doesn't try to auto-detect the user's light/dark mode preference. This should be done at the application level. As a best practice, to provide a dark theme in your app, you should:
- Check for [`prefers-color-scheme`](https://stackoverflow.com/a/57795495/567486) and use its value by default
- Allow the user to override the setting in your app
- Remember the user's preference and restore it on subsequent logins
Shoelace avoids using the `prefers-color-scheme` media query because not all apps support dark mode, and it would break things for the ones that don't.
## Creating a Theme
A theme is nothing more than a stylesheet that uses the Shoelace API to customize design tokens and/or components. To create a theme, you will need a decent understanding of CSS, including [CSS Custom Properties](https://developer.mozilla.org/en-US/docs/Web/CSS/--*) and the [`::part` selector](https://developer.mozilla.org/en-US/docs/Web/CSS/::part).
The recommended way to create a theme is to piggyback on top of the default theme, adjusting design tokens and styling components as necessary to achieve the look you want. This makes your theme lightweight and "future proof", as upcoming versions of Shoelace may introduce new design tokens and components that your theme won't support initially. The default theme will account for these so components won't appear to be broken.
Technically, you can roll your own theme from scratch without using the default theme as a baseline, but that approach isn't recommended.
### Theme Classes
All theme classes must use the `sl-theme-{name}` convention, where `{name}` is a lowercase, hyphen-delimited value representing the name of your theme. For example, a theme called "Purple Power" would use the `sl-theme-purple-power` class.
Every selector in a theme must be scoped to the theme's class to ensure interoperability with other themes.
### Design Tokens
[Design tokens](/getting-started/customizing?id=design-tokens) give you a high-level way to customize Shoelace components. You can customize them in your theme as shown below.
```css
.sl-theme-purple-power{
--sl-color-primary-hue:290;
--sl-color-primary-saturation:80%;
/* more design token customizations here */
}
```
?> Avoid scoping design tokens to `:root`. You may notice that the default theme does this, but that's because it's not technically a theme — it's a set of design tokens and base styles that themes can use as a foundation to build upon.
### Components
To customize individual components, use the following syntax. Available "parts" can be found in the CSS Parts section of each component's documentation.
```css
.sl-theme-purple-powersl-button::part(base){
/* your custom button styles here */
}
```
?> Pay special attention to each component's CSS Parts API. You almost always need to use a `::part` selector when theming components!
## Using a Custom Theme
If a theme adheres to the guidelines above, you can use it by importing the stylesheet and activating it with the [`<sl-theme>`](/components/theme.md) component.
If desired, you can import and activate more than one theme on the same page.
## Submitting a Theme
**I am very interested in showcasing well-designed themes that complement this library.** To submit a theme for review, please [open an issue](https://github.com/shoelace-style/shoelace/issues/new) on GitHub with the theme linked or attached. Once approved, your theme will be showcased on this page.
Please note the following requirements before submitting a theme.
- Themes must be complete and of high quality
- Themes must be available under an open source license
- Derivative works must be properly credited
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.