Color mode

Share

Per-article share controls built at build time. For every published entry the plugin builds share URLs for the configured services and injects the controls into the rendered HTML. The links are ordinary anchors and work without JavaScript; only the copy-link action is a progressive enhancement.

日本語

Overview

share() resolves each note's permalink to an absolute URL, composes the service URLs from the note title and URL, and inserts the controls near the article. The controls are inserted into the manifest entry's HTML, which Core synchronizes with the content the route renders, so they appear on generated pages and in feeds.

Supported services:

Service Share URL
x https://twitter.com/intent/tweet?url=…&text=…
bluesky https://bsky.app/intent/compose?text=…
mastodon https://{instance}/share?text=…
facebook https://www.facebook.com/sharer/sharer.php?u=…
linkedin https://www.linkedin.com/sharing/share-offsite/?url=…
hatena https://b.hatena.ne.jp/add?mode=confirm&url=…&title=…
copy Copies the note URL (button, no JavaScript required for the links)

mastodon is opt-in: add "mastodon" to services and set mastodonInstance.

Usage

ts
import { defineConfig } from "@riebeckite/core";
import { share } from "@riebeckite/plugin-share";
 
export default defineConfig({
  // ...
  plugins: [share()],
});

Enable Mastodon and change placement:

ts
share({
  services: ["x", "bluesky", "mastodon", "copy"],
  mastodonInstance: "mastodon.social",
  placement: "top",
});

Options

Option Type Default Description
services ShareService[] every service except mastodon Services to render, in order
placement "top" | "bottom" "bottom" Where the controls appear
mastodonInstance string none Mastodon host; required when services includes "mastodon"
className string none Extra root class alongside the stable rr-share hook
ariaLabel string "Share" Accessible name for the control group
labels Partial<Record<ShareService, string>> built-in labels Per-service visible labels
copiedLabel string "Copied" Status announced after a successful copy
copyFailedLabel string "Copy failed" Status announced when a copy fails

share throws a configuration error at riebeckite check time when services includes "mastodon" but mastodonInstance is missing.

Output

html
<div class="rr-share" data-rr-share data-rr-share-placement="bottom"
     role="group" aria-label="Share">
  <ul class="rr-share__list">
    <li class="rr-share__item">
      <a class="rr-share__link rr-share__link--x"
         href="https://twitter.com/intent/tweet?url=…&amp;text=…"
         target="_blank" rel="noopener noreferrer" data-share-service="x">X</a>
    </li>
    <li class="rr-share__item">
      <button type="button" class="rr-share__button rr-share__copy"
              data-rr-share-copy data-share-url="https://example.com/posts/hello"
              data-rr-share-copied="Copied" hidden>Copy link</button>
    </li>
  </ul>
  <p class="rr-share__status" role="status" aria-live="polite"></p>
</div>

Progressive enhancement

The share links are plain anchors, so they work with JavaScript disabled. The copy-link button starts hidden and is revealed by initShare(), which the app calls during page initialization; a no-JS reader never sees a control that cannot work. Copying uses navigator.clipboard.writeText and falls back to a hidden textarea with document.execCommand("copy"). The result is announced in the aria-live="polite" status region.

Style

The package ships style.css. Register it like any other plugin stylesheet:

ts
import "@riebeckite/plugin-share/style.css";

The stable classes are rr-share (root), rr-share__list, rr-share__item, rr-share__link, rr-share__link--{service}, rr-share__button, rr-share__copy, and rr-share__status. A theme can target these hooks; the optional className is added to the root without replacing them.

Exports

  • share(options?) — plugin factory
  • sharePlugin — alias of share
  • resolveShareOptions(options?) — apply option defaults
  • validateShareOptions(options?) — validate runtime options
  • buildAbsoluteUrl(config, permalink) — resolve a note URL to absolute
  • normalizeMastodonInstance(value) — normalize an instance to a bare host
  • buildShareUrl(service, target, instance?) — build one service URL
  • buildShareLinks(options, target) — build every link-bearing service
  • renderShareControls(options, target) — render the controls HTML
  • initShare() — client initializer (also via @riebeckite/plugin-share/client)
  • Constants: SHARE_SERVICES, SHARE_ATTRIBUTE, SHARE_ROOT_CLASS, DEFAULT_SHARE_SERVICES, DEFAULT_SHARE_LABELS, DEFAULT_SHARE_PLACEMENT
  • Types: ShareOptions, ResolvedShareOptions, ShareService, SharePlacement, ShareLink, ShareTarget

Limitations

  • Share URLs are fixed at build time. A full rebuild always recomputes them.
  • Mastodon cannot be enabled without a concrete instance.
  • The plugin contributes controls to article.before-content for top and article.footer for bottom; a Site places those semantic slots in its layout.

See also

History

1 changesCollapseExpand
1 + <!-- Generated from packages/plugins/share/README.md. Do not edit this page directly; edit the package README and run `pnpm docs:sync`. -->
2 +
3 + # Share
4 +
5 + Per-article share controls built at build time. For every published entry the
6 + plugin builds share URLs for the configured services and injects the controls
7 + into the rendered HTML. The links are ordinary anchors and work without
8 + JavaScript; only the copy-link action is a progressive enhancement.
9 +
10 + [日本語](./share.md)
11 +
12 + ## Overview
13 +
14 + `share()` resolves each note's `permalink` to an absolute URL, composes the
15 + service URLs from the note title and URL, and inserts the controls near the
16 + article. The controls are inserted into the manifest entry's HTML, which Core
17 + synchronizes with the content the route renders, so they appear on generated
18 + pages and in feeds.
19 +
20 + Supported services:
21 +
22 + | Service | Share URL |
23 + | ------- | --------- |
24 + | `x` | `https://twitter.com/intent/tweet?url=…&text=…` |
25 + | `bluesky` | `https://bsky.app/intent/compose?text=…` |
26 + | `mastodon` | `https://{instance}/share?text=…` |
27 + | `facebook` | `https://www.facebook.com/sharer/sharer.php?u=…` |
28 + | `linkedin` | `https://www.linkedin.com/sharing/share-offsite/?url=…` |
29 + | `hatena` | `https://b.hatena.ne.jp/add?mode=confirm&url=…&title=…` |
30 + | `copy` | Copies the note URL (button, no JavaScript required for the links) |
31 +
32 + `mastodon` is opt-in: add `"mastodon"` to `services` and set
33 + `mastodonInstance`.
34 +
35 + ## Usage
36 +
37 + ```ts
38 + import { defineConfig } from "@riebeckite/core";
39 + import { share } from "@riebeckite/plugin-share";
40 +
41 + export default defineConfig({
42 + // ...
43 + plugins: [share()],
44 + });
45 + ```
46 +
47 + Enable Mastodon and change placement:
48 +
49 + ```ts
50 + share({
51 + services: ["x", "bluesky", "mastodon", "copy"],
52 + mastodonInstance: "mastodon.social",
53 + placement: "top",
54 + });
55 + ```
56 +
57 + ## Options
58 +
59 + | Option | Type | Default | Description |
60 + | ------ | ---- | ------- | ----------- |
61 + | `services` | `ShareService[]` | every service except `mastodon` | Services to render, in order |
62 + | `placement` | `"top" \| "bottom"` | `"bottom"` | Where the controls appear |
63 + | `mastodonInstance` | `string` | none | Mastodon host; required when `services` includes `"mastodon"` |
64 + | `className` | `string` | none | Extra root class alongside the stable `rr-share` hook |
65 + | `ariaLabel` | `string` | `"Share"` | Accessible name for the control group |
66 + | `labels` | `Partial<Record<ShareService, string>>` | built-in labels | Per-service visible labels |
67 + | `copiedLabel` | `string` | `"Copied"` | Status announced after a successful copy |
68 + | `copyFailedLabel` | `string` | `"Copy failed"` | Status announced when a copy fails |
69 +
70 + `share` throws a configuration error at `riebeckite check` time when
71 + `services` includes `"mastodon"` but `mastodonInstance` is missing.
72 +
73 + ## Output
74 +
75 + ```html
76 + <div class="rr-share" data-rr-share data-rr-share-placement="bottom"
77 + role="group" aria-label="Share">
78 + <ul class="rr-share__list">
79 + <li class="rr-share__item">
80 + <a class="rr-share__link rr-share__link--x"
81 + href="https://twitter.com/intent/tweet?url=…&amp;text=…"
82 + target="_blank" rel="noopener noreferrer" data-share-service="x">X</a>
83 + </li>
84 + <li class="rr-share__item">
85 + <button type="button" class="rr-share__button rr-share__copy"
86 + data-rr-share-copy data-share-url="https://example.com/posts/hello"
87 + data-rr-share-copied="Copied" hidden>Copy link</button>
88 + </li>
89 + </ul>
90 + <p class="rr-share__status" role="status" aria-live="polite"></p>
91 + </div>
92 + ```
93 +
94 + ## Progressive enhancement
95 +
96 + The share links are plain anchors, so they work with JavaScript disabled. The
97 + copy-link button starts `hidden` and is revealed by `initShare()`, which the
98 + app calls during page initialization; a no-JS reader never sees a control that
99 + cannot work. Copying uses `navigator.clipboard.writeText` and falls back to a
100 + hidden textarea with `document.execCommand("copy")`. The result is announced in
101 + the `aria-live="polite"` status region.
102 +
103 + ## Style
104 +
105 + The package ships `style.css`. Register it like any other plugin stylesheet:
106 +
107 + ```ts
108 + import "@riebeckite/plugin-share/style.css";
109 + ```
110 +
111 + The stable classes are `rr-share` (root), `rr-share__list`, `rr-share__item`,
112 + `rr-share__link`, `rr-share__link--{service}`, `rr-share__button`,
113 + `rr-share__copy`, and `rr-share__status`. A theme can target these hooks; the
114 + optional `className` is added to the root without replacing them.
115 +
116 + ## Exports
117 +
118 + - `share(options?)` — plugin factory
119 + - `sharePlugin` — alias of `share`
120 + - `resolveShareOptions(options?)` — apply option defaults
121 + - `validateShareOptions(options?)` — validate runtime options
122 + - `buildAbsoluteUrl(config, permalink)` — resolve a note URL to absolute
123 + - `normalizeMastodonInstance(value)` — normalize an instance to a bare host
124 + - `buildShareUrl(service, target, instance?)` — build one service URL
125 + - `buildShareLinks(options, target)` — build every link-bearing service
126 + - `renderShareControls(options, target)` — render the controls HTML
127 + - `initShare()` — client initializer (also via
128 + `@riebeckite/plugin-share/client`)
129 + - Constants: `SHARE_SERVICES`, `SHARE_ATTRIBUTE`, `SHARE_ROOT_CLASS`,
130 + `DEFAULT_SHARE_SERVICES`, `DEFAULT_SHARE_LABELS`, `DEFAULT_SHARE_PLACEMENT`
131 + - Types: `ShareOptions`, `ResolvedShareOptions`, `ShareService`,
132 + `SharePlacement`, `ShareLink`, `ShareTarget`
133 +
134 + ## Limitations
135 +
136 + - Share URLs are fixed at build time. A full rebuild always recomputes them.
137 + - Mastodon cannot be enabled without a concrete instance.
138 + - The plugin contributes controls to `article.before-content` for `top` and
139 + `article.footer` for `bottom`; a Site places those semantic slots in its layout.
140 +
141 + ## See also
142 +
143 + - [Plugin guide](../reference/plugin-api.en.md)
144 +