Basic
The most basic usage.
Code
<%= render Hakumi::QrCode::Component.new(
value: "https://hakumi.com"
) %>
With Icon
QRCode with icon overlay.
Code
<%= render Hakumi::QrCode::Component.new(
value: "https://hakumi.com",
icon: :scan,
icon_size: 48
) %>
Status
The status can be controlled by the value status.
Active
Loading
Expired
ExpiredPlease refresh to continue
Scanned
ScannedYou can now continue
Code
<%= render Hakumi::Space::Component.new(size: :large) do |space| %>
<% [ :active, :loading, :expired, :scanned ].each do |state| %>
<% space.with_item do %>
<%= render Hakumi::Space::Component.new(direction: :vertical, size: :small) do |status_space| %>
<% status_space.with_item do %>
<%= render(Hakumi::Typography::Text::Component.new(weight: :strong)) { state.to_s.capitalize } %>
<% end %>
<% status_space.with_item do %>
<%= render Hakumi::QrCode::Component.new(
value: "https://hakumi.com/#{state}",
status: state
) %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
Custom Status Render
Customize the rendering logic of the QR code in different states.
Status: expired
Code
<%= render Hakumi::QrCode::Component.new(
value: "https://hakumi.com/custom-status",
status: :expired,
status_render: ->(status) do
render Hakumi::Space::Component.new(direction: :vertical, size: :small) do |space|
space.with_item do
render(Hakumi::Typography::Text::Component.new(weight: :strong)) { "Status: #{status}" }
end
space.with_item do
render(Hakumi::Button::Component.new(type: :primary, size: :small)) { "Refresh" }
end
end
end
) %>
Custom Render Type
Customize rendering by type, providing canvas and svg.
Canvas
SVG
Code
<%= render Hakumi::Space::Component.new(size: :large) do |space| %>
<% space.with_item do %>
<%= render Hakumi::Space::Component.new(direction: :vertical, size: :small) do |type_space| %>
<% type_space.with_item do %>
<%= render(Hakumi::Typography::Text::Component.new(weight: :strong)) { "Canvas" } %>
<% end %>
<% type_space.with_item do %>
<%= render Hakumi::QrCode::Component.new(
value: "https://hakumi.com/canvas",
type: :canvas
) %>
<% end %>
<% end %>
<% end %>
<% space.with_item do %>
<%= render Hakumi::Space::Component.new(direction: :vertical, size: :small) do |type_space| %>
<% type_space.with_item do %>
<%= render(Hakumi::Typography::Text::Component.new(weight: :strong)) { "SVG" } %>
<% end %>
<% type_space.with_item do %>
<%= render Hakumi::QrCode::Component.new(
value: "https://hakumi.com/svg",
type: :svg
) %>
<% end %>
<% end %>
<% end %>
<% end %>
Custom Size
Adjust the size of the QR code.
Resize with JS API
Code
<%= render Hakumi::Space::Component.new(size: :large) do |space| %>
<% space.with_item do %>
<%= render Hakumi::QrCode::Component.new(
value: "https://hakumi.com/size-small",
size: 120
) %>
<% end %>
<% space.with_item do %>
<%= render Hakumi::QrCode::Component.new(
value: "https://hakumi.com/size-large",
size: 220
) %>
<% end %>
<% space.with_item do %>
<%= render Hakumi::Space::Component.new(direction: :vertical, size: :small, block: true) do |interactive| %>
<% interactive.with_item do %>
<%= render Hakumi::Typography::Text::Component.new(strong: true) do %>
Resize with JS API
<% end %>
<% end %>
<% interactive.with_item do %>
<%= render Hakumi::QrCode::Component.new(
id: "qr-code-resize",
value: "https://hakumi.com/resize",
size: 160,
type: :canvas
) %>
<% end %>
<% interactive.with_item do %>
<%= render Hakumi::Space::Component.new(size: :small) do |buttons| %>
<% [ { label: "120px", size: 120 }, { label: "200px", size: 200 }, { label: "260px", size: 260 } ].each do |option| %>
<% buttons.with_item do %>
<%= render(Hakumi::Button::Component.new(
type: :default,
data: { "qr-resize": option[:size] }
)) { option[:label] } %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
<script>
(function() {
var target = document.getElementById("qr-code-resize")
if (!target) return
var buttons = document.querySelectorAll("[data-qr-resize]")
if (!buttons.length) return
var wire = function() {
if (!target.hakumiQrCode || typeof target.hakumiQrCode.setSize !== "function") {
return false
}
buttons.forEach(function(button) {
button.addEventListener("click", function() {
var nextSize = Number(button.getAttribute("data-qr-resize"))
target.hakumiQrCode.setSize(nextSize)
})
})
return true
}
if (wire()) return
var onReady = function() {
if (wire()) {
document.removeEventListener("turbo:load", onReady)
window.removeEventListener("load", onReady)
}
}
document.addEventListener("turbo:load", onReady)
window.addEventListener("load", onReady)
})()
</script>
Custom Color
Customize foreground and background colors.
Code
<%= render Hakumi::QrCode::Component.new(
value: "https://hakumi.com/color",
color: "#1677ff",
bg_color: "#e6f4ff"
) %>
Download QRCode
Download the QRCode image via the public API.
Code
<%= render Hakumi::Space::Component.new(direction: :vertical, size: :middle) do |space| %>
<% space.with_item do %>
<%= render Hakumi::QrCode::Component.new(
value: "https://hakumi.com/download",
id: "qr-code-download"
) %>
<% end %>
<% space.with_item do %>
<%= render(Hakumi::Button::Component.new(id: "qr-code-download-button", type: :primary)) { "Download QRCode" } %>
<% end %>
<% end %>
<script>
(() => {
const button = document.getElementById("qr-code-download-button")
const qr = document.getElementById("qr-code-download")
if (!button || !qr) return
const wire = () => {
if (!qr.hakumiQrCode) return false
button.addEventListener("click", () => qr.hakumiQrCode.download("hakumi-qr-code"))
return true
}
if (wire()) return
const onReady = () => {
if (wire()) {
document.removeEventListener("turbo:load", onReady)
window.removeEventListener("load", onReady)
}
}
document.addEventListener("turbo:load", onReady)
window.addEventListener("load", onReady)
})()
</script>
Error Level
Set the error correction level.
Level L
Level M
Level Q
Level H
Code
<%= render Hakumi::Space::Component.new(size: :large) do |space| %>
<% [ :L, :M, :Q, :H ].each do |level| %>
<% space.with_item do %>
<%= render Hakumi::Space::Component.new(direction: :vertical, size: :small) do |level_space| %>
<% level_space.with_item do %>
<%= render(Hakumi::Typography::Text::Component.new(weight: :strong)) { "Level #{level}" } %>
<% end %>
<% level_space.with_item do %>
<%= render Hakumi::QrCode::Component.new(
value: "https://hakumi.com/level-#{level}",
error_level: level
) %>
<% end %>
<% end %>
<% end %>
<% end %>
<% end %>
With Popover
Advanced usage with popover.
Code
<%= render Hakumi::Popover::Component.new(
title: "Scan me",
body: render(Hakumi::QrCode::Component.new(value: "https://hakumi.com/popover")),
trigger: "hover",
placement: "bottom"
) do %>
<%= render(Hakumi::Button::Component.new(type: :primary)) { "Hover to view" } %>
<% end %>
Programmatic
Render a QRCode with HakumiComponents.renderComponent.
Awaiting render...
Code
<%= render Hakumi::Space::Component.new(direction: :vertical, size: :middle) do |space| %>
<% space.with_item do %>
<%= render(Hakumi::Button::Component.new(id: "qr-code-programmatic-button", type: :primary)) { "Render QRCode" } %>
<% end %>
<% space.with_item do %>
<%= render Hakumi::Flex::Component.new(
id: "qr-code-programmatic-target",
align: :center,
justify: :center,
style: "min-height: 180px;"
) do %>
<%= render(Hakumi::Typography::Text::Component.new(type: :secondary)) { "Awaiting render..." } %>
<% end %>
<% end %>
<% end %>
<script>
(() => {
const button = document.getElementById("qr-code-programmatic-button")
const target = document.getElementById("qr-code-programmatic-target")
if (!button || !target) return
const wire = () => {
if (!window.HakumiComponents?.renderComponent) return false
button.addEventListener("click", async () => {
await window.HakumiComponents.renderComponent("qr_code", {
target,
params: {
value: "https://hakumi.com/render",
size: 180,
type: "svg",
error_level: "H"
}
})
})
return true
}
if (wire()) return
const onReady = () => {
if (wire()) {
document.removeEventListener("turbo:load", onReady)
window.removeEventListener("load", onReady)
}
}
document.addEventListener("turbo:load", onReady)
window.addEventListener("load", onReady)
})()
</script>
QRCode Ruby Props
| Prop | Type | Default | Description |
|---|---|---|---|
value |
String |
- |
Value encoded in the QR code. |
size |
Number |
160 |
QR code size in pixels. |
type |
Symbol |
:canvas |
Render type (:canvas or :svg). |
color |
String |
"#000000d9" |
Foreground color. |
bg_color |
String |
"#ffffff" |
Background color. |
icon |
String |
- |
Icon URL overlay. |
icon_size |
Number |
40 |
Icon size in pixels. |
status |
Symbol |
:active |
Status (:active, :expired, :loading, :scanned). |
status_render |
Proc | ViewComponent or String |
- |
Custom status render callback or component. |
bordered |
Boolean |
true |
Whether to display a border. |
error_level |
Symbol |
:M |
Error correction level (:L, :M, :Q, :H). |
download_name |
String |
- |
Default filename for downloads. |
aria_label |
String |
"QR Code" |
Accessibility label. |
JavaScript API (element.hakumiQrCode)
| Prop | Type | Default | Description |
|---|---|---|---|
getValue() |
Function |
- |
Returns the current QR value. |
setValue(value) |
Function |
- |
Updates the QR value and re-renders. |
getSize() |
Function |
- |
Returns the current size in pixels. |
setSize(size) |
Function |
- |
Sets the size (px) and updates layout + render. |
getType() |
Function |
- |
Returns the renderer type (:canvas or :svg). |
setType(type) |
Function |
- |
Switches renderer between canvas / svg. |
setColors({ color, bgColor }) |
Function |
- |
Overrides foreground/background colors. |
setErrorLevel(level) |
Function |
- |
Changes error correction level (:L/:M/:Q/:H). |
getDataUrl() |
Function |
- |
Returns a data URL for the rendered QR code. |
download(filename) |
Function |
- |
Downloads the QR code image. |
rerender() |
Function |
- |
Forces a re-render of the QR code. |
getState() |
Function |
- |
Returns { value, size, type, errorLevel, status }. |