Skip to content

Theming

<ship-dot src="/shipdot.json" theme="auto"></ship-dot> <!-- default: follows the OS -->
<ship-dot src="/shipdot.json" theme="dark"></ship-dot>

If your app has its own theme toggle, set the attribute from it. Both built-in themes meet WCAG 2.1 AA contrast, verified with axe in CI.

Set them on ship-dot or on :root. Values can use light-dark() to adapt to the theme.

Property Default (light / dark) What it styles
--shipdot-accent #4f46e5 / #a5b4fc Badge, unread dot, links, “Got it”
--shipdot-accent-contrast #fff / #18181b Text on the accent color
--shipdot-hotspot #db2777 / #f472b6 Hotspot dots (distinct from the accent so they stand out on brand-colored buttons)
--shipdot-bg #fff / #18181b Panel and tooltip background
--shipdot-fg #18181b / #f4f4f5 Text
--shipdot-muted #52525b / #a1a1aa Dates and secondary text
--shipdot-border #e4e4e7 / #3f3f46 Borders and separators
--shipdot-radius 12px Panel and tooltip corners
--shipdot-shadow 0 12px 32px rgb(0 0 0 / .2) Panel and tooltip shadow
--shipdot-font 400 14px/1.5 system-ui, sans-serif Font shorthand
--shipdot-panel-width 380px (popover), 420px (drawer) Panel width
--shipdot-trigger-size 40px Bell button size
--shipdot-z 2147483000 z-index of the hotspot layer
ship-dot {
--shipdot-accent: light-dark(#0f766e, #5eead4);
--shipdot-radius: 6px;
color: #334155; /* the bell icon uses currentColor */
}

If you change colors, keep text contrast at 4.5:1 or more.

Every key piece is exposed with ::part():

ship-dot::part(trigger) {} /* the bell button */
ship-dot::part(badge) {} /* unread count */
ship-dot::part(panel) {} /* popover, drawer or modal */
ship-dot::part(header) {}
ship-dot::part(close) {}
ship-dot::part(list) {}
ship-dot::part(entry) {}
ship-dot::part(entry-title) {}
ship-dot::part(tag) {}
ship-dot::part(image) {}
ship-dot::part(body) {}
ship-dot::part(link) {}
.shipdot-layer::part(hotspot) {}
.shipdot-layer::part(tooltip) {}
.shipdot-layer::part(got-it) {}
<ship-dot src="/shipdot.json" mode="popover"></ship-dot> <!-- default, anchored to the bell -->
<ship-dot src="/shipdot.json" mode="drawer"></ship-dot> <!-- slides in from the side -->
<ship-dot src="/shipdot.json" mode="modal"></ship-dot> <!-- centered dialog -->

Drawer and modal use a native <dialog>: the rest of the page becomes inert, focus stays inside, Esc closes it and focus returns to the trigger.

Anything you put inside <ship-dot> replaces the bell. Clicking it toggles the panel. The element gets a data-unread attribute with the count, so you can style your own badge:

<ship-dot src="/shipdot.json">
<button type="button" class="nav-link">What's new</button>
</ship-dot>
<style>
ship-dot:not([data-unread='0']) .nav-link::after { content: '•'; color: crimson; }
</style>

Give your button an accessible name that mentions new updates when there are any.